Open georgesco94 opened 4 years ago
Hello!
CairoSVG doesn’t rely on Pycairo, it relies on CairoCFFI. So, you can quite easily access a CairoCFFI context, but it’s harder to use a Pycairo context (even if it’s possible).
There’s no "official" way to use an already opened context, but it should be possible by creating a class inheriting from Surface
and overriding the _create_surface
method.
Hope that it helps!
Overriding _create_surface
does not seem to work:
File "/home/simon/site-packages/cairosvg/surface.py", line 213, in __init__
self.context = cairo.Context(self.cairo)
File "/usr/lib/python3/dist-packages/cairocffi/context.py", line 101, in __init__
self._init_pointer(cairo.cairo_create(target._pointer))
AttributeError: 'cairo.PDFSurface' object has no attribute '_pointer'
But I did manage to hack on __init__
until I got it to work, at least for my specific requirements:
#!/usr/bin/env python3
import sys
import cairo
from cairosvg.parser import Tree
from cairosvg.surface import Surface
class MySurf(Surface):
def _create_surface(self, width, height): # FAIL
surface = cairo.PDFSurface("test_out.pdf", width, height)
return surface, width, height
def __init__(self, tree, output, dpi):
W, H = 600., 200. # point == 1/72 inch
surface = cairo.PDFSurface("test_out.pdf", W, H)
self.context = cairo.Context(surface)
self.dpi = dpi
self._old_parent_node = self.parent_node = None
self.output = output
self.font_size = None
self.context_width = W
self.context_height = H
self.cursor_position = [0, 0]
self.cursor_d_position = [0, 0]
self.text_path_width = 0
self.stroke_and_fill = True
self.tree_cache = {(tree.url, tree.get('id')): tree}
self.markers = {}
self.gradients = {}
self.patterns = {}
self.masks = {}
self.paths = {}
self.filters = {}
self.map_rgba = None
self.map_image = None
self.draw(tree)
surface.finish()
if __name__ == "__main__":
name = sys.argv[1]
s = open(name).read()
tree = Tree(bytestring=s)
my = MySurf(tree, None, 72.)
Thanks! We should have this in the documentation.
I had the same question before I saw this issue and came up with a slightly different solution:
class ContextOnlySurface(cairosvg.surface.Surface):
def __init__(self, tree, context):
self.context = context
# cache stuff
self.markers = {}
self.gradients = {}
self.patterns = {}
self.masks = {}
self.paths = {}
self.filters = {}
self.images = {}
self.tree_cache = {(tree.url, tree.get('id')): tree}
# state stuff
self.context_width, self.context_height , viewbox = node_format(self, tree) # used in `size` for % units
self.dpi = 96 # used in `size` for pt units
self.font_size = size(self, '12pt')
self.cursor_position = [0, 0]
self.cursor_d_position = [0, 0]
self.text_path_width = 0
self._old_parent_node = self.parent_node = None
self.stroke_and_fill = True
self.map_rgba = None
self.map_image = None
# self.draw(tree) # should not be done in init
tree = cairosvg.parser.Tree(file_obj=open(...))
surface = ...
context = cairocffi.Context(surface)
ContextOnlySurface(tree, context).draw(tree)
The Surface
class could (should?) be refactored to decouple the rendering to a context from the surface creation.
Hello, I am wondering if there is a way to render an svg to an already opened pyCairo
context
, as opposed to a file. I cannot seem to find anything in the documentation suggesting how to do this. I knowrsvg
does this, but am looking for an alternative. If not, is this a planned feature for the future ? Thank you for the help