在不更改像素值的情况下将 svg 转换为 png

Posted

技术标签:

【中文标题】在不更改像素值的情况下将 svg 转换为 png【英文标题】:Converting svg to png without changing the pixel values 【发布时间】:2017-12-20 23:48:09 【问题描述】:

我已经被这个问题困扰了一段时间了。本质上,我有一堆 svg 图像。 svg 文件中的每个“孩子”都标有一些像素值。目前这个值的数量非常少,所有东西都标记为 rgb(0.0, 0.0, 0.0), rgb(1.0, 1.0, 1.0) ... rgb(9.0, 9.0, 9.0),所以基本上我有 10 种不同的类型像素。

现在,我想将这些图像转换为 png 格式,更重要的是我需要像素值的映射为 1 对 1。本质上,所有在 svg 文件中具有 rgb(0.0, 0.0, 0.0) 值的像素,都需要在 png 文件中具有 rgb(x,x,x) 值(甚至更好的 L(x)); svg 文件上的 rgb(1.0, 1.0, 1.0) 需要转换为 png 文件上的 rgb(y,y,y) (甚至更好的 L(y))等等。这种一对一映射对我的应用程序来说是个大问题,因为这本质上是我工作的基本事实。

只需在控制台中编写:

    convert test.svg test.png

没有给我我想要的。检查值的直方图,似乎我有 248 个唯一值而不是 10 个,这对我不利(尽管它们中的绝大多数只有几个像素)。

有谁知道:

如果可以的话。 如何做到这一点。

到目前为止,我已经尝试过使用 Python 的 cairosvg 等其他库,但效果似乎更糟。是的,我知道 svg 和 png 是完全不同的格式。

为了澄清,添加一个 svg 和一个 png 文件:

svg:https://drive.google.com/open?id=0B_vhcDz1zxeYeGVDSnhfeWplOWs

png:https://drive.google.com/open?id=0B_vhcDz1zxeYUnYzZUtIUmVqVWM

在 Python 中打开文件,似乎有 248 个唯一像素值,而应该只有 4 个(背景 + 三个符号)。

谢谢!

【问题讨论】:

我认为你需要更具体一些,实际展示一个文件,而不是抽象地谈论 "children"Lx 和 “像素类型” 特别是考虑到svg 文件甚至没有像素。 没有看到您的测试文件,我只能猜测您看到的是缩放效果,其中 PNG 像素是从 SVG 数据点插入的。 公平点,我添加了一个svg文件,以及对应的png文件。 @MarkSetchell @GlennRanders-Pehrson 谢谢。我正在看一看。 GraphicsMagick 产生与您的 png 相同的输出。由于某种原因,我的 ImageMagick v6 和 v7 都拒绝了 svg 文件。 【参考方案1】:

您的请求没有多大意义。据我所知,您的示例 SVG 文件只有两种颜色:黑色和白色 (rgb(255.0, 255.0, 255.0))。那么这 10 种颜色的想法是从哪里来的呢?

另外,SVG 标准并没有具体说明如何将矢量形状转换为像素。 SVG 渲染器之间会有细微差别。

请记住,穿过像素中间的矢量形状边缘会产生灰色像素。这称为抗锯齿。它旨在使边缘看起来更平滑。我想这就是为什么您看到的像素值比您预期的要多。


也许您的意思是您想要一种禁用抗锯齿的方法?一些转换程序可能有执行此操作的选项。或者,您可以尝试将 shape-rendering 属性添加到文件的根 <svg> 标记:

<ns0:svg ...(snip)... shape-rendering="crispEdges">

但是一些 SVG 转换程序可能不支持这个属性。但是,如果您在大多数浏览器中尝试一下,就会发现它可以正常工作。

关闭抗锯齿生成的输出看起来不太好。但也许出于您的目的,您并不关心这一点。


或者,也许您想知道如何将 SVG 转换为位图,同时将抗锯齿限制为 10 个特定的灰色级别? Imagemagick 可以让你做到这一点。我不是 Imagemagick 用户,但显然您可以通过使用 -map 参数传递调色板图像来告诉 imagemagick 使用特定的调色板。

【讨论】:

在整个数据集上,我使用了 10 种颜色(9 种黑色,白色作为背景)。在我上传的图片上,应该有 4 种不同的颜色(一种白色,三种黑色,每个符号一个)。当然,三个黑色的对于人眼是无法区分的,但是如果以数组的形式打开文件,它们的值是不同的。我使用了抗锯齿,但它没有改变任何东西,我仍然获得了比我应该的更多的颜色。 Control-F fill="rgb(2.0, 2.0, 2.0)" fill="rgb(3.0, 3.0, 3.0)" fill="rgb(9.0, 9.0, 9.0)" 你会找出其他三种颜色。 还要注意rgb() 颜色中的值应该是整数。一些渲染器不支持像 2.0 这样的小数 - 例如。铬。 shape-rendering="crispEdges" 似乎有点用。现在,我得到了正确的颜色数量。另一方面,现在白色似乎是 65535 而不是 255(一个数字似乎用 2 个字节而不是 1 表示)。它不是一个破坏者(毕竟,我可以为此使用映射),但是有没有一种简单的方法可以让所有内容都在 [0, 255] 范围内? 我不知道 rgb() 值应该是整数。改变了这一点,虽然它似乎在输出中没有任何区别。 @保罗勒博【参考方案2】:

3 年,但没有很好的解决方案 gg:

我找到了 2 个不错的:

    您可以在 ImageMagick 命令行中使用:

    "转换 in.svg +antialias out.png"

但要小心,我的消息来源说“+”会停用 AA,而“-”会激活它。但是来源很老,这看起来很奇怪。我不能试试这个

    Inkscape 在更新中带来了一个很好的解决方案(我在版本 1.0.1 中尝试过): 在“导出 png”的高级设置中,您可以直接选择抗锯齿 "CAIRO_ANTIALIAS_NONE" 非常适合我

【讨论】:

以上是关于在不更改像素值的情况下将 svg 转换为 png的主要内容,如果未能解决你的问题,请参考以下文章

如何在不损失质量的情况下将 PNG 转换为 BMP

Ubuntu 下将 svg 图片转换为其他格式 (如 png)

我可以在不更改项目顺序的情况下将 JSON 字符串转换为 Flex ArrayCollection 吗?

如何在不丢失 swift 精度的情况下将 String 转换为 Double [重复]

如何在不将字体转换为轮廓的情况下将 cairo-pdf 转换为 eps

如何在不通知用户的情况下将画布保存为 png 文件,