将所有 cairo RecordingSurface 传输到 SVG

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

使用以下代码,我尝试使用 cairocffi 绘制图形。由于在绘制图形之前我不知道图形有多大,因此我使用无界 RecordingSurface 来记录操作,然后将操作传输到正确尺寸的 SVGSurface。然而,当我这样做时,只有一小部分图表出现在输出图像的左上角。 (我执行此操作的特定图表最终大多带有负 x 和 y 坐标。)如何让整个图表显示在最终的 SVGSurface 中?

import cairocffi as cairo
# ...
def draw_line(ctx):
    dx, dy = unit_vector(ctx.angle)
    ctx.rel_line_to(dx, dy)

def eval_symbol(sym, ctx):
    if sym == 'L':
        ctx.angle -= ANGLE
    elif sym == 'R':
        ctx.angle += ANGLE
    elif sym == 'F':
        draw_line(ctx)

def graph(iteration):
    rec_surf = cairo.RecordingSurface(cairo.CONTENT_COLOR, None)
    ctx = cairo.Context(rec_surf)
    ctx.move_to(0, 0)
    ctx.angle = 0

    for sym in iteration:
        eval_symbol(sym, ctx)
    ctx.stroke()
    x, y, width, height = rec_surf.ink_extents()
    print(x, y, width, height)

    final_surf = cairo.SVGSurface(FILENAME, width, height)
    final_ctx = cairo.Context(final_surf)
    final_ctx.set_source_surface(rec_surf, 0, 0)
    final_ctx.paint()
python-3.x svg cairo
1个回答
0
投票

您已通过将记录表面设置为源表面,将其正确重播(绘制)为 svg 表面。

但是,您未能考虑墨水范围中的 x/y 偏移。

所有数据均输出为svg。您根本看不到它,因为您的图像查看器正在将输出裁剪为 svg 视口的大小。

设置源表面时,还要设置偏移量,以将所有着墨表面放入视口内。 (注意必须是-x,-y)

您可以在 Inkscape 中打开 svg 以查看视口之外的内容。

#!/bin/python3

import cairo

def draw(surface, S):
    cr = cairo.Context(surface)
    cr.set_source_rgba(1, 0, 0, 1)
    cr.rectangle(0, 0, S, S)
    cr.stroke()
    
    # draw something partially outside of the target surface svg window
    cr.set_source_rgba(0, 1, 0, 1)
    cr.rectangle(-10, -10, 20, 20)
    cr.fill()
    
    # draw something entirely outside of the target surface svg window
    cr.set_source_rgba(0, 1, 0, 1)
    cr.rectangle(-100, -100, 20, 20)
    cr.fill()

    
if __name__=='__main__':
    S = 100

    rec = cairo.RecordingSurface(cairo.CONTENT_COLOR, None)
    
    #draw
    draw(rec, S)

    #replay
    x, y, width, height = rec.ink_extents()
    print(x, y, width, height)
    svg = cairo.SVGSurface("out.svg", width, height)
    
    cr = cairo.Context(svg)
    cr.set_source_surface(rec, -x, -y)
    cr.paint()

    svg.flush()
    svg.finish()
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="201pt" height="201pt" viewBox="0 0 201 201" version="1.1">
<defs>
<g id="surface7" clip-path="url(#clip1)">
<rect width="16777215" height="16777215" style="opacity:1;stroke:none;fill:rgb(0,0,0);"/>
<path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 0 L 100 0 L 100 100 L 0 100 Z M 0 0 " transform="matrix(1,0,0,1,-0,0)"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,100%,0%);fill-opacity:1;" d="M -10 -10 L 10 -10 L 10 10 L -10 10 Z M -10 -10 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,100%,0%);fill-opacity:1;" d="M -100 -100 L -80 -100 L -80 -80 L -100 -80 Z M -100 -100 "/>
</g>
</defs>
<g id="surface4">
<use xlink:href="#surface7" transform="matrix(1,0,0,1,100,100)"/>
</g>
</svg>
© www.soinside.com 2019 - 2024. All rights reserved.