|
| 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 | + |
0 commit comments