Skip to content

Commit fd956cf

Browse files
committed
Split Renders into two Renderer
Implement SVGRenderer for rendering in an SVG file Catch error from Cairo and raise CairoException when that happens. Layout will require a Renderer when intialising. Signed-off-by: Naveen M K <[email protected]>
1 parent eceecf1 commit fd956cf

8 files changed

+140
-18
lines changed

manimpango/exceptions.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class CairoException(Exception):
2+
pass

manimpango/layout.pxd

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
cdef class LayoutRenderer:
2+
cdef PangoLayout* layout
3+
cdef LayoutRenderer _renderer
4+
cpdef bint render(self)
5+
6+
cdef class SVGRenderer(BaseRenderer):
7+

manimpango/layout.pyx

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
# gets a bit easy.
88

99
cdef class Layout:
10-
11-
def __init__(self):
10+
def __cinit__(self, renderer: LayoutRenderer):
11+
# this is the place where we should initialise
12+
# things. So, first initialse layout.
13+
# this will create a ``LayoutRenderer`` and it
14+
# use that everywhere.
15+
self._renderer = LayoutRenderer
16+
def __init__(self, renderer: LayoutRenderer):
1217
pass

manimpango/layout_renderer.pxd

-3
This file was deleted.

manimpango/layout_renderer.pyx

-13
This file was deleted.

manimpango/renderer.pxd

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from cairo cimport *
2+
from glib cimport *
3+
from pango cimport *
4+
5+
cdef class BaseRenderer:
6+
cdef PangoLayout* layout
7+
cdef cairo_surface_t* surface
8+
cdef cairo_t* context
9+
cpdef bint render(self)
10+
cdef str is_context_fine(self)
11+
12+
cdef class SVGRenderer(BaseRenderer):
13+
pass

manimpango/renderer.pyx

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import typings as T
2+
import copy
3+
from .exception import CairoException
4+
5+
cdef class BaseRenderer:
6+
# This class should contain things
7+
# should provide API to render to an SVG
8+
# or get the buffer.
9+
def __init__(self):
10+
pass
11+
cpdef bint render(self):
12+
pass
13+
cdef str is_context_fine(self):
14+
cdef cairo_status_t status
15+
status = cairo_status(self.context)
16+
if status == CAIRO_STATUS_NO_MEMORY:
17+
cairo_destroy(self.context)
18+
cairo_surface_destroy(self.surface)
19+
g_object_unref(self.layout)
20+
raise MemoryError("Cairo isn't finding memory")
21+
elif status != CAIRO_STATUS_SUCCESS:
22+
return copy.deepcopy(cairo_status_to_string(status).decode())
23+
return ""
24+
25+
cdef class SVGRenderer(BaseRenderer):
26+
def __cinit__(
27+
self,
28+
file_name: str,
29+
width:int,
30+
height:int,
31+
move_to: T.Tuple[int,int] = (0,0)
32+
):
33+
cdef cairo_status_t status
34+
surface = cairo_svg_surface_create(
35+
file_name.encode("utf-8"),
36+
width,
37+
height
38+
)
39+
if surface == NULL:
40+
raise MemoryError("Cairo.SVGSurface can't be created.")
41+
context = cairo_create(surface)
42+
status = cairo_status(context)
43+
44+
if context == NULL or status == CAIRO_STATUS_NO_MEMORY:
45+
cairo_destroy(context)
46+
cairo_surface_destroy(surface)
47+
raise MemoryError("Cairo.Context can't be created.")
48+
elif status != CAIRO_STATUS_SUCCESS:
49+
cairo_destroy(context)
50+
cairo_surface_destroy(surface)
51+
raise Exception(cairo_status_to_string(status))
52+
53+
cairo_move_to(context,move_to[0],move_to[1])
54+
55+
# Create a Pango layout.
56+
layout = pango_cairo_create_layout(context)
57+
if layout==NULL:
58+
cairo_destroy(context)
59+
cairo_surface_destroy(surface)
60+
raise MemoryError("Pango.Layout can't be created from Cairo Context.")
61+
62+
# Now set the created things as attributes.
63+
self.surface = surface
64+
self.context = context
65+
self.layout = layout
66+
67+
def __init__(self, file_name: str, width:int, height:int, move_to: T.Tuple[int,int]):
68+
self.file_name = file_name
69+
self.width = width
70+
self.height = height
71+
72+
def __copy__(self):
73+
raise NotImplementedError
74+
75+
def __deepcopy__(self):
76+
raise NotImplementedError
77+
78+
cpdef bint render(self):
79+
cdef cairo_t* context
80+
cdef cairo_surface_t* surface
81+
cdef PangoLayout* layout
82+
# check whether cairo is happy till now
83+
# else error out or it may create SegFaults.
84+
status = self.is_context_fine()
85+
if status:
86+
raise CairoException(status)
87+
context = self.context
88+
surface = self.surface
89+
layout = self.layout
90+
pango_cairo_show_layout(context, layout)
91+
92+
# check for status again
93+
status = self.is_context_fine()
94+
if status:
95+
raise CairoException(status)
96+
97+
# should I clean it up here?
98+
# In that case calling this function
99+
# will result in SegFaults.
100+
# I think calling this function again
101+
# is waste.
102+
def __dealloc__(self):
103+
cairo_destroy(self.context)
104+
cairo_surface_destroy(self.surface)
105+
g_object_unref(self.layout)
106+

setup.py

+5
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ def update_dict(dict1: dict, dict2: dict):
232232
[str(base_file / ("colours" + ext))],
233233
**returns,
234234
),
235+
Extension(
236+
"manimpango.renderer",
237+
[str(base_file / ("renderer" + ext))],
238+
**returns,
239+
),
235240
]
236241
if USE_CYTHON:
237242
ext_modules = cythonize(

0 commit comments

Comments
 (0)