diff --git a/extensions/fablabchemnitz/buxtronix_living_hinges/buxtronix_living_hinges.py b/extensions/fablabchemnitz/buxtronix_living_hinges/buxtronix_living_hinges.py index 6a527e79..552cd1da 100755 --- a/extensions/fablabchemnitz/buxtronix_living_hinges/buxtronix_living_hinges.py +++ b/extensions/fablabchemnitz/buxtronix_living_hinges/buxtronix_living_hinges.py @@ -136,8 +136,7 @@ class Generator(object): link = self.canvas.add(inkex.PathElement()) link.update(**{"style": style, "inkscape:label": "lattice", "d": path_command}) - link.description("%s hinge %s" % (self.name, self.parameter_text())) - + link.insert(0, inkex.Desc("%s hinge %s" % (self.name, self.parameter_text()))) class StraightLatticeGenerator(Generator): def __init__(self, *args, **kwargs): diff --git a/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.inx b/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.inx new file mode 100644 index 00000000..af0f065e --- /dev/null +++ b/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.inx @@ -0,0 +1,15 @@ + + + Duplicate + Reverse + Join + fablabchemnitz.de.duplicate_reverse_join + + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.py b/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.py new file mode 100644 index 00000000..56fbc77c --- /dev/null +++ b/extensions/fablabchemnitz/duplicate_reverse_join/duplicate_reverse_join.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 Ellen Wasboe, ellen@wasbo.net +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +""" +Duplicate subpaths of all selected paths, reverse and join end nodes. +""" + +import inkex + +class DuplicateReverseJoin(inkex.EffectExtension): + + def effect(self): + for elem in self.svg.selection: + + pp=elem.path.to_absolute() + dList=str(pp).split(' M') + dFinal='' + l=0 + for sub in dList: + if l>0: + origSub='M'+dList[l] + else: + origSub=dList[l] + + elem.path=origSub + reSub=elem.path.reverse() + + if l>0: + origSub=' '+origSub + + if origSub.find('Z') > -1: + dRev=str(reSub).split(' ') + strRev='' + if dRev[3]=='L' and dRev[1]==dRev[4] and dRev[2]==dRev[5]: + strRev=' '.join(dRev[0:3])+' '+' '.join(dRev[6:]) #avoid that reverse path duplicate first node + else: + strRev=' '.join(dRev) + dFinal=dFinal+origSub+' '+strRev #keep original and reverse as separate closed paths + if dRev[-1]!='Z': + dFinal=dFinal+' Z'#avoid that reverse of closed path is open + else: + dRev=str(reSub).split(' ') + dFinal=dFinal+origSub+' '+' '.join(dRev[3:])+' Z' #pop off M element of reverse path and add Z to close + l+=1 + elem.path=dFinal + + +if __name__ == '__main__': + DuplicateReverseJoin().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/duplicate_reverse_join/meta.json b/extensions/fablabchemnitz/duplicate_reverse_join/meta.json new file mode 100644 index 00000000..9ebc2eae --- /dev/null +++ b/extensions/fablabchemnitz/duplicate_reverse_join/meta.json @@ -0,0 +1,20 @@ +[ + { + "name": "Duplicate + Reverse + Join", + "id": "fablabchemnitz.de.duplicate_reverse_join", + "path": "duplicate_reverse_join", + "original_name": "Duplicate, reverse, join", + "original_id": "EllenWasbo.cutlings.duplicateReverseJoin", + "license": "GNU GPL v2", + "license_url": "https://gitlab.com/EllenWasbo/inkscape-extension-duplicatereversejoin/-/blob/master/duplicateReverseJoin.py", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/duplicate_reverse_joi", + "fork_url": "https://gitlab.com/EllenWasbo/inkscape-extension-duplicatereversejoin", + "documentation_url": "https://stadtfabrikanten.org/pages/viewpage.action?pageId=120525059", + "inkscape_gallery_url": null, + "main_authors": [ + "gitlab.com/EllenWasbo", + "github.com/vmario89" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/join_paths/join_paths.inx b/extensions/fablabchemnitz/join_paths/join_paths.inx index 0e263103..a8d05bd9 100644 --- a/extensions/fablabchemnitz/join_paths/join_paths.inx +++ b/extensions/fablabchemnitz/join_paths/join_paths.inx @@ -8,6 +8,7 @@ true + true 0.0100 diff --git a/extensions/fablabchemnitz/join_paths/join_paths.py b/extensions/fablabchemnitz/join_paths/join_paths.py index 087fd7c9..b66d2386 100644 --- a/extensions/fablabchemnitz/join_paths/join_paths.py +++ b/extensions/fablabchemnitz/join_paths/join_paths.py @@ -126,6 +126,7 @@ class JoinPaths(inkex.EffectExtension): def add_arguments(self, pars): pars.add_argument("--optimized", type=inkex.Boolean, default=True) + pars.add_argument("--reverse", type=inkex.Boolean, default=False) pars.add_argument("--margin", type=float, default=0.0100) pars.add_argument("--add_dimples", type=inkex.Boolean, default=False) pars.add_argument("--draw_dimple_centers", type=inkex.Boolean, default=False) @@ -146,23 +147,24 @@ class JoinPaths(inkex.EffectExtension): pars.add_argument("--tab", default="sampling", help="Tab") def effect(self): - selections = self.svg.selected - if len(self.svg.selected) == 0: - self.msg('Please select some paths first.') - return + pathNodes = self.document.xpath('//svg:path',namespaces=inkex.NSS) - paths = {p.get('id'): getPartsFromCubicSuper(CubicSuperPath(p.get('d'))) for p in pathNodes } + if self.options.reverse is True: #helps debugging some strange Z orders (try out) + pathNodes = pathNodes[::-1] + #pathNodes[0].path = pathNodes[0].path.reverse() + #pathNodes[0].path = pathNodes[-1].path.reverse() + + paths = {p.get('id'): getPartsFromCubicSuper(CubicSuperPath(p.get('d'))) for p in pathNodes } #paths.keys() Order disturbed pathIds = [p.get('id') for p in pathNodes] - + if self.options.dimples_to_group is True: dimpleUnifyGroup = self.svg.get_current_layer().add(inkex.Group(id=self.svg.get_unique_id("dimplesCollection"))) if(len(paths) > 1): if(self.options.optimized): startPathId = pathIds[0] - pathIds = getArrangedIds(paths, startPathId) - + pathIds = getArrangedIds(paths, startPathId) newParts = [] firstElem = None for key in pathIds: @@ -171,7 +173,7 @@ class JoinPaths(inkex.EffectExtension): start = parts[0][0][0] try: elem = self.svg.selected[key] - + if(len(newParts) == 0): newParts += parts[:] firstElem = elem @@ -373,6 +375,9 @@ class JoinPaths(inkex.EffectExtension): except: pass #elem might come from group item - in this case we need to ignore it + if firstElem is None: + self.msg('Please select some paths first. Check if you selected a group or an object instead.') + exit() newElem = copy.copy(firstElem) oldId = firstElem.get('id') newElem.set('d', CubicSuperPath(getCubicSuperFromParts(newParts))) diff --git a/extensions/fablabchemnitz/mirror/meta.json b/extensions/fablabchemnitz/mirror/meta.json index 84f1636b..9bfc5258 100644 --- a/extensions/fablabchemnitz/mirror/meta.json +++ b/extensions/fablabchemnitz/mirror/meta.json @@ -11,7 +11,7 @@ "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/mirror", "fork_url": "https://inkscape.org/~jeko/%E2%98%85mirror", "documentation_url": "https://stadtfabrikanten.org/display/IFM/Mirror", - "inkscape_gallery_url": "https://inkscape.org/~MarioVoigt/%E2%98%85move-path-node", + "inkscape_gallery_url": null, "main_authors": [ "inkscape.org/jeko", "github.com/vmario89" diff --git a/extensions/fablabchemnitz/move_path_node/meta.json b/extensions/fablabchemnitz/move_path_node/meta.json index d930d988..e946a739 100644 --- a/extensions/fablabchemnitz/move_path_node/meta.json +++ b/extensions/fablabchemnitz/move_path_node/meta.json @@ -11,7 +11,7 @@ "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/move_path_node", "fork_url": null, "documentation_url": "https://stadtfabrikanten.org/display/IFM/Move+Path+Node", - "inkscape_gallery_url": null, + "inkscape_gallery_url": "https://inkscape.org/~MarioVoigt/%E2%98%85move-path-node", "main_authors": [ "github.com/vmario89" ] diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py index ac63536c..2ab229dc 100644 --- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py +++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py @@ -295,7 +295,8 @@ class StylesToLayers(inkex.EffectExtension): #call does not apply for this so we need to do it as PREVIOUS step before! for i in range(0, len(layerNodeList)): if len(layerNodeList[i][0]) == 0: - layerNodeList[i][0].getparent().remove(layerNodeList[i][0]) + if layerNodeList[i][0].getparent() is not None: + layerNodeList[i][0].getparent().remove(layerNodeList[i][0]) if self.options.cleanup == True: try: diff --git a/extensions/fablabchemnitz/webp_import/meta.json b/extensions/fablabchemnitz/webp_import/meta.json new file mode 100644 index 00000000..e74d9753 --- /dev/null +++ b/extensions/fablabchemnitz/webp_import/meta.json @@ -0,0 +1,20 @@ +[ + { + "name": "WebP Import", + "id": "fablabchemnitz.de.webp_import", + "path": "webp_import", + "original_name": "WebP Import", + "original_id": "fablabchemnitz.de.webp_import", + "license": "GNU GPL v3", + "license_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/LICENSE", + "comment": "Written by Mario Voigt", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/webp_import", + "fork_url": null, + "documentation_url": "https://stadtfabrikanten.org/display/IFM/WebP+Import", + "inkscape_gallery_url": null, + "main_authors": [ + "inkscape.org/mono", + "github.com/vmario89" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/webp_import/output.xml b/extensions/fablabchemnitz/webp_import/output.xml new file mode 100644 index 00000000..e69de29b diff --git a/extensions/fablabchemnitz/webp_import/person.xml b/extensions/fablabchemnitz/webp_import/person.xml new file mode 100644 index 00000000..572613cf --- /dev/null +++ b/extensions/fablabchemnitz/webp_import/person.xml @@ -0,0 +1 @@ +5.1 \ No newline at end of file diff --git a/extensions/fablabchemnitz/webp_import/webp_import.inx b/extensions/fablabchemnitz/webp_import/webp_import.inx new file mode 100644 index 00000000..2f83bc2c --- /dev/null +++ b/extensions/fablabchemnitz/webp_import/webp_import.inx @@ -0,0 +1,14 @@ + + + WebP Import + fablabchemnitz.de.webp_import + + .webp + image/webp + WebP Format (*.webp) + Import WebP Format + + + diff --git a/extensions/fablabchemnitz/webp_import/webp_import.py b/extensions/fablabchemnitz/webp_import/webp_import.py new file mode 100644 index 00000000..51b6fe5f --- /dev/null +++ b/extensions/fablabchemnitz/webp_import/webp_import.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +import sys +import os +import argparse +import inkex +from inkex import Rectangle +from PIL import Image +import base64 +from io import BytesIO, StringIO +from distutils.spawn import find_executable +import subprocess +from lxml import etree + +class WebpImport(inkex.InputExtension): + + def add_arguments(self, pars): + pars.add_argument('inputfile') + + def effect(self): + if os.name == 'nt': + tmp = os.getenv('TEMP') + '\\' + else: + tmp = '/tmp/' + convertfile = os.path.join(tmp, "webp.png") + if find_executable('magick'): + command = "magick \"%s\" \"%s\" " % (self.options.inputfile, convertfile) + elif find_executable('convert'): + command = "convert \"%s\" \"%s\" " % (self.options.inputfile, convertfile) + else: + inkex.errormsg('ImageMagick does not appear to be installed.') + exit() + p = subprocess.Popen(command, shell=True) + return_code = p.wait() + #inkex.utils.debug("command:" + command) + #inkex.utils.debug("Errorcode:" + str(return_code)) + + try: + img = Image.open(convertfile) + except Image.DecompressionBombError as e: #we could also increse PIL.Image.MAX_IMAGE_PIXELS = some large int + self.msg("Error. Image is too large. Reduce DPI and try again!") + exit(1) + output_buffer = BytesIO() + img.save(output_buffer, format='PNG') + width, height = img.size + byte_data = output_buffer.getvalue() + base64_str = base64.b64encode(byte_data).decode('UTF-8') + webp = etree.SubElement(Rectangle(), '{http://www.w3.org/2000/svg}image') + webp.attrib['x'] = str(0) + webp.attrib['y'] = str(0) + webp.attrib['width'] = str(width) + webp.attrib['height'] = str(height) + webp.attrib['{http://www.w3.org/1999/xlink}href'] = "data:image/png;base64,{}".format(base64_str) + base = ('' + ).format(width, height, 0, 0, width, height) + output = StringIO(base) + tree = etree.parse(output) + output.close() + tree.getroot().append(webp) + svgfile = os.path.join(tmp, "webp.svg") + with open(svgfile, 'w') as file: + tree.write(svgfile) + with open(svgfile, 'r') as newfile: + sys.stdout.write(newfile.read()) + + def load(self, stream): + return str(stream.read()) + +if __name__ == '__main__': + WebpImport().run() + \ No newline at end of file