PicScrub logoPicScrub
返回格式列表

SVG 格式

Scalable Vector Graphics

XML 结构

SVG 和本站其他格式都不一样,因为它不是二进制,而是纯粹的 XML 文本。 你可以直接用文本编辑器打开一个 SVG 读起来。这让清除元数据在概念上更简单, 但也意味着信息能藏身的地方更多了。

元数据可以以专门的元素出现,也可以是任意元素上的属性、XML 注释或处理指令。 矢量编辑器尤其喜欢往 SVG 文件里塞自己的数据。

SVG 的基本结构

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     width="100" height="100" viewBox="0 0 100 100">

  <!-- 元数据元素 -->
  <title>My Drawing</title>
  <desc>Created by John Doe</desc>
  <metadata>
    <rdf:RDF xmlns:rdf="...">
      <!-- RDF/Dublin Core 元数据 -->
    </rdf:RDF>
  </metadata>

  <!-- 矢量内容 -->
  <circle cx="50" cy="50" r="40" fill="red"/>
</svg>

几个关键元素

  • <svg>:根元素,带有 viewBox 和尺寸
  • xmlns:命名空间声明
  • <defs>:可复用的定义(渐变、图案)
  • <g>:分组元素

元数据元素

SVG 规范定义了好几种挂载元数据的方式,不同工具用法也不同。 有些一目了然(毕竟真的有一个 <metadata> 元素),有些则藏得更深。

<metadata>

结构化元数据的容器,通常是 RDF/Dublin Core, 可能包含创作者姓名、创建日期、权利声明等等。

<metadata>
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
           xmlns:dc="http://purl.org/dc/elements/1.1/">
    <rdf:Description>
      <dc:creator>John Doe</dc:creator>
      <dc:date>2024-01-15</dc:date>
    </rdf:Description>
  </rdf:RDF>
</metadata>

<title>

给整个 SVG 或单个元素起的可读标题。常用于无障碍访问, 但也可能暴露这份文件是干什么用的。

<desc>

描述元素,可能写着关于这张图、创作者或用途的详细信息。

XML 注释

<!-- comment --> 里可能藏着作者备注、 创建日期、软件信息或调试信息。

编辑器命名空间

这里就是 SVG 变乱的地方。每个矢量编辑器都会加上自己的带命名空间的属性, 用来存放 SVG 本身不支持的功能。打开一个 Inkscape 文件,你会看到满屏的 inkscape: 和 sodipodi: 属性。 它们本身算不上隐私风险,但足以标出你用的是什么软件。

inkscape:* / sodipodi:*

Inkscape 会加上带命名空间的属性,记录图层名称、参考线位置、 文档设置和编辑历史。

<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
     xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
     inkscape:version="1.2"
     sodipodi:docname="my-drawing.svg">
  <sodipodi:namedview inkscape:current-layer="layer1"/>
</svg>

Adobe Illustrator

Illustrator 会嵌入大量元数据,包括版本、画板设置, 有时甚至是完整的 AI 格式数据。

xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
xmlns:x="http://ns.adobe.com/Extensibility/1.0/"

Sketch / Figma

现代设计工具可能会在自定义属性里嵌入图层名称、组件 ID 和导出设置。

处理指令

SVG 文件开头的 XML 处理指令(<?...?>)里可能带有软件标识。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

保留与清除

  • • <?xml ...?> 声明:保留(必需)
  • • <?xml-stylesheet ...?>:保留(有实际功能)
  • • 其他处理指令:清除

基于 DOM 的处理

既然 SVG 是合法的 XML,我们就可以把它解析成 DOM 树, 再像做手术一样精准摘掉不想要的部分。这比用正则表达式硬匹配准确得多, 也不会误伤有效内容。

1

解析 XML

把 SVG 当作 XML 文档解析,保留原有结构

2

删除元数据元素

删掉 <metadata>、<title>、<desc> 元素

3

剥掉编辑器属性

清除 inkscape:*、sodipodi:* 以及其他编辑器命名空间

4

删除注释

把文档里所有 XML 注释都去掉

5

清理命名空间

从根元素上移除用不到的命名空间声明

6

序列化

把清理干净的 XML 重新写成 SVG 文件

处理小结

会保留

  • • 所有矢量图形(路径、形状、文字)
  • • 样式和 CSS
  • • 渐变和图案
  • • 滤镜和特效
  • • 嵌入的图片(通过引用)
  • • viewBox 和尺寸
  • • 标准的 SVG 命名空间

会清除

  • • <metadata> 元素
  • • <title> 元素
  • • <desc> 元素
  • • XML 注释
  • • inkscape:* 属性
  • • sodipodi:* 属性
  • • Adobe/Sketch 命名空间
  • • 用不到的命名空间声明

嵌入的位图

有个容易被忽视的坑:SVG 文件可以用 base64 data URI 的方式嵌入位图。 这些嵌进去的 JPEG 或 PNG,里面可能还藏着自己的 EXIF 元数据。

目前的局限

PicScrub 目前会清除 SVG 这一层的元数据,但不会解码和处理嵌入的位图:

<image href="data:image/jpeg;base64,/9j/4AAQ..." />

PicScrub 目前不会处理 SVG 文件里嵌入的位图。 如果想做到彻底,请把嵌入的图片提取出来单独处理。