通过程序,我正在生成尺寸为 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 图像或修改其大小?
上面的答案不完整,至少对我来说没有解决问题。
可以使用 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")
调整参数应该会得到所需的裁剪。
花了一些时间才找到这个,因为大多数答案都说这是不可能完成的,这很荒谬。
您不能像裁剪 PNG 那样裁剪 SVG,因为在后者中您只能删除像素,而对于前者,您定义了无法轻松重新计算的路径。
如果您确定要“裁剪”的部分没有任何内容,您可以使用
set_context_size
使 svg 上下文/画布变小,同时保留内部的比例和大小。
这是通过
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>'
有两点需要注意:
height
或 width
之一应为 'auto'
或缺失才能正确查看,或者两者都相应重置。您可以添加以下行:re.sub(r'height\=[\"\'](.*?)[\"\']', 'height="auto"', svg,1)