Skip to main content
 首页 » 编程设计

python之如何在不调整其内容大小的情况下使 SVG 图像的视口(viewport)变为正方形

2025年05月04日14qq号

我有一个包含以下内容的 SVG 图像(可以说是一个简单的图标):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M436 160c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V48c0-26.51-21.49-48-48-48H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20zm-74 304H54a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v404a6 6 0 0 1-6 6zM128 208c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm208 133.477V360c0 13.255-10.745 24-24 24H104c-13.255 0-24-10.745-24-24v-18.523c0-22.026 14.99-41.225 36.358-46.567l35.657-8.914c29.101 20.932 74.509 26.945 111.97 0l35.657 8.914C321.01 300.252 336 319.452 336 341.477z"/></svg> 

viewbox 不是正方形 (448!=512) 我需要让短边等于长边,这样它的内容就不会失去它们的原始比例(=> 不要拉伸(stretch)),并且它们需要到达 Canvas 的确切中心。

示例:将左侧图像转换为右侧图像。 (边框不是实际路径而是 View 框)

编程语言和工具并不重要。我只需要可以应用于许多文件的东西(在 bash 脚本中)。因此欢迎使用带有第三方库解决方案的 imagemagick、inkscape、python。

请您参考如下方法:

玩你的测试 svg(使用 internet explorer 作为查看器)表明,在没有定义 width,height 的情况下为 SVG 更改 viewBox 不会改变它们的方面(没有拉伸(stretch)只是缩放和平移),因此无需使用矩阵,所有这些都可以单独在 viewBox 中完成。这是你的例子:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"> 
 <path d="M436 160c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V48c0-26.51-21.49-48-48-48H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20zm-74 304H54a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v404a6 6 0 0 1-6 6zM128 208c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm208 133.477V360c0 13.255-10.745 24-24 24H104c-13.255 0-24-10.745-24-24v-18.523c0-22.026 14.99-41.225 36.358-46.567l35.657-8.914c29.101 20.932 74.509 26.945 111.97 0l35.657 8.914C321.01 300.252 336 319.452 336 341.477z"/> 
</svg> 

所以你想将 448 更改为 512 但我们仍想使图像居中因此我们也需要调整 x0 位置(在相反方向上调整一半差异 (512-448)/2 = 32)。因此,将 viewBox 更改为:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="-32 0 512 512"> 
 <path d="M436 160c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V48c0-26.51-21.49-48-48-48H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20zm-74 304H54a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v404a6 6 0 0 1-6 6zM128 208c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm208 133.477V360c0 13.255-10.745 24-24 24H104c-13.255 0-24-10.745-24-24v-18.523c0-22.026 14.99-41.225 36.358-46.567l35.657-8.914c29.101 20.932 74.509 26.945 111.97 0l35.657 8.914C321.01 300.252 336 319.452 336 341.477z"/> 
</svg> 

假设原始参数是:viewBox(x0,y0,xs0,ys0) 那么新参数就是viewBox(x1,y1,xs1,ys1)其中:

xs1= ys1 = max(xs0,ys0); 
x1 = x0 + (xs0 - xs1)/2; 
y1 = y0 + (ys0 - ys1)/2; 

因为 SVG 只是文本文件 (XML),以防您没有 R/W 访问 SVG::viewBox 在你的环境中,然后只需编写一个脚本来搜索/解析/替换文本文件中的 viewBox 文本......我不在 python 中编写代码,而是在 C++将只是“几行”代码(注意一些 SVG 是 ASCII 一些是 UNICODE)。