如何在 Python 中裁剪 SVG 图像?

问题描述 投票:0回答:3

通过程序,我正在生成尺寸为 400px x 400px 的 SVG 图像。但是,我想根据一个变量来裁剪此 SVG 图像的底部,该变量指示应裁剪图像底部的多少像素。

此 SVG 图像是使用 pyCairo 生成的,带有

surface = cairo.SVGSurface("output.svg", WIDTH, HEIGHT)
ctx = cairo.Context(surface)

虽然

HEIGHT
变量是一个常量并且没有改变,但在我对
surface
对象执行一些操作后,我希望能够再次调整它的大小。我可以使用 Pillow
Image
对象来裁剪 PNG,但它不支持 SVG。

我还尝试使用

open("output.svg")
打开 svg 文件。但是,如果我尝试阅读它,我无法阅读它,并且它显示为空白,从而使其不可修改。

Python 有没有办法在使用 pycairo 修改 SVG 图像后裁剪 SVG 图像或修改其大小?

python svg python-imaging-library pycairo
3个回答
2
投票

上面的答案不完整,至少对我来说没有解决问题。

可以使用 vpype 以及裁剪或修剪和平移命令简单地裁剪(修剪、剪裁、剪切)SVG。

import vpype_cli as vp
#vp.excute("read test.svg translate 300 400 trim 30 20 write output.svg")
vpype_cli.execute("read test.svg crop 0cm 0cm 10cm 20cm write output.svg")

调整参数应该会得到所需的裁剪。

花了一些时间才找到这个,因为大多数答案都说这是不可能完成的,这很荒谬。


0
投票

您不能像裁剪 PNG 那样裁剪 SVG,因为在后者中您只能删除像素,而对于前者,您定义了无法轻松重新计算的路径。

如果您确定要“裁剪”的部分没有任何内容,您可以使用

set_context_size
使 svg 上下文/画布变小,同时保留内部的比例和大小。


0
投票

这是通过

viewBox
属性裁剪 SVG 的示例。

def verify_bbox(bbox):
    if not isinstance(bbox, (tuple, list)):
        raise TypeError(f"Bounding box should be a tuple or list, got {type(bbox)}")
    if len(bbox) != 4:
        raise ValueError(f"Bounding box should have 4 values [left, top, right, bottom], got {len(bbox)}")
    for b in bbox:
        if not isinstance(b,(int,float)) or b < 0 or b > 1:
            raise ValueError(f"Bounding box values should be between 0 and 1, got {b}")

def crop_svg(svg, bbox):
    verify_bbox(bbox) # left, top, right, bottom in 0-1 range

    def crop_viewbox(m):
        vb, *_ = m.groups()
        x,y,w,h = [int(v) for v in vb.split()]

        X, Y = bbox[0]*w + x, bbox[1]*h + y # offset by original viewbox
        W, H = (bbox[2] - bbox[0])*w, (bbox[3] - bbox[1])*h
        return m.group().replace(vb, f'{X} {Y} {W} {H}') # Replace viewbox with new values
    
    return re.sub(r'viewBox\=[\"\'](.*?)[\"\']', crop_viewbox, svg ,1)

svg = '''<svg xmlns="http://www.w3.org/2000/svg" height="50px" viewBox="0 0 25 25" fill="red" stroke-width="2" transform="rotate(45)">\n    <rect x="9" y="0" width="8" height="6"/>\n    <rect x="9" y="7" width="1" height="10"/>\n    <rect x="12" y="7" width="2" height="10"/>\n    <rect x="16" y="7" width="1" height="10"/>\n    <polygon points="9 18,17 18,13 25,9 18"></polygon>\n</svg>'''

crop_svg(svg, [0.5,0,1,1])
'<svg xmlns="http://www.w3.org/2000/svg" height="50px" viewBox="12.5 0 12.5 25" fill="red" stroke-width="2" transform="rotate(45)">\n    <rect x="9" y="0" width="8" height="6"/>\n    <rect x="9" y="7" width="1" height="10"/>\n    <rect x="12" y="7" width="2" height="10"/>\n    <rect x="16" y="7" width="1" height="10"/>\n    <polygon points="9 18,17 18,13 25,9 18"></polygon>\n</svg>'

Original SVG Cropped SVG

有两点需要注意:

  • 裁剪沿着旋转的 viewBox 进行,而不是在 x,y 上。
  • height
    width
    之一应为
    'auto'
    或缺失才能正确查看,或者两者都相应重置。您可以添加以下行:
re.sub(r'height\=[\"\'](.*?)[\"\']', 'height="auto"', svg,1)
© www.soinside.com 2019 - 2024. All rights reserved.