通过应用变换简化SVG - 减小文件大小

5 投票
3 回答
2553 浏览
提问于 2025-04-16 17:40

我经常会遇到一些结构像这样的SVG文件:

<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>

我想直接对坐标进行平移,并删除变换属性:

<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>

你知道有没有简化SVG的脚本或程序吗?或者有没有Python的小代码可以解析SVG文件的?

这个脚本适合我特定的情况,但我希望能有一个通用的解决方案:

#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()

我觉得如果能去掉变换属性,SVG的大小可以大幅度减小,而且不会影响质量。如果这个工具还能减少坐标的精度,删除不必要的区域,合理地进行分组和样式设置,那就太好了。

3 个回答

0

1) 你可以用正则表达式来解析和编辑它。这样你就能轻松获取翻译的值和 x、y 的坐标。
2) 如果你检查了 minidom,确认你唯一的问题就是 ':' 这个符号,那你可以先把 ':' 替换掉,编辑你需要的内容,然后再把它换回来。
3) 你可以参考这个问题: 有没有什么脚本化的 SVG 编辑器? 来学习如何更好地解析这种 XML 格式。

1

你可以看看 scour

Scour 的目标是尽可能减小 SVG 文件的大小,同时保持文件的原始显示效果。不过,它并不是对所有文件都能完美处理,所以建议用户不要覆盖原始文件。

Scour 对 SVG 文件进行的优化包括:去掉空的元素、去掉元数据元素、去掉未使用的 id 属性值、去掉无法显示的元素、将坐标精简到一定的有效位数,以及去掉矢量编辑器的元数据。

3

我建议你使用 lxml。这个库非常快,而且有很多好用的功能。如果你正确地声明了 svg 的命名空间前缀,就可以解析你的例子。这个操作其实很简单:

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

现在你可以用 lxml.etree(或者 xml.etree.ElementTree)来解析它:

>>> doc = etree.fromstring(svg)

如果你使用 lxml,你还可以利用 XPath 的功能:

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

>>> doc.xpath('//svg:g/@transform', namespaces=ns)
<<< ['translate(-251.5,36.5)']

撰写回答