Mar*_*ink 5 python svg reportlab
首先,我注意到有很多相关的问题,但是在尝试了 pyvip 和 cairo 以及其余的一天之后,即使在安装了它们似乎依赖的其他软件之后,它们都对我不起作用。例外是 svglib 和 reportlab,它很接近,但还没有完全达到目标!这是我发现的最好的帖子,可能会对一些人有所帮助。
我的所有源图像都保存在 SVG 文件中。大多数应用商店要求您提供一组具有特定尺寸和质量的 PNG。所以我需要获取一个 SVG 并生成一个宽度为 w、高度为 h 以及特定 dpi 的 PNG。我想在 python 中以编程方式执行此操作。
我编写了一个几乎可以工作的函数,但是缩放和 dpi 以奇怪的方式相互作用。我使用 svglib 将 SVG 转换为 ReportLab 绘图,然后使用 reportlab 操作该绘图。与其他一些选项不同,Windows 上的安装过程很顺利。
pip install svglib
pip install reportlab
Run Code Online (Sandbox Code Playgroud)
代码如下。我检查了上面的库来获取参数,但添加了一些东西来获取特定的大小。
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)
Run Code Online (Sandbox Code Playgroud)
只要我不考虑 dpi,该函数就可以调整大小。dpi=72 似乎是reportlab 中的通用默认值,也是问题的根源。我希望增加 dpi 能够提高 PNG 的质量(减少像素化),但它似乎所做的只是扩大画布。
输入的 SVG 当然是像素完美的。这是上述函数中的四个 PNG。
比例 1 dpi 72(暗淡 115x124 大小 8.13kb),使用所有默认值进行转换。
比例 1 dpi 144(暗淡 230x249 大小 9.06kb),画布加倍,图片位于左下象限,忽略黑线错误。
缩放 2 dpi 72(暗淡 230x249 大小 17.5kb),缩放正确但像素化(看眼睛)
比例 2 dpi 144(暗淡 461x497 大小 19.8kb),画布四倍?图片翻倍了。
有人可以建议如何正确使用reportlab将图片调整为给定的比例或尺寸,并在该固定尺寸内通过dpi提高质量。
回答我自己的问题,在 svglib 中进行大量代码检查后,似乎不可能调整大小并将 dpi 增加到预定义值。这是因为 svglib 将 SVG 渲染到 ReportLab 绘图,但没有任何能力告诉它以所需的分辨率渲染 SVG,考虑到矢量的整个点是任意分辨率,这是一个遗憾。一旦进入 ReportLab,您就会被绘图的分辨率所困扰。
我切换到使用 libvips 的 pyvips。
安装起来有点麻烦,你不能只 pip install pyvips 。您必须下载libvips 软件包并将其解压缩到磁盘上保存程序的位置。然后你可以按照通常的方式 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)
Run Code Online (Sandbox Code Playgroud)
缩放时该功能可以正常工作。设置固定输出大小时,效果很好,但可能需要对输入 dpi 进行一些调整才能获得准确正确的输出 dpi。