diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx index 168e516c..ed968747 100644 --- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx +++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.inx @@ -13,7 +13,7 @@ - + diff --git a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py index 0c7b3bec..f24d4854 100644 --- a/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py +++ b/extensions/fablabchemnitz/styles_to_layers/styles_to_layers.py @@ -47,7 +47,7 @@ class StylesToLayers(inkex.EffectExtension): pars.add_argument("--tab") pars.add_argument("--apply_transformations", type=inkex.Boolean, default=False, help="Run 'Apply Transformations' extension before running vpype. Helps avoiding geometry shifting") pars.add_argument("--separateby", default = "stroke", help = "Separate by") - pars.add_argument("--parsecolors",default = "hexval", help = "Sort colors by") + pars.add_argument("--sortcolorby", default = "hexval", help = "Sort colors by") pars.add_argument("--subdividethreshold", type=int, default = 1, help = "Threshold for splitting into sub layers") pars.add_argument("--decimals", type=int, default = 1, help = "Decimal tolerance") pars.add_argument("--cleanup", type=inkex.Boolean, default = True, help = "Cleanup all unused groups/layers (requires separate extension)") @@ -57,13 +57,13 @@ class StylesToLayers(inkex.EffectExtension): def effect(self): def colorsort(stroke_value): #this function applies to stroke or fill (hex colors) - if self.options.parsecolors == "hexval": + if self.options.sortcolorby == "hexval": return float(int(stroke_value[1:], 16)) - elif self.options.parsecolors == "hue": + elif self.options.sortcolorby == "hue": return float(Color(stroke_value).to_hsl()[0]) - elif self.options.parsecolors == "saturation": + elif self.options.sortcolorby == "saturation": return float(Color(stroke_value).to_hsl()[1]) - elif self.options.parsecolors == "luminance": + elif self.options.sortcolorby == "luminance": return float(Color(stroke_value).to_hsl()[2]) return None @@ -93,7 +93,7 @@ class StylesToLayers(inkex.EffectExtension): if isinstance(element, inkex.ShapeElement): # Elements which have a visible representation on the canvas (even without a style attribute but by their type); if we do not use that ifInstance Filter we provokate unkown InkScape fatal crashes - style = element.get('style') + style = element.style if style is not None: #if no style attributes or stroke/fill are set as extra attribute stroke = element.get('stroke') @@ -107,9 +107,9 @@ class StylesToLayers(inkex.EffectExtension): neutral_value = None #we will use this value to slice the filter result into sub layers (threshold) if fill is not None: - style = 'fill:'+ fill + ";" + style['fill'] = fill if stroke is not None: - style = style + 'stroke:' + stroke + ";" + style['stroke'] = stroke #we don't want to destroy elements with gradients (they contain svg:stop elements which have a style too) and we don't want to mess with tspans (text) #the Styles to Layers extension still might brick the gradients (some tests failed) @@ -120,65 +120,59 @@ class StylesToLayers(inkex.EffectExtension): layer_name = "element_tag-" + element.tag.replace("{http://www.w3.org/2000/svg}", "") elif self.options.separateby == "stroke": - stroke = re.search('(;|^)stroke:(.*?)(;|$)', style) - if stroke is not None: - stroke = stroke[0] - stroke_value = stroke.split("stroke:")[1].split(";")[0] - if stroke_value != "none": - stroke_converted = str(Color(stroke_value).to_rgb()) #the color can be hex code or clear name. we handle both the same + stroke = style.get('stroke') + if stroke is not None and stroke != "none": + stroke_converted = str(Color(stroke).to_rgb()) #the color can be hex code or clear name. we handle both the same neutral_value = colorsort(stroke_converted) - layer_name = "stroke-" + self.options.parsecolors + "-" + stroke_converted + layer_name = "stroke-{}-{}".format(self.options.sortcolorby, stroke_converted) else: - layer_name = "stroke-" + self.options.parsecolors + "-none" + layer_name = "stroke-{}-none".format(self.options.sortcolorby) elif self.options.separateby == "stroke_width": - stroke_width = re.search('stroke-width:(.*?)(;|$)', style) + stroke_width = style.get('stroke-width') if stroke_width is not None: - stroke_width = stroke_width[0] - neutral_value = self.svg.unittouu(stroke_width.split("stroke-width:")[1].split(";")[0]) - layer_name = stroke_width + neutral_value = self.svg.unittouu(stroke_width) + layer_name = "stroke-width-{}".format(neutral_value) else: layer_name = "stroke-width-none" elif self.options.separateby == "stroke_hairline": - stroke_hairline = re.search('-inkscape-stroke:hairline(;|$)', style) - if stroke_hairline is not None: + inkscape_stroke = style.get('-inkscape-stroke') + if inkscape_stroke is not None and inkscape_stroke == "hairline": neutral_value = 1 layer_name = "stroke-hairline-yes" else: neutral_value = 0 layer_name = "stroke-hairline-no" - elif self.options.separateby == "stroke_opacity": - stroke_opacity = re.search('stroke-opacity:(.*?)(;|$)', style) + elif self.options.separateby == "stroke_opacity": + stroke_opacity = style.get('stroke-opacity') if stroke_opacity is not None: - stroke_opacity = stroke_opacity[0] - neutral_value = float(stroke_opacity.split("stroke-opacity:")[1].split(";")[0]) - layer_name = stroke_opacity + neutral_value = float(stroke_opacity) + layer_name = "stroke-opacity-{}".format(neutral_value) else: layer_name = "stroke-opacity-none" - elif self.options.separateby == "fill": - fill = re.search('fill:(.*?)(;|$)', style) + elif self.options.separateby == "fill": + fill = style.get('fill') if fill is not None: - fill = fill[0] - fill_value = fill.split("fill:")[1].split(";")[0] #check if the fill color is a real color or a gradient. if it's a gradient we skip the element - if fill_value != "none" and "url" not in fill_value: - fill_converted = str(Color(fill_value).to_rgb()) #the color can be hex code or clear name. we handle both the same + if fill != "none" and "url" not in fill: + fill_converted = str(Color(fill).to_rgb()) #the color can be hex code or clear name. we handle both the same neutral_value = colorsort(fill_converted) - layer_name = "fill-" + self.options.parsecolors + "-" + fill_converted - elif "url" in fill_value: #okay we found a gradient. we put it to some group - layer_name = "fill-" + self.options.parsecolors + "-gradient" + layer_name = "fill-{}-{}".format(self.options.sortcolorby,fill_converted) + elif "url" in fill: #okay we found a gradient. we put it to some group + layer_name = "fill-{}-gradient".format(self.options.sortcolorby) + else: #none + layer_name = "fill-" + self.options.sortcolorby + "-none" else: - layer_name = "fill-" + self.options.parsecolors + "-none" + layer_name = "fill-" + self.options.sortcolorby + "-none" - elif self.options.separateby == "fill_opacity": - fill_opacity = re.search('fill-opacity:(.*?)(;|$)', style) + elif self.options.separateby == "fill_opacity": + fill_opacity = style.get('fill-opacity') if fill_opacity is not None: - fill_opacity = fill_opacity[0] - neutral_value = float(fill_opacity.split("fill-opacity:")[1].split(";")[0]) - layer_name = fill_opacity + neutral_value = float(fill_opacity) + layer_name = "fill-opacity-{}".format(neutral_value) else: layer_name = "fill-opacity-none" @@ -219,9 +213,8 @@ class StylesToLayers(inkex.EffectExtension): continue # we do some cosmetics with layers. Sometimes it can happen that one layer includes another. We don't want that. We move all layers to the top level - for newLayerNode in layerNodeList: + for newLayerNode in layerNodeList: self.document.getroot().append(newLayerNode[0]) - # Additionally if threshold was defined re-arrange the previously created layers by putting them into sub layers if self.options.subdividethreshold > 1 and contentlength > 0: #check if we need to subdivide and if there are items we could rearrange into sub layers @@ -294,6 +287,12 @@ class StylesToLayers(inkex.EffectExtension): #clean all empty layers from node list. Please note that the following remove_empty_groups #call does not apply for this so we need to do it as PREVIOUS step before! for i in range(0, len(layerNodeList)): + deletes = [] + for j in range(0, len(layerNodeList[i][0])): + if len(layerNodeList[i][0][j]) == 0 and isinstance(layerNodeList[i][0][j], inkex.Group): + deletes.append(layerNodeList[i][0][j]) + for delete in deletes: + delete.getparent().remove(delete) if len(layerNodeList[i][0]) == 0: if layerNodeList[i][0].getparent() is not None: layerNodeList[i][0].getparent().remove(layerNodeList[i][0])