diff --git a/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py b/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py index c834bf21..0f70f858 100644 --- a/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py +++ b/extensions/fablabchemnitz/epilog_dashboard_bbox_adjust/epilog_dashboard_bbox_adjust.py @@ -59,7 +59,7 @@ class EpilogDashboardBboxAdjust(inkex.EffectExtension): else: #for element in self.svg.root.getchildren(): for element in self.document.getroot().iter("*"): - if isinstance (element, inkex.ShapeElement): + if isinstance (element, inkex.ShapeElement) and element.tag != inkex.addNS('use','svg') and element.get('inkscape:groupmode') != 'layer': #bbox fails for svg:use elements and layers: bbox += element.bounding_box() if abs(bbox.width) == math.inf or abs(bbox.height) == math.inf: diff --git a/extensions/fablabchemnitz/laser_check/laser_check.inx b/extensions/fablabchemnitz/laser_check/laser_check.inx new file mode 100644 index 00000000..f5ffadff --- /dev/null +++ b/extensions/fablabchemnitz/laser_check/laser_check.inx @@ -0,0 +1,17 @@ + + + Laser Check + fablabchemnitz.de.laser_check + + + all + + + + + + + + \ No newline at end of file diff --git a/extensions/fablabchemnitz/laser_check/laser_check.py b/extensions/fablabchemnitz/laser_check/laser_check.py new file mode 100644 index 00000000..c509f36c --- /dev/null +++ b/extensions/fablabchemnitz/laser_check/laser_check.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 + +import inkex +from inkex.bezier import csplength, csparea +from lxml import etree +import re +import math + +class LaserCheck(inkex.EffectExtension): + + ''' + check for old styles which should be upgraded + border around complete content + ''' + + #def add_arguments(self, pars): + # pars.add_argument('-d', '--depth', type = int, default = 1, help = 'Convert nested group up to DEPTH layers deep') + + def effect(self): + + def parseChildren(element): + if element not in selected: + selected.append(element) + children = element.getchildren() + if children is not None: + for child in children: + if child not in selected: + selected.append(child) + parseChildren(child) #go deeper and deeper + + #check if we have selected elements or if we should parse the whole document instead + selected = [] #total list of elements to parse + if len(self.svg.selected) == 0: + for element in self.document.getroot().iter(tag=etree.Element): + if element != self.document.getroot(): + + selected.append(element) + else: + for element in self.svg.selected.values(): + parseChildren(element) + + + namedView = self.document.getroot().find(inkex.addNS('namedview', 'sodipodi')) + doc_units = namedView.get(inkex.addNS('document-units', 'inkscape')) + pagecolor = namedView.get('pagecolor') + inkex.utils.debug("Document units: {}".format(doc_units)) + + inkex.utils.debug("---------- Groups and layers") + groups = [] + layers = [] + for element in selected: + if element.tag == inkex.addNS('g','svg'): + if element.get('inkscape:groupmode') == 'layer': + layers.append(element) + else: + groups.append(element) + inkex.utils.debug("{} groups in total".format(len(groups))) + inkex.utils.debug("{} layers in total".format(len(layers))) + + #check for empty groups + for group in groups: + if len(group) == 0: + inkex.utils.debug("group id={} is empty".format(group.get('id'))) + + #check for empty layers + for layer in layers: + if len(layer) == 0: + inkex.utils.debug("layer id={} is empty".format(layer.get('id'))) + + inkex.utils.debug("---------- Clones (svg:use) - maybe unlink") + uses = [] + for element in selected: + if element.tag == inkex.addNS('use','svg'): + uses.append(element) + inkex.utils.debug("{} svg:use clones in total".format(len(uses))) + for use in uses: + inkex.utils.debug("clone id={}".format(use.get('id'))) + + inkex.utils.debug("---------- Clippings (svg:clipPath) - please replace with real cut paths") + clipPaths = [] + for element in selected: + if element.tag == inkex.addNS('clipPath','svg'): + clipPaths.append(element) + inkex.utils.debug("{} svg:clipPath in total".format(len(clipPaths))) + for clipPath in clipPaths: + inkex.utils.debug("clipPath id={}".format(clipPath.get('id'))) + + + inkex.utils.debug("---------- Images (svg:image) - maybe trace to svg") + images = [] + for element in selected: + if element.tag == inkex.addNS('image','svg'): + images.append(element) + inkex.utils.debug("{} svg:image in total".format(len(images))) + for image in images: + inkex.utils.debug("image id={}".format(image.get('id'))) + + inkex.utils.debug("---------- Low level strokes (svg:line/polyline/polygon) - maybe convert to path") + lowlevels = [] + for element in selected: + if element.tag in (inkex.addNS('line','svg'), inkex.addNS('polyline','svg'), inkex.addNS('polygon','svg')): + lowlevels.append(element) + inkex.utils.debug("{} low level strokes in total".format(len(lowlevels))) + for lowlevel in lowlevels: + inkex.utils.debug("stroke id={}".format(lowlevel.get('id'))) + + inkex.utils.debug("---------- Texts (should be converted to paths)") + texts = [] + for element in selected: + if element.tag == inkex.addNS('text','svg'): + texts.append(element) + inkex.utils.debug("{} svg:text in total".format(len(texts))) + for text in texts: + inkex.utils.debug("text id={}".format(text.get('id'))) + + + inkex.utils.debug("---------- Shapes / Non-shapes") + nonShapes = [] + shapes = [] + for element in selected: + if not isinstance(element, inkex.ShapeElement): + nonShapes.append(element) + else: + shapes.append(element) + inkex.utils.debug("{} shape elements in total".format(len(shapes))) + inkex.utils.debug("{} non-shape elements in total".format(len(nonShapes))) + for nonShape in nonShapes: + inkex.utils.debug("non-shape id={}".format(nonShape.get('id'))) + + inkex.utils.debug("---------- Stroke colors") + strokeColors = [] + for element in shapes: + style = element.get('style') + if style is not None: + stroke = re.search('(;|^)stroke:(.*?)(;|$)', style) + if stroke is not None: + strokeColor = stroke[0].split("stroke:")[1].split(";")[0] + if strokeColor not in strokeColors: + strokeColors.append(strokeColor) + inkex.utils.debug("{} different stroke colors in total".format(len(strokeColors))) + for strokeColor in strokeColors: + inkex.utils.debug("stroke color {}".format(strokeColor)) + + inkex.utils.debug("---------- Borders around all elements - minimum offset 5mm from each side") + bbox = inkex.BoundingBox() + for element in self.document.getroot().iter(tag=etree.Element): + if element != self.document.getroot() and isinstance(element, inkex.ShapeElement) and element.tag != inkex.addNS('use','svg') and element.get('inkscape:groupmode') != 'layer': #bbox fails for svg:use elements and layers + transform = inkex.Transform() + parent = element.getparent() + if parent is not None and isinstance(parent, inkex.ShapeElement): + transform = parent.composed_transform() + try: + bbox += element.bounding_box(transform) + except Exception: + transform = element.composed_transform() + x1, y1 = transform.apply_to_point([0, 0]) + x2, y2 = transform.apply_to_point([1, 1]) + bbox += inkex.BoundingBox((x1, x2), (y1, y2)) + + if abs(bbox.width) == math.inf or abs(bbox.height) == math.inf: + inkex.utils.debug("bounding box could not be calculated") + else: + inkex.utils.debug("bounding box is {}".format(bbox)) + page_width = self.svg.unittouu(self.document.getroot().attrib['width']) + width_height = self.svg.unittouu(self.document.getroot().attrib['height']) + fmm = self.svg.unittouu("5mm") + if bbox.left > fmm: + self.msg("left ok") + else: + self.msg("left fail") + + if bbox.top > fmm: + self.msg("top ok") + else: + self.msg("top fail") + + if bbox.right + fmm <= page_width: + self.msg("right ok") + else: + self.msg("right fail") + + if bbox.bottom + fmm <= width_height: + self.msg("bottom ok") + else: + self.msg("bottom fail") + + inkex.utils.debug("---------- Stroke widths") + strokeWidths = [] + for element in shapes: + style = element.get('style') + if style is not None: + stroke_width = re.search('stroke-width:(.*?)(;|$)', style) + if stroke_width is not None: + strokeWidth = self.svg.unittouu(stroke_width[0].split("stroke-width:")[1].split(";")[0]) + if strokeWidth not in strokeWidths: + strokeWidths.append(strokeWidth) + inkex.utils.debug("{} different stroke widths in total".format(len(strokeWidths))) + for strokeWidth in strokeWidths: + inkex.utils.debug("stroke width {}".format(strokeWidth)) + + inkex.utils.debug("---------- Cosmetic dashes - should be converted to paths") + strokeDasharrays = [] + for element in shapes: + style = element.get('style') + if style is not None: + stroke_dasharray = re.search('stroke-dasharray:(.*?)(;|$)', style) + if stroke_dasharray is not None: + strokeDasharray = stroke_dasharray[0].split("stroke-dasharray:")[1].split(";")[0] + if strokeDasharray not in strokeDasharrays: + strokeDasharrays.append(strokeDasharray) + inkex.utils.debug("{} different stroke dash arrays in total".format(len(strokeDasharrays))) + for strokeDasharray in strokeDasharrays: + inkex.utils.debug("stroke dash array {}".format(strokeDasharray)) + + inkex.utils.debug("---------- Invisible shapes") + invisibles = [] + for element in shapes: + if element.tag not in (inkex.addNS('tspan','svg')): + style = element.get('style') + if style is not None: + stroke = re.search('stroke:(.*?)(;|$)', style) #filter white on white (we guess the background color of the document is white too but we do not check) + if stroke is None: + strokeVis = 0 + elif stroke[0].split("stroke:")[1].split(";")[0] == 'none': + strokeVis = 0 + elif stroke[0].split("stroke:")[1].split(";")[0] in ('#ffffff', 'white', 'rgb(255,255,255)'): + strokeVis = 0 + else: + strokeVis = 1 + + stroke_width = re.search('stroke-width:(.*?)(;|$)', style) + if stroke_width is None: + widthVis = 0 + elif self.svg.unittouu(stroke_width[0].split("stroke-width:")[1].split(";")[0]) < 0.005: #really thin (0,005pc = 0,080px) + widthVis = 0 + else: + widthVis = 1 + + stroke_opacity = re.search('stroke-opacity:(.*?)(;|$)', style) + if stroke_opacity is None: + strokeOpacityVis = 0 + elif float(stroke_opacity[0].split("stroke-opacity:")[1].split(";")[0]) < 0.05: #nearly invisible (<5% opacity) + strokeOpacityVis = 0 + else: + strokeOpacityVis = 1 + + if pagecolor == '#ffffff': + invisColors = [pagecolor, 'white', 'rgb(255,255,255)'] + else: + invisColors = [pagecolor] #we could add some parser to convert pagecolor to rgb/hsl/cmyk + fill = re.search('fill:(.*?)(;|$)', style) + if fill is None: + fillVis = 0 + elif fill[0].split("fill:")[1].split(";")[0] == 'none': + fillVis = 0 + elif fill[0].split("fill:")[1].split(";")[0] in invisColors: + fillVis = 0 + else: + fillVis = 1 + + fill_opacity = re.search('fill-opacity:(.*?)(;|$)', style) + if fill_opacity is None: + fillOpacityVis = 0 + elif float(fill_opacity[0].split("fill-opacity:")[1].split(";")[0]) < 0.05: #nearly invisible (<5% opacity) + fillOpacityVis = 0 + else: + fillOpacityVis = 1 + + #self.msg("strokeVis={}, widthVis={}, strokeOpacityVis={}, fillVis={}, fillOpacityVis={}".format(strokeVis, widthVis, strokeOpacityVis, fillVis, fillOpacityVis)) + if (strokeVis == 0 or widthVis == 0 or strokeOpacityVis == 0) and (fillVis == 0 or fillOpacityVis == 0): + if element not in invisibles: + invisibles.append(element) + inkex.utils.debug("{} invisible shapes in total".format(len(invisibles))) + for invisible in invisibles: + inkex.utils.debug("shape id={}".format(invisible.get('id'))) + + inkex.utils.debug("---------- Objects with stroke transparencies (< 1.0) - should be set to 1.0") + transparencies = [] + for element in shapes: + style = element.get('style') + if style is not None: + stroke_opacity = re.search('stroke-opacity:(.*?)(;|$)', style) + if stroke_opacity is not None: + if float(stroke_opacity[0].split("stroke-opacity:")[1].split(";")[0]) < 1.0: + if element not in transparencies: + transparencies.append(element) + inkex.utils.debug("{} stroke transparencies shapes in total".format(len(transparencies))) + for transparency in transparencies: + inkex.utils.debug("shape id={}".format(transparency.get('id'))) + + inkex.utils.debug("---------- Pointy paths - should be deleted") + pointyPaths = [] + for element in shapes: + if isinstance(element, inkex.PathElement): + p = element.path + commandsCoords = p.to_arrays() + if len(commandsCoords) == 1 or \ + (len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]) or \ + (len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z') or \ + (len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z'): + pointyPaths.append(element) + inkex.utils.debug("{} pointy paths in total".format(len(pointyPaths))) + for pointyPath in pointyPaths: + inkex.utils.debug("path id={}".format(pointyPath.get('id'))) + + inkex.utils.debug("---------- Transformations - should be applied to absolute") + transformations = [] + for element in shapes: + if element.get('transform') is not None: + transformations.append(element) + inkex.utils.debug("{} transformation in total".format(len(transformations))) + for transformation in transformations: + inkex.utils.debug("transformation in id={}".format(transformation.get('id'))) + + inkex.utils.debug("---------- Short paths (< 1mm)") + shortPaths = [] + for element in shapes: + if isinstance(element, inkex.PathElement): + slengths, stotal = csplength(element.path.transform(element.composed_transform()).to_superpath()) + if stotal < self.svg.unittouu("1mm"): + shortPaths.append(element) + inkex.utils.debug("{} short paths in total".format(len(shortPaths))) + for shortPath in shortPaths: + inkex.utils.debug("short path id={}".format(shortPath.get('id'))) + +if __name__ == '__main__': + LaserCheck().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/laser_check/meta.json b/extensions/fablabchemnitz/laser_check/meta.json new file mode 100644 index 00000000..c4a26db5 --- /dev/null +++ b/extensions/fablabchemnitz/laser_check/meta.json @@ -0,0 +1,19 @@ +[ + { + "name": "Laser Check", + "id": "fablabchemnitz.de.laser_check", + "path": "laser_check", + "original_name": "Laser Checkr", + "original_id": "fablabchemnitz.de.laser_check", + "license": "GNU GPL v4", + "license_url": "", + "comment": "", + "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/laser_check", + "fork_url": null, + "documentation_url": "", + "inkscape_gallery_url": null, + "main_authors": [ + "github.com/vmario89" + ] + } +] \ No newline at end of file diff --git a/extensions/fablabchemnitz/optimize_sequence_lasercut_sequence/meta.json b/extensions/fablabchemnitz/optimize_sequence_lasercut_sequence/meta.json index f0a90c91..ab2babba 100644 --- a/extensions/fablabchemnitz/optimize_sequence_lasercut_sequence/meta.json +++ b/extensions/fablabchemnitz/optimize_sequence_lasercut_sequence/meta.json @@ -5,7 +5,7 @@ "path": "optimize_sequence_lasercut_sequence", "original_name": "Fix cutting sequence", "original_id": "L0laapk3.filter.lasercut_sequence", - "license": "CC BY-NC-SA 4.0", + "license": "GNU AGPL v3", "license_url": "https://github.com/L0laapk3/inkscape-laser-sequence-extension/blob/master/LICENSE", "comment": "ported to Inkscape v1 by Mario Voigt", "source_url": "https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X/src/branch/master/extensions/fablabchemnitz/optimize_sequence_lasercut_sequence", diff --git a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.inx b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.inx index 258f994c..2d4668a7 100644 --- a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.inx +++ b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.inx @@ -43,7 +43,8 @@ true - true + true + true true true true diff --git a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py index 1af9dce8..741aeaf8 100644 --- a/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py +++ b/extensions/fablabchemnitz/ungrouper_and_element_migrator_filter/ungrouper_and_element_migrator_filter.py @@ -41,6 +41,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): pars.add_argument("--circle", type=inkex.Boolean, default=True) pars.add_argument("--clipPath", type=inkex.Boolean, default=True) pars.add_argument("--defs", type=inkex.Boolean, default=True) + pars.add_argument("--desc", type=inkex.Boolean, default=True) pars.add_argument("--ellipse", type=inkex.Boolean, default=True) pars.add_argument("--image", type=inkex.Boolean, default=True) pars.add_argument("--guide", type=inkex.Boolean, default=True) @@ -77,6 +78,7 @@ class UngrouperAndElementMigratorFilter(inkex.EffectExtension): namespace.append("{http://www.w3.org/2000/svg}circle") if self.options.circle else "" namespace.append("{http://www.w3.org/2000/svg}clipPath") if self.options.clipPath else "" namespace.append("{http://www.w3.org/2000/svg}defs") if self.options.defs else "" + namespace.append("{http://www.w3.org/2000/svg}desc") if self.options.desc else "" namespace.append("{http://www.w3.org/2000/svg}ellipse") if self.options.ellipse else "" namespace.append("{http://www.w3.org/2000/svg}image") if self.options.image else "" namespace.append("{http://www.w3.org/2000/svg}line") if self.options.line else ""