Python 中的 SVG viewBox 和坐标

快速解答: 要在 Python 中控制 SVG 坐标,请加载或创建 SVGDocument,并使用 set_attribute() 在 SVG 根元素上设置 widthheightviewBoxwidthheight 设置可见输出尺寸。viewBox 选择要显示的坐标矩形,SVG 会将该坐标系统放大或缩小以填满 viewport。

1from aspose.svg import SVGDocument
2
3with SVGDocument() as document:
4    svg = document.root_element
5    svg.set_attribute("width", "300")
6    svg.set_attribute("height", "150")
7    svg.set_attribute("viewBox", "0 0 100 50")
8    document.save("viewbox.svg")

在本文中,您将学习如何:

理解 viewBox 最简单的方法,是把“绘图所在的坐标空间”和“显示它的区域”分开。SVG 画布是放置形状的坐标空间。viewport 是可见输出区域,通常由 widthheight 定义。viewBox 的含义是:“在 viewport 中显示 SVG 画布上的这个矩形区域,然后把这个矩形缩放到填满 viewport。”

viewBox 属性包含四个值:min-xmin-ywidthheight。例如,viewBox="0 0 100 50" 表示:从坐标 (0, 0) 开始观察,水平方向显示 100 个坐标单位,垂直方向显示 50 个坐标单位。如果 viewport 是 300x150,这个 100x50 坐标系统会被放大 3 倍来填满可见区域。渲染尺寸也可以是 600x300 或其他等比例尺寸,同一组坐标会再次缩放以适配它。

viewBox 基础

属性示例含义
width300可见输出宽度,例如 300 个屏幕像素或 CSS 单位
height150可见输出高度
viewBox0 0 100 50要缩放到 viewport 中显示的坐标矩形
preserveAspectRatioxMidYMid meet当宽高比例不一致时,图形如何对齐和缩放

用户坐标系统就是应用 viewBox 后形状使用的坐标系统。如果矩形有 x="10"width="80",这些值以 viewBox 单位度量,而不是直接以屏幕像素度量。使用 width="300" height="150" viewBox="0 0 100 50" 时,SVG 会放大用户坐标系统:一个 viewBox 单位在两个方向上都变成 3 个渲染单位。如果 viewBox 大于 viewport,同一个机制会把绘图缩小。

如何在 Python 中设置 SVG viewBox

当生成的 SVG 图形需要可预测坐标和清晰可见区域时,请使用以下工作流:

  1. 创建或加载 SVGDocument
  2. document.root_element 获取 SVG 根元素。
  3. 使用 set_attribute() 设置 widthheightviewBox 等根属性。
  4. 使用位于 viewBox 矩形范围内的坐标添加或更新形状。
  5. 使用 document.save() 保存 SVG,并检查图形是否被裁剪。

使用较小的 viewBox 放大 SVG 图形

一种常见模式是保留简单的绘图坐标,同时渲染更大的图像。下面的示例使用 300x150 viewport 和 100x50 viewBox,然后用 viewBox 坐标绘制一个矩形。矩形定义为 80x30 个坐标单位,但显示为 240x90 个渲染单位,因为 viewport 在两个方向上都是 viewBox 的 3 倍。

 1import os
 2from aspose.svg import SVGDocument
 3
 4SVG_NS = "http://www.w3.org/2000/svg"
 5
 6output_folder = "output/"
 7output_path = os.path.join(output_folder, "svg-viewbox-fixed.svg")
 8os.makedirs(output_folder, exist_ok=True)
 9
10with SVGDocument() as document:
11    svg = document.root_element
12    svg.set_attribute("width", "300")
13    svg.set_attribute("height", "150")
14    svg.set_attribute("viewBox", "0 0 100 50")
15
16    rect = document.create_element_ns(SVG_NS, "rect")
17    rect.set_attribute("x", "10")
18    rect.set_attribute("y", "10")
19    rect.set_attribute("width", "80")
20    rect.set_attribute("height", "30")
21    rect.set_attribute("rx", "4")
22    rect.set_attribute("fill", "#2e86de")
23    svg.append_child(rect)
24
25    document.save(output_path)

输出会保持矩形比例,因为 viewport 比例 300:150 与 viewBox 比例 100:50 一致。SVG 会在 x 轴和 y 轴上用相同倍数放大用户坐标系统,所以矩形在屏幕上变大,但比例不变。实际使用中,您可以用方便的小数字设计图标、图表或示意图,并在更大尺寸下渲染,而不必重写每个坐标。

下图比较同一个矩形在同一个 300x150 渲染 viewport 中的效果。图 (a) 使用 viewBox="0 0 300 150",一个坐标单位对应一个渲染单位,因此 80x30 矩形保持较小。图 (b) 使用 viewBox="0 0 100 50",SVG 将较小的坐标系统放大 3 倍以填满同一 viewport。代码中的矩形数值相同,但显示得明显更大。

SVG viewBox 对比图,a 使用 viewBox 0 0 300 150 显示小矩形,b 使用 viewBox 0 0 100 50 显示放大的同一矩形

移动可见坐标区域

viewBox 的前两个值可以为负数,也可以不为零。它们不是移动单个形状,而是在 SVG 画布上移动可见坐标窗口。当生成的图形围绕中心点计算,或需要在跨越零点的形状周围留出空间时,这很有用。

