"""
Simplifies SVG files in preparation for sif export.
Copyright (C) 2011 Nikita Kitaev
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
"""
import inkex
###### Utility Classes ####################################
"""Raised when the SVG document is invalid or contains unsupported features"""
return """SVG document is invalid or contains unsupported features
Error message: %s
The SVG to Synfig converter is designed to handle SVG files that were created using Inkscape. Unsupported features are most likely to occur in SVG files written by other programs.
try:
except:
"""A class for calling Inkscape to perform operations on a document"""
"""Set the SVG document that Inkscape will operate on"""
"""Set the initial arguments to Inkscape subprocess
Can be used to pass additional arguments to Inkscape, or an initializer
command (e.g. unlock all objects before proceeding).
"""
"""Clear all actions"""
"""Run an Inkscape verb
For a list of verbs, run `inkscape --verb-list`
"""
if self.has_selection:
if not self.has_action:
"""Select object with given id"""
if not self.has_selection:
"""Select the object represented by the SVG node
Selection will fail if node has no id attribute
"""
if node_id is None:
raise MalformedSVGError, "Node has no id"
"""Select objects represented by SVG nodes
Selection will fail if any node has no id attribute
"""
"""Select objects matching a given XPath expression
Selection will fail if any matching node has no id attribute
"""
"""Deselect all objects"""
if self.has_selection:
"""Run the actions on a specific file"""
if not self.has_action:
return
if bsubprocess:
f = p.stdout
else:
f.close()
"""Run the actions on the svg xml tree"""
if not self.has_action:
return self.svg_document
# First save the document
# Run the action on the document
# Open the resulting file
# Clean up.
try:
except Exception:
pass
# Set the current SVG document
# Return the new document
return new_svg_doc
"""An action group with stock commands designed for Synfig exporting"""
"""Convert unsupported objects to paths"""
# Flow roots contain rectangles inside them, so they need to be
# converted to paths separately from other shapes
non_paths = [
"svg:rect",
"svg:circle",
"svg:ellipse",
"svg:line",
"svg:polyline",
"svg:polygon",
"svg:text"
]
# Build an xpath command to select these nodes
# Select all of these elements
# Note: already selected elements are not deselected
# Convert them to paths
"""Unlink clones (remove <svg:use> elements)"""
###### Utility Functions ##################################
### Path related
"""Fuse subpaths of a path. Should only be used on unstroked paths"""
return
i = 0
return_stack = []
# Remove any terminators: they are redundant
continue
# Skip all elements that do not begin a new path
i += 1
continue
# This element begins a new path - it should be a moveto
# Swap it for a lineto
# If the old subpath has not been closed yet, close it
i += 1
# Set the initial point of this subpath
# Append this point to the return stack
#end while
# Now pop the entire return stack
while return_stack != []:
i += 1
"""Split a path into two paths, one filled and one stroked
Returns a the list [fill, stroke], where each is the XML element of the
fill or stroke, or None.
"""
# If there is only stroke or only fill, don't split anything
return [None, None] # Path has neither stroke nor fill
else:
return [None, path_node]
return [path_node, None]
d = attribs["d"]
del attribs["d"]
else:
raise AssertionError, "Cannot split stroke and fill of non-path element"
else:
nodetypes = None
del attribs["id"]
else:
del attribs["style"]
del attribs["transform"]
else:
transform = None
# Pass along all remaining attributes to the group
# Next split apart the style attribute
style_group = {}
else:
# Finalize the two paths
if nodetypes is not None:
if transform is not None:
# Replace the original node with the group
### Object related
"""Propagate style and transform to remove inheritance"""
# Don't enter non-graphical portions of the document
return
# Compose the transformations
else:
# Compose the style attribs
remaining_style = {} # Style attributes that are not propagated
for key in non_propagated:
del this_style[key]
# Create a copy of the parent style, and merge this style into it
# Merge in any attributes outside of the style
for attrib in style_attribs:
# Leave only non-propagating style attributes
else:
# Remove the transform attribute
# Continue propagating on subelements
for c in node.iterchildren():
else:
# This element is not a container
# Merge remaining_style into this_style
# Set the element's style and transform attribs
### Style related
"""Convert an SVG length string from arbitrary units to pixels"""
if s == "":
return 0
try:
except:
last = None
return float(s)
elif s[-1] == "%":
return 1024
elif s[-2:] == "px":
return float(s[:-2])
elif s[-2:] == "pt":
elif s[-2:] == "em":
elif s[-2:] == "mm":
elif s[-2:] == "pc":
elif s[-2:] == "cm":
elif s[-2:] == "in":
else:
return 1024
###### Main Class #########################################
"""Transform document in preparation for exporting it into the Synfig format"""
# Remove inheritance of attributes
# Fuse multiple subpaths in fills
# There are multiple subpaths
if fill is not None:
if __name__ == '__main__':
try:
e = SynfigPrep()
e.affect()
except MalformedSVGError, e:
errormsg(e)
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99