Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify SVGs by applying transform - reduce size

Tags:

python

svg

I have quite often some SVGs with structures like this:

<svg:g
  transform="translate(-251.5,36.5)"
  id="g12578"
  style="fill:#ffff00;fill-opacity:1">
  <svg:rect
width="12"
height="12"
x="288"
y="35.999958"
id="rect12580"
style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1" />
</svg:g>

I would like to apply translate directly to the coordinates and delete the tranform-attribute:

<svg:g
  id="g12578"
  style="fill:#ffff00;fill-opacity:1">
  <svg:rect
width="12"
height="12"
x="36.5"
y="69.499958"
id="rect12580"
style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1" />
</svg:g>

Do you know a script / program for simplifying SVGs? Or a python-snipplet for parsing SVG's?

This script works for my special case, but I would like one which works allways:

#http://epydoc.sourceforge.net/stdlib/xml.dom.minidom.Element-class.html
from xml.dom.minidom import parse, parseString
import re

f = open('/home/moose/mathe/svg/Solitaire-Board.svg', 'r')

xmldoc = parse(f)

p = re.compile('translate\(([-\d.]+),([-\d.]+)\)', re.IGNORECASE)

for node in xmldoc.getElementsByTagName('svg:g'):
  transform_dict = node.attributes["transform"]
  m = p.match(transform_dict.value)
  if m:
    x = float(m.group(1))
    y = float(m.group(2))
  child_rectangles = node.getElementsByTagName('svg:rect') 
  for rectangle in child_rectangles:
    x_dict = rectangle.attributes["x"]
    y_dict = rectangle.attributes["y"]
    new_x = float(x_dict.value) + x
    new_y = float(y_dict.value) + y
    rectangle.setAttribute('x', str(new_x))
    rectangle.setAttribute('y', str(new_y))
  node.removeAttribute('transform')

print xmldoc.toxml()

I think the size of the svg could be reduced quite heavily without loss of quality, if the transform-attribute could be removed. If the tool would be able to reduce coordinate precision, delete unnecessary regions, group and style wisely it would be great.

like image 367
Martin Thoma Avatar asked Oct 12 '22 01:10

Martin Thoma


1 Answers

I'd recommend using lxml. It's extremely fast and has a lot of nice features. You can parse your example if you properly declare the svg namespace prefix. You can do that pretty easily:

>>> svg = '<svg xmlns:svg="http://www.w3.org/2000/svg">' + example_svg + '</svg>'

Now you can parse it with lxml.etree (or xml.etree.ElementTree):

>>> doc = etree.fromstring(svg)

If you use lxml you can take advantage of XPath:

>>> ns = {'svg': 'http://www.w3.org/2000/svg'}

>>> doc.xpath('//svg:g/@transform', namespaces=ns)
<<< ['translate(-251.5,36.5)']
like image 110
zeekay Avatar answered Oct 21 '22 09:10

zeekay