【问题标题】:In python convert SVG to PNG while resizing and increasing quality在 python 中将 SVG 转换为 PNG,同时调整大小和提高质量
【发布时间】:2021-09-15 10:45:49
【问题描述】:

首先我注意到有很多相关的问题,但是在尝试了一天的 pyvip 和 cairo 之后,其余的都不适合我,即使在安装了它们似乎依赖的其他软件之后也是如此。例外是带有reportlab的svglib,它很接近,但还没有完全到达那里! This 是我找到的最好的帖子,可能会对一些人有所帮助。

我的所有源图像都保存在 SVG 文件中。大多数应用商店都要求您提供一组具有特定大小和质量的 PNG。所以我需要一个 SVG 并生成一个宽度为 w 和高度为 h 和特定 dpi 的 PNG。我想在 python 中以编程方式执行此操作。

我编写了一个几乎可以工作的函数,但是缩放和 dpi 以奇怪的方式相互影响。我使用 svglib 将 SVG 转换为 ReportLab 绘图,然后使用 reportlab 来操作绘图。与其他一些选项不同,Windows 上的安装非常顺利。

pip install svglib
pip install reportlab

代码如下。我检查了上述库以获取参数,但添加了一些东西以获得特定的大小。

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM

def svg_to_png(in_path,out_path,fmt="PNG",
    scale=None,size=None,scale_x=1,size_x=None,scale_y=1,size_y=None,
    dpi=72, bg=0xffffff):
    # Convert SVG to ReportLab drawing. 
    drawing = svg2rlg(in_path)
    # Work out scale factors
    # Scale over-rides scale_x|y, ditto size
    scale_x = scale if scale else scale_x
    scale_y = scale if scale else scale_y
    size_x = size if size else size_x
    size_y = size if size else size_y
    # Size over-rides scale
    scaling_x = size_x/drawing.width if size_x else scale_x
    scaling_y = size_y/drawing.height if size_y else scale_y
    # Scale the drawing
    drawing.width = drawing.minWidth() * scaling_x
    drawing.height = drawing.height * scaling_y
    drawing.scale(scaling_x, scaling_y)
    # Render ReportLab drawing as a PNG
    renderPM.drawToFile(drawing, out_path, fmt=fmt, dpi=dpi, bg=bg)

if __name__ == '__main__': 
    breakpoint()
    in_path = 'C:\\Users\\...\\A.svg'
    out_path = 'C:\\Users\\...\\A.png'
    svg_to_png(in_path,out_path,scale=2,dpi=72)

只要我不考虑 dpi,该功能就可以调整大小。 dpi=72 似乎是 reportlab 中的通用默认值和问题的根源。我希望增加 dpi 会提高 PNG 的质量(减少像素化),但它似乎所做的只是扩大画布。

输入的 SVG 当然是像素完美的。以下是上述函数的四个 PNG。

比例 1 dpi 72(暗淡 115x124 大小 8.13kb),使用所有默认值进行转换。

缩放 1 dpi 144(dim 230x249 大小 9.06kb),画布翻倍,图片在左下象限,忽略黑线错误。

缩放 2 dpi 72(暗淡 230x249 大小 17.5kb),缩放正确但像素化(看着眼睛)

缩放 2 dpi 144(dim 461x497 大小 19.8kb),画布四倍?图片翻倍了。

有人可以建议如何正确使用reportlab将图片调整为给定的比例或尺寸,并在该固定尺寸内,通过dpi提高质量。

【问题讨论】:

    标签: python svg reportlab


    【解决方案1】:

    回答我自己的问题,在 svglib 中进行大量代码检查后,似乎不可能调整大小并将 dpi 增加到预定义的值。这是因为 svglib 将 SVG 渲染到 ReportLab 绘图,而没有任何能力告诉它以所需的分辨率渲染 SVG,鉴于矢量的整个点是任意分辨率,这是一种耻辱。一旦进入 ReportLab,您就会被绘图的分辨率所困扰。

    我切换到使用 libvips 的 pyvips。

    安装有点繁琐,不能只pip install pyvips。您必须下载libvips package 并将其解压缩到磁盘上您保存程序的某个位置。然后,您可以以通常的方式 pip install pyvips 。然后在您的 python 代码中将 libvips /bin 添加到您的路径中,假设您不想从操作系统永久执行此操作。

    然后可以使用以下函数将 SVG 转换为 PNG 并设置 PNG 的分辨率并对其进行缩放或设置其水平宽度。

    def svg_to_png(svg_path,png_path,dpi=72,scale=1,size=None):
        # Documentation
        # Ref: https://libvips.github.io/libvips/API/current/
        # Ref: https://libvips.github.io/pyvips/
        # Initialise
        debug=False
        import os
        os.environ['path'] += r';C:\programs\vips\vips-dev-8.11\bin'
        import pyvips
        # Get the image
        if size:
            image = pyvips.Image.new_from_file(svg_path,dpi=dpi,scale=1)
            if debug: print({field:image.get(field) for field in image.get_fields()})
            scale = size/image.get('width')
            image = image.resize(scale)
        else:
            image = pyvips.Image.new_from_file(svg_path,dpi=dpi,scale=scale)
        # Write the image
        if debug: print({field:image.get(field) for field in image.get_fields()})
        image.write_to_file(png_path)
    

    该功能在缩放时正常工作。设置固定输出大小时效果很好,但可能需要稍微调整输入 dpi 才能获得准确正确的输出 dpi。

    【讨论】:

    • 非常感谢您回答您自己的问题!这正是我所需要的。
    猜你喜欢
    • 2013-08-14
    • 2016-04-24
    • 2016-06-30
    • 2013-06-24
    • 2013-02-15
    • 2017-06-11
    • 2021-11-06
    • 2018-07-31
    • 1970-01-01
    相关资源
    最近更新 更多