pygobject / pycairo

Python bindings for cairo
https://pycairo.readthedocs.io
Other
620 stars 85 forks source link

Use vector graphics as patterns in SVG. #328

Closed 10maurycy10 closed 1 year ago

10maurycy10 commented 1 year ago

Currently creating a SurfacePattern from an SVGSurface and using it to draw to another SVGSurface rendered to a SVG file results in a rasterized version of the pattern, however SVG supports vector fill patterns.

Is this a bug or am I doing something wrong?

stuaxo commented 1 year ago

Can you post some minimal example code ?

It sounds like it may be a Cairo issue, but let's have a look at some code first.

10maurycy10 commented 1 year ago
import cairo

# Create a simple pattern cosisting of a horsisontal line
pattern_surface = cairo.SVGSurface(None, 16, 16)
pattern_context = cairo.Context(pattern_surface)

pattern_context.line_to(0, 0)
pattern_context.line_to(16, 16)
pattern_context.stroke()

# Paint a surface with the pattern
pattern = cairo.SurfacePattern(pattern_surface)

surface = cairo.SVGSurface("test.svg", 16, 16)
context = cairo.Context(surface)

context.set_source(pattern)
context.paint()

I would expect this to create a svg file cotaining a pattern with a vector stroke, but instead it embeds an image as a base64 encoded data url.

stuaxo commented 1 year ago

This looks similar to something I saw with recording surfaces a long time ago, but I didn't have as clean an example.

I ported the code to C, and am able to reproduce it in Cairo itself, so I opened a bug there https://gitlab.freedesktop.org/cairo/cairo/-/issues/790

I'd add yourself to that the bug there.

psychon commented 1 year ago

Thanks for the nice reproder and the port to C.

Quick question: Is there some reason why you use an SVG surface for the intermediate surface? Using a recording surface produces the expected output, I guess (not a base64-encoded PNG, but a path that is being <use>d).

I am no SVG expert, but from a quick look at the cairo source code, SVG surfaces have an in-memory representation that do not make it easy to replay them to another SVG surface (e.g. ID collisions could occur... but I am just guessing here). However, recording surfaces are explicitly meant to be replayed to another surface.

10maurycy10 commented 1 year ago

I guess I will just use a RecodingSurface instead for my code, thanks.

stuaxo commented 1 year ago

Closing here as it seems to be resolved, not sure what the upstream resolution will be but I'll keep an eye on it.