在下一个示例中,viewBox="-60 -60 120 120" 使坐标 (0, 0) 出现在正方形 viewport 的中心。可见区域从 x=-60y=-60 开始,向右和向下各延伸 120 个单位。

 1import os
 2from aspose.svg import SVGDocument
 3
 4namespace_uri = "http://www.w3.org/2000/svg"
 5
 6output_folder = "output/"
 7output_path = os.path.join(output_folder, "svg-viewbox-shifted.svg")
 8os.makedirs(output_folder, exist_ok=True)
 9
10with SVGDocument() as document:
11    svg = document.root_element
12    svg.set_attribute("width", "240")
13    svg.set_attribute("height", "240")
14    svg.set_attribute("viewBox", "-60 -60 120 120")
15
16    x_axis = document.create_element_ns(namespace_uri, "line")
17    x_axis.set_attribute("x1", "-50")
18    x_axis.set_attribute("y1", "0")
19    x_axis.set_attribute("x2", "50")
20    x_axis.set_attribute("y2", "0")
21    x_axis.set_attribute("stroke", "#0071aa")
22    x_axis.set_attribute("stroke-width", "3")
23    svg.append_child(x_axis)
24
25    marker = document.create_element_ns(namespace_uri, "circle")
26    marker.set_attribute("cx", "0")
27    marker.set_attribute("cy", "0")
28    marker.set_attribute("r", "25")
29    marker.set_attribute("fill", "#00aaaa")
30    marker.set_attribute("stroke", "#006863")
31    marker.set_attribute("stroke-width", "5")
32    svg.append_child(marker)
33
34    document.save(output_path)

这里,可见区域的中心是坐标 (0, 0)。水平轴从 x=-50x=50,圆正好以原点为中心。这个模式适用于图标、标记、极坐标图以及更容易围绕中心点计算的生成符号。

下图比较显示一个中心位于坐标 (0, 0) 的圆的两种方式。图 (a) 使用 viewBox="0 0 240 240",因此 (0, 0) 是左上角,圆的大部分被裁剪到 viewport 外。图 (b) 使用 viewBox="-60 -60 120 120",可见坐标区域从 (-60, -60)(60, 60)。这样 (0, 0) 位于 viewport 中心,完整圆形可见。

SVG viewBox 对比图,a 使用 viewBox 0 0 240 240 裁剪以 0 0 为中心的圆,b 使用 viewBox -60 -60 120 120 将圆居中显示

常见错误和修复

问题原因修复
SVG 看起来为空所有可见元素都在 viewBox 定义的坐标矩形之外。例如,cx="200" 的圆在 viewBox="0 0 100 100" 中不可见。将元素移动到 viewBox 范围内,或增大 viewBox 的 widthheightmin-xmin-y,让元素位于可见坐标区域内。
图形被裁剪元素只有一部分位于 viewBox 内。SVG 显示落在可见坐标矩形内的部分,并隐藏其余部分。扩大 viewBox,或用 min-xmin-y 移动它,使整个形状适合可见区域。
图形看起来比预期更大viewBox 的宽度和高度小于 viewport,产生了放大效果。使用更大的 viewBox,或减小渲染的 widthheight
图形看起来比预期更小viewBox 的宽度和高度大于 viewport,产生了缩小效果。使用更小的 viewBox,或增大渲染的 widthheight
输出看起来被拉伸viewport 宽高比与 viewBox 宽高比不一致。例如,300x150100x100 的比例不同。使用匹配的比例,或有意识地设置 preserveAspectRatio
坐标难以管理viewBox 与您理解绘图的方式不一致。选择方便的坐标系统,例如图标使用 0 0 100 100,对称形状使用负数到正数的居中坐标。
边缘处的描边被切掉形状本身在范围内,但描边一半在形状边界内、一半在外。贴近 viewBox 边缘的圆可能会丢失部分轮廓。在 viewBox 内留出额外边距,或至少按 stroke-width 的一半将形状移离边缘。

常见问题

SVG viewBox 是什么意思?

viewBox 定义 SVG 画布上的哪个矩形坐标区域应显示在 SVG viewport 中。在 viewBox="0 0 100 50" 中,可见区域从 (0, 0) 开始,横向包含 100 个单位,纵向包含 50 个单位。然后 SVG 会把这个 100x50 坐标区域放大或缩小,以填满渲染 viewport。

viewport 和 viewBox 有什么区别?

viewport 是由 widthheight 定义的可见输出区域。viewBox 是映射到该可见区域的坐标矩形。更深入的 SVG 理论说明,请参阅 SVG Coordinate Systems and UnitsSVG viewBox

width 和 height 会改变 SVG 坐标吗?

不会。widthheight 控制渲染 viewport 的尺寸。viewBox 控制形状、文本和路径使用的坐标区域。即使 SVG 渲染为 100 像素宽或 1000 像素宽,cx="50" 的圆仍然使用坐标 50。

为什么较小的 viewBox 会让 SVG 图形看起来更大?

较小的 viewBox 显示较小的坐标区域,并把它适配到同一个 viewport。例如,将 viewBox="0 0 50 50" 放入 200x200 viewport 时,每个坐标单位占用的渲染空间会比 viewBox="0 0 200 200" 更大。

为什么较大的 viewBox 会让 SVG 图形看起来更小?

较大的 viewBox 会在同一个 viewport 中显示更多坐标空间。渲染器必须把更多画布区域压入同一可见尺寸,因此每个坐标单位占用的渲染空间更少,图形看起来更小。

viewBox 值可以是负数吗?

可以。负的 min-xmin-y 在围绕中心点绘制,或需要在接近零的坐标周围保留可见边距时很有用。

相关文章