summaryrefslogtreecommitdiffstats
path: root/share/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions')
-rwxr-xr-xshare/extensions/convert2dashes.py4
-rw-r--r--share/extensions/inkscape_help_keys.inx2
-rw-r--r--share/extensions/inkscape_help_relnotes.inx2
-rwxr-xr-xshare/extensions/launch_webbrowser.py1
-rwxr-xr-xshare/extensions/plotter.py2
-rw-r--r--share/extensions/restack.inx4
-rw-r--r--share/extensions/seamless_pattern.inx2
-rw-r--r--share/extensions/ungroup_deep.inx19
-rw-r--r--share/extensions/ungroup_deep.py281
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()