diff options
Diffstat (limited to 'share/extensions')
| -rwxr-xr-x | share/extensions/convert2dashes.py | 4 | ||||
| -rw-r--r-- | share/extensions/inkscape_help_keys.inx | 2 | ||||
| -rw-r--r-- | share/extensions/inkscape_help_relnotes.inx | 2 | ||||
| -rwxr-xr-x | share/extensions/launch_webbrowser.py | 1 | ||||
| -rwxr-xr-x | share/extensions/plotter.py | 2 | ||||
| -rw-r--r-- | share/extensions/restack.inx | 4 | ||||
| -rw-r--r-- | share/extensions/seamless_pattern.inx | 2 | ||||
| -rw-r--r-- | share/extensions/ungroup_deep.inx | 19 | ||||
| -rw-r--r-- | share/extensions/ungroup_deep.py | 281 |
9 files changed, 309 insertions, 8 deletions
diff --git a/share/extensions/convert2dashes.py b/share/extensions/convert2dashes.py index d13e6498e..1d1ba9736 100755 --- a/share/extensions/convert2dashes.py +++ b/share/extensions/convert2dashes.py @@ -50,10 +50,10 @@ class SplitIt(inkex.Effect): self.not_converted = [] def effect(self): - for _, node in self.selected.iteritems(): + for i, node in self.selected.iteritems(): self.convert2dash(node) if len(self.not_converted): - inkex.errormsg('Total number of objects not converted: {}\n'.format(len(self.not_converted))) + inkex.errormsg(_('Total number of objects not converted: {}\n').format(len(self.not_converted))) # return list of IDs in case the user needs to find a specific object inkex.debug(self.not_converted) diff --git a/share/extensions/inkscape_help_keys.inx b/share/extensions/inkscape_help_keys.inx index 612524517..5aabbea41 100644 --- a/share/extensions/inkscape_help_keys.inx +++ b/share/extensions/inkscape_help_keys.inx @@ -4,7 +4,7 @@ <id>org.inkscape.help.keys</id>
<dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
<!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/keys091.html</_param>
+ <_param name="url" gui-hidden="true" type="string">http://inkscape.org/doc/keys092.html</_param>
<effect needs-document="false">
<object-type>all</object-type>
<effects-menu hidden="true" />
diff --git a/share/extensions/inkscape_help_relnotes.inx b/share/extensions/inkscape_help_relnotes.inx index d032eb7e0..5c5b1b4e8 100644 --- a/share/extensions/inkscape_help_relnotes.inx +++ b/share/extensions/inkscape_help_relnotes.inx @@ -4,7 +4,7 @@ <id>org.inkscape.help.relnotes</id>
<dependency type="executable" location="extensions">launch_webbrowser.py</dependency>
<!-- i18n. Please don't translate it unless a page exists in your language -->
- <_param name="url" gui-hidden="true" type="string">http://wiki.inkscape.org/wiki/index.php/Release_notes/0.91</_param>
+ <_param name="url" gui-hidden="true" type="string">http://wiki.inkscape.org/wiki/index.php/Release_notes/0.92</_param>
<effect needs-document="false">
<object-type>all</object-type>
<effects-menu hidden="true" />
diff --git a/share/extensions/launch_webbrowser.py b/share/extensions/launch_webbrowser.py index 1ee6caca8..225484393 100755 --- a/share/extensions/launch_webbrowser.py +++ b/share/extensions/launch_webbrowser.py @@ -16,6 +16,7 @@ class VisitWebSiteWithoutLockingInkscape(threading.Thread): (self.options, args) = parser.parse_args() def run(self): + inkex.localize() webbrowser.open(_(self.options.url)) vwswli = VisitWebSiteWithoutLockingInkscape() diff --git a/share/extensions/plotter.py b/share/extensions/plotter.py index 14b41df18..8a14d55bc 100755 --- a/share/extensions/plotter.py +++ b/share/extensions/plotter.py @@ -147,7 +147,7 @@ class Plot(inkex.Effect): + "\n\n" + _("1. Download and extract (unzip) this file to your local harddisk:") + "\n" + " https://pypi.python.org/packages/source/p/pyserial/pyserial-2.7.tar.gz" + "\n" + _("2. Copy the \"serial\" folder (Can be found inside the just extracted folder)") - + "\n" + _(" into the following Inkscape folder: C:\\<Program files>\\inkscape\\python\\Lib\\") + + "\n" + _(" into the following Inkscape folder: C:\\[Program files]\\inkscape\\python\\Lib\\") + "\n" + _("3. Close and restart Inkscape.")) return # init serial framework diff --git a/share/extensions/restack.inx b/share/extensions/restack.inx index 4f5f577cb..e14d2d5d5 100644 --- a/share/extensions/restack.inx +++ b/share/extensions/restack.inx @@ -9,7 +9,7 @@ <_param name="desc_dir" type="description" appearance="header">Restack Direction</_param> <param name="nb_direction" type="notebook"> <page name="presets" _gui-text="Presets"> - <param name="direction" type="enum" _gui-text=""> + <param name="direction" type="enum" gui-text=""> <_item value="lr">Left to Right (0)</_item> <_item value="bt">Bottom to Top (90)</_item> <_item value="rl">Right to Left (180)</_item> @@ -36,7 +36,7 @@ </page> <page name="z_order" _gui-text="Based on Z-Order"> <_param name="desc_zsort" type="description" appearance="header">Restack Mode</_param> - <param name="zsort" type="enum" _gui-text=""> + <param name="zsort" type="enum" gui-text=""> <_item value="rev">Reverse Z-Order</_item> <_item value="rand">Shuffle Z-Order</_item> </param> diff --git a/share/extensions/seamless_pattern.inx b/share/extensions/seamless_pattern.inx index f63872272..219319b85 100644 --- a/share/extensions/seamless_pattern.inx +++ b/share/extensions/seamless_pattern.inx @@ -6,7 +6,7 @@ <dependency type="executable" location="extensions">inkex.py</dependency> <param name="width" _gui-text="Custom Width (px):" type="int" min="1" max="99999999">100</param> <param name="height" _gui-text="Custom Height (px):" type="int" min="1" max="99999999">100</param> - <_param name="help-info" type="description">This extension overwrite current document</_param> + <_param name="help-info" type="description">This extension overwrites the current document</_param> <effect needs-live-preview="false"> <object-type>All</object-type> diff --git a/share/extensions/ungroup_deep.inx b/share/extensions/ungroup_deep.inx new file mode 100644 index 000000000..f0b6339e8 --- /dev/null +++ b/share/extensions/ungroup_deep.inx @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <_name>Deep Ungroup</_name> + <id>mcepl.ungroup_deep</id> + <dependency type="executable" location="extensions">ungroup_deep.py</dependency> + <dependency type="executable" location="extensions">inkex.py</dependency> + <_param name="title" type="description">Ungroup all groups in the selected object.</_param> + <param name="startdepth" type="int" min="0" max="65535" _gui-text="Starting Depth">0</param> + <param name="maxdepth" type="int" min="0" max="65535" _gui-text="Stopping Depth (from top)">65535</param> + <param name="keepdepth" type="int" min="0" max="65535" _gui-text="Depth to Keep (from bottom)">0</param> + <effect needs-live-preview="false"> + <effects-menu > + <submenu _name="Arrange" /> + </effects-menu> + </effect> + <script> + <command reldir="extensions" interpreter="python">ungroup_deep.py</command> + </script> +</inkscape-extension> diff --git a/share/extensions/ungroup_deep.py b/share/extensions/ungroup_deep.py new file mode 100644 index 000000000..d27bb8a69 --- /dev/null +++ b/share/extensions/ungroup_deep.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +see #inkscape on Freenode and +https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 +for an example how to do the transform of parent to children. +""" + +__version__ = "0.2" # Works but in terms of maturity, still unsure + +from inkex import addNS +import logging +import simplestyle +import simpletransform +logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', + level=logging.INFO) + +try: + import inkex +except ImportError: + raise ImportError("""No module named inkex in {0}.""".format(__file__)) + +try: + from numpy import matrix +except: + raise ImportError("""Cannot find numpy.matrix in {0}.""".format(__file__)) + +SVG_NS = "http://www.w3.org/2000/svg" +INKSCAPE_NS = "http://www.inkscape.org/namespaces/inkscape" + + +class Ungroup(inkex.Effect): + + def __init__(self): + inkex.Effect.__init__(self) + self.OptionParser.add_option("-s", "--startdepth", + action="store", type="int", + dest="startdepth", default=0, + help="starting depth for ungrouping") + self.OptionParser.add_option("-m", "--maxdepth", + action="store", type="int", + dest="maxdepth", default=65535, + help="maximum ungrouping depth") + self.OptionParser.add_option("-k", "--keepdepth", + action="store", type="int", + dest="keepdepth", default=0, + help="levels of ungrouping to " + + "leave untouched") + + def _get_dimension(s="1024"): + """Convert an SVG length string from arbitrary units to pixels""" + if s == "": + return 0 + try: + last = int(s[-1]) + except: + last = None + + if type(last) == int: + return float(s) + elif s[-1] == "%": + return 1024 + elif s[-2:] == "px": + return float(s[:-2]) + elif s[-2:] == "pt": + return float(s[:-2]) * 1.25 + elif s[-2:] == "em": + return float(s[:-2]) * 16 + elif s[-2:] == "mm": + return float(s[:-2]) * 3.54 + elif s[-2:] == "pc": + return float(s[:-2]) * 15 + elif s[-2:] == "cm": + return float(s[:-2]) * 35.43 + elif s[-2:] == "in": + return float(s[:-2]) * 90 + else: + return 1024 + + def _merge_transform(self, node, transform): + """Propagate style and transform to remove inheritance + Originally from + https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 + """ + + # Compose the transformations + if node.tag == addNS("svg", "svg") and node.get("viewBox"): + vx, vy, vw, vh = [self._get_dimension(x) + for x in node.get("viewBox").split()] + dw = self._get_dimension(node.get("width", vw)) + dh = self._get_dimension(node.get("height", vh)) + t = ("translate(%f, %f) scale(%f, %f)" % + (-vx, -vy, dw / vw, dh / vh)) + this_transform = simpletransform.parseTransform( + t, transform) + this_transform = simpletransform.parseTransform( + node.get("transform"), this_transform) + del node.attrib["viewBox"] + else: + this_transform = simpletransform.parseTransform(node.get( + "transform"), transform) + + # Set the node's transform attrib + node.set("transform", + simpletransform.formatTransform(this_transform)) + + def _merge_style(self, node, style): + """Propagate style and transform to remove inheritance + Originally from + https://github.com/nikitakit/svg2sif/blob/master/synfig_prepare.py#L370 + """ + + # Compose the style attribs + this_style = simplestyle.parseStyle(node.get("style", "")) + remaining_style = {} # Style attributes that are not propagated + + # Filters should remain on the top ancestor + non_propagated = ["filter"] + for key in non_propagated: + if key in this_style.keys(): + remaining_style[key] = this_style[key] + del this_style[key] + + # Create a copy of the parent style, and merge this style into it + parent_style_copy = style.copy() + parent_style_copy.update(this_style) + this_style = parent_style_copy + + # Merge in any attributes outside of the style + style_attribs = ["fill", "stroke"] + for attrib in style_attribs: + if node.get(attrib): + this_style[attrib] = node.get(attrib) + del node.attrib[attrib] + + if (node.tag == addNS("svg", "svg") + or node.tag == addNS("g", "svg") + or node.tag == addNS("a", "svg") + or node.tag == addNS("switch", "svg")): + # Leave only non-propagating style attributes + if len(remaining_style) == 0: + if "style" in node.keys(): + del node.attrib["style"] + else: + node.set("style", simplestyle.formatStyle(remaining_style)) + + else: + # This element is not a container + + # Merge remaining_style into this_style + this_style.update(remaining_style) + + # Set the element's style attribs + node.set("style", simplestyle.formatStyle(this_style)) + + def _merge_clippath(self, node, clippathurl): + + if (clippathurl): + node_transform = simpletransform.parseTransform( + node.get("transform")) + if (node_transform): + # Clip-paths on nodes with a transform have the transform + # applied to the clipPath as well, which we don't want. So, we + # create new clipPath element with references to all existing + # clippath subelements, but with the inverse transform applied + inverse_node_transform = simpletransform.formatTransform( + self._invert_transform(node_transform)) + new_clippath = inkex.etree.SubElement( + self.xpathSingle('//svg:defs'), 'clipPath', + {'clipPathUnits': 'userSpaceOnUse', + 'id': self.uniqueId("clipPath")}) + clippath = self.getElementById(clippathurl[5:-1]) + for c in (clippath.iterchildren()): + inkex.etree.SubElement( + new_clippath, 'use', + {inkex.addNS('href', 'xlink'): '#' + c.get("id"), + 'transform': inverse_node_transform, + 'id': self.uniqueId("use")}) + + # Set the clippathurl to be the one with the inverse transform + clippathurl = "url(#" + new_clippath.get("id") + ")" + + # Reference the parent clip-path to keep clipping intersection + # Find end of clip-path chain and add reference there + node_clippathurl = node.get("clip-path") + while (node_clippathurl): + node = self.getElementById(node_clippathurl[5:-1]) + node_clippathurl = node.get("clip-path") + node.set("clip-path", clippathurl) + + def _invert_transform(self, transform): + # duplicate list to avoid modifying it + return matrix(transform + [[0, 0, 1]]).I.tolist()[0:2] + + # Flatten a group into same z-order as parent, propagating attribs + def _ungroup(self, node): + node_parent = node.getparent() + node_index = list(node_parent).index(node) + node_style = simplestyle.parseStyle(node.get("style")) + node_transform = simpletransform.parseTransform(node.get("transform")) + node_clippathurl = node.get('clip-path') + for c in reversed(list(node)): + self._merge_transform(c, node_transform) + self._merge_style(c, node_style) + self._merge_clippath(c, node_clippathurl) + node_parent.insert(node_index, c) + node_parent.remove(node) + + # Put all ungrouping restrictions here + def _want_ungroup(self, node, depth, height): + if (node.tag == addNS("g", "svg") and + node.getparent() is not None and + height > self.options.keepdepth and + depth >= self.options.startdepth and + depth <= self.options.maxdepth): + return True + return False + + def _deep_ungroup(self, node): + # using iteration instead of recursion to avoid hitting Python + # max recursion depth limits, which is a problem in converted PDFs + + # Seed the queue (stack) with initial node + q = [{'node': node, + 'depth': 0, + 'prev': {'height': None}, + 'height': None}] + + while q: + current = q[-1] + node = current['node'] + depth = current['depth'] + height = current['height'] + + # Recursion path + if (height is None): + # Don't enter non-graphical portions of the document + if (node.tag == addNS("namedview", "sodipodi") + or node.tag == addNS("defs", "svg") + or node.tag == addNS("metadata", "svg") + or node.tag == addNS("foreignObject", "svg")): + q.pop() + + # Base case: Leaf node + if (node.tag != addNS("g", "svg") or not len(node)): + current['height'] = 0 + + # Recursive case: Group element with children + else: + depth += 1 + for c in node.iterchildren(): + q.append({'node': c, 'prev': current, + 'depth': depth, 'height': None}) + + # Return path + else: + # Ungroup if desired + if (self._want_ungroup(node, depth, height)): + self._ungroup(node) + + # Propagate (max) height up the call chain + height += 1 + previous = current['prev'] + prev_height = previous['height'] + if (prev_height is None or prev_height < height): + previous['height'] = height + + # Only process each node once + q.pop() + + def effect(self): + if len(self.selected): + for elem in self.selected.itervalues(): + self._deep_ungroup(elem) + else: + for elem in self.document.getroot(): + self._deep_ungroup(elem) + +if __name__ == '__main__': + effect = Ungroup() + effect.affect() |
