Skip to content

Commit

Permalink
Split Renders into two Renderer
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
naveen521kk committed Mar 29, 2021
1 parent eceecf1 commit fd956cf
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 18 deletions.
2 changes: 2 additions & 0 deletions manimpango/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class CairoException(Exception):
pass
7 changes: 7 additions & 0 deletions manimpango/layout.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cdef class LayoutRenderer:
cdef PangoLayout* layout
cdef LayoutRenderer _renderer
cpdef bint render(self)

cdef class SVGRenderer(BaseRenderer):

9 changes: 7 additions & 2 deletions manimpango/layout.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
# gets a bit easy.

cdef class Layout:

def __init__(self):
def __cinit__(self, renderer: LayoutRenderer):
# this is the place where we should initialise
# things. So, first initialse layout.
# this will create a ``LayoutRenderer`` and it
# use that everywhere.
self._renderer = LayoutRenderer
def __init__(self, renderer: LayoutRenderer):
pass
3 changes: 0 additions & 3 deletions manimpango/layout_renderer.pxd

This file was deleted.

13 changes: 0 additions & 13 deletions manimpango/layout_renderer.pyx

This file was deleted.

13 changes: 13 additions & 0 deletions manimpango/renderer.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from cairo cimport *
from glib cimport *
from pango cimport *

cdef class BaseRenderer:
cdef PangoLayout* layout
cdef cairo_surface_t* surface
cdef cairo_t* context
cpdef bint render(self)
cdef str is_context_fine(self)

cdef class SVGRenderer(BaseRenderer):
pass
106 changes: 106 additions & 0 deletions manimpango/renderer.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import typings as T
import copy
from .exception import CairoException

cdef class BaseRenderer:
# This class should contain things
# should provide API to render to an SVG
# or get the buffer.
def __init__(self):
pass
cpdef bint render(self):
pass
cdef str is_context_fine(self):
cdef cairo_status_t status
status = cairo_status(self.context)
if status == CAIRO_STATUS_NO_MEMORY:
cairo_destroy(self.context)
cairo_surface_destroy(self.surface)
g_object_unref(self.layout)
raise MemoryError("Cairo isn't finding memory")
elif status != CAIRO_STATUS_SUCCESS:
return copy.deepcopy(cairo_status_to_string(status).decode())
return ""

cdef class SVGRenderer(BaseRenderer):
def __cinit__(
self,
file_name: str,
width:int,
height:int,
move_to: T.Tuple[int,int] = (0,0)
):
cdef cairo_status_t status
surface = cairo_svg_surface_create(
file_name.encode("utf-8"),
width,
height
)
if surface == NULL:
raise MemoryError("Cairo.SVGSurface can't be created.")
context = cairo_create(surface)
status = cairo_status(context)

if context == NULL or status == CAIRO_STATUS_NO_MEMORY:
cairo_destroy(context)
cairo_surface_destroy(surface)
raise MemoryError("Cairo.Context can't be created.")
elif status != CAIRO_STATUS_SUCCESS:
cairo_destroy(context)
cairo_surface_destroy(surface)
raise Exception(cairo_status_to_string(status))

cairo_move_to(context,move_to[0],move_to[1])

# Create a Pango layout.
layout = pango_cairo_create_layout(context)
if layout==NULL:
cairo_destroy(context)
cairo_surface_destroy(surface)
raise MemoryError("Pango.Layout can't be created from Cairo Context.")

# Now set the created things as attributes.
self.surface = surface
self.context = context
self.layout = layout

def __init__(self, file_name: str, width:int, height:int, move_to: T.Tuple[int,int]):
self.file_name = file_name
self.width = width
self.height = height

def __copy__(self):
raise NotImplementedError

def __deepcopy__(self):
raise NotImplementedError

cpdef bint render(self):
cdef cairo_t* context
cdef cairo_surface_t* surface
cdef PangoLayout* layout
# check whether cairo is happy till now
# else error out or it may create SegFaults.
status = self.is_context_fine()
if status:
raise CairoException(status)
context = self.context
surface = self.surface
layout = self.layout
pango_cairo_show_layout(context, layout)

# check for status again
status = self.is_context_fine()
if status:
raise CairoException(status)

# should I clean it up here?
# In that case calling this function
# will result in SegFaults.
# I think calling this function again
# is waste.
def __dealloc__(self):
cairo_destroy(self.context)
cairo_surface_destroy(self.surface)
g_object_unref(self.layout)

5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ def update_dict(dict1: dict, dict2: dict):
[str(base_file / ("colours" + ext))],
**returns,
),
Extension(
"manimpango.renderer",
[str(base_file / ("renderer" + ext))],
**returns,
),
]
if USE_CYTHON:
ext_modules = cythonize(
Expand Down

0 comments on commit fd956cf

Please sign in to comment.