ManimPango 0.6.0__cp39-cp39-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,321 @@
1
+ import typing
2
+ import warnings
3
+ from xml.sax.saxutils import escape
4
+
5
+ from . import registered_fonts
6
+ from .enums import Alignment
7
+ from .utils import *
8
+
9
+ include "utils.pxi"
10
+
11
+ class TextSetting:
12
+ """Formatting for slices of a :class:`manim.mobject.svg.text_mobject.Text` object."""
13
+ def __init__(
14
+ self,
15
+ start: int,
16
+ end: int,
17
+ font: str,
18
+ slant: str,
19
+ weight: str,
20
+ line_num = -1,
21
+ color: str = None,
22
+ ):
23
+ self.start = start
24
+ self.end = end
25
+ self.font = font
26
+ self.slant = slant
27
+ self.weight = weight
28
+ self.line_num = line_num
29
+ self.color = color
30
+
31
+
32
+ def text2svg(
33
+ settings: list,
34
+ size: float,
35
+ line_spacing: float,
36
+ disable_liga: bool,
37
+ file_name: str,
38
+ START_X: int,
39
+ START_Y: int,
40
+ width: int,
41
+ height: int,
42
+ orig_text: str,
43
+ pango_width: typing.Union[int, None] = None,
44
+ ) -> str:
45
+ """Render an SVG file from a :class:`manim.mobject.svg.text_mobject.Text` object."""
46
+ cdef cairo_surface_t* surface
47
+ cdef cairo_t* cr
48
+ cdef PangoFontDescription* font_desc
49
+ cdef PangoLayout* layout
50
+ cdef double font_size_c = size
51
+ cdef cairo_status_t status
52
+ cdef int temp_width
53
+ cdef PangoFontMap* fontmap
54
+
55
+ file_name_bytes = file_name.encode("utf-8")
56
+ surface = cairo_svg_surface_create(file_name_bytes,width,height)
57
+
58
+ if surface == NULL:
59
+ raise MemoryError("Cairo.SVGSurface can't be created.")
60
+
61
+ cr = cairo_create(surface)
62
+ status = cairo_status(cr)
63
+
64
+ if cr == NULL or status == CAIRO_STATUS_NO_MEMORY:
65
+ cairo_destroy(cr)
66
+ cairo_surface_destroy(surface)
67
+ raise MemoryError("Cairo.Context can't be created.")
68
+ elif status != CAIRO_STATUS_SUCCESS:
69
+ cairo_destroy(cr)
70
+ cairo_surface_destroy(surface)
71
+ raise Exception(cairo_status_to_string(status))
72
+
73
+ cairo_move_to(cr,START_X,START_Y)
74
+ offset_x = 0
75
+ last_line_num = 0
76
+
77
+ layout = pango_cairo_create_layout(cr)
78
+ fontmap = pango_context_get_font_map (pango_layout_get_context (layout));
79
+
80
+ for font_item in registered_fonts:
81
+ if font_item.type == 'win32':
82
+ add_to_fontmap(fontmap, font_item.path)
83
+
84
+ if layout == NULL:
85
+ cairo_destroy(cr)
86
+ cairo_surface_destroy(surface)
87
+ raise MemoryError("Pango.Layout can't be created from Cairo Context.")
88
+
89
+ if pango_width is None:
90
+ pango_layout_set_width(layout, pango_units_from_double(width))
91
+ else:
92
+ pango_layout_set_width(layout, pango_units_from_double(pango_width))
93
+
94
+ for setting in settings:
95
+ family = setting.font.encode('utf-8')
96
+ style = PangoUtils.str2style(setting.slant)
97
+ weight = PangoUtils.str2weight(setting.weight)
98
+ color = setting.color
99
+ text_str = orig_text[setting.start : setting.end].replace("\n", " ")
100
+ font_desc = pango_font_description_new()
101
+ if font_desc==NULL:
102
+ cairo_destroy(cr)
103
+ cairo_surface_destroy(surface)
104
+ g_object_unref(layout)
105
+ raise MemoryError("Pango.FontDesc can't be created.")
106
+ pango_font_description_set_size(font_desc, pango_units_from_double(font_size_c))
107
+ if family:
108
+ pango_font_description_set_family(font_desc, family)
109
+ pango_font_description_set_style(font_desc, style.value)
110
+ pango_font_description_set_weight(font_desc, weight.value)
111
+ pango_layout_set_font_description(layout, font_desc)
112
+ pango_font_description_free(font_desc)
113
+ if setting.line_num != last_line_num:
114
+ offset_x = 0
115
+ last_line_num = setting.line_num
116
+ cairo_move_to(cr,START_X + offset_x,START_Y + line_spacing * setting.line_num)
117
+
118
+ pango_cairo_update_layout(cr,layout)
119
+ markup = escape(text_str)
120
+ if color:
121
+ markup = (f"<span color='{color}'>{markup}</span>")
122
+ if MarkupUtils.validate(markup):
123
+ cairo_destroy(cr)
124
+ cairo_surface_destroy(surface)
125
+ g_object_unref(layout)
126
+ raise ValueError(f"Pango cannot recognize your color '{color}' for text '{text_str}'.")
127
+ if disable_liga:
128
+ markup = f"<span font_features='liga=0,dlig=0,clig=0,hlig=0'>{markup}</span>"
129
+ pango_layout_set_markup(layout, markup.encode('utf-8'), -1)
130
+ pango_cairo_show_layout(cr, layout)
131
+ pango_layout_get_size(layout,&temp_width,NULL)
132
+ offset_x += pango_units_to_double(temp_width)
133
+
134
+ status = cairo_status(cr)
135
+
136
+ if cr == NULL or status == CAIRO_STATUS_NO_MEMORY:
137
+ cairo_destroy(cr)
138
+ cairo_surface_destroy(surface)
139
+ g_object_unref(layout)
140
+ raise MemoryError("Cairo.Context can't be created.")
141
+ elif status != CAIRO_STATUS_SUCCESS:
142
+ cairo_destroy(cr)
143
+ cairo_surface_destroy(surface)
144
+ g_object_unref(layout)
145
+ raise Exception(cairo_status_to_string(status).decode())
146
+
147
+ cairo_destroy(cr)
148
+ cairo_surface_destroy(surface)
149
+ g_object_unref(layout)
150
+ return file_name
151
+
152
+ class MarkupUtils:
153
+ @staticmethod
154
+ def validate(markup: str) -> str:
155
+ """Validates whether markup is a valid Markup
156
+ and return the error's if any.
157
+
158
+ Parameters
159
+ ==========
160
+ markup : :class:`str`
161
+ The markup which should be checked.
162
+
163
+ Returns
164
+ =======
165
+ :class:`str`
166
+ Returns empty string if markup is valid. If markup
167
+ contains error it return the error message.
168
+
169
+ """
170
+ cdef GError *err = NULL
171
+ text_bytes = markup.encode("utf-8")
172
+ res = pango_parse_markup(
173
+ text_bytes,
174
+ -1,
175
+ 0,
176
+ NULL,
177
+ NULL,
178
+ NULL,
179
+ &err
180
+ )
181
+ if res:
182
+ return ""
183
+ else:
184
+ message = <bytes>err.message
185
+ g_error_free(err)
186
+ return message.decode('utf-8')
187
+
188
+ @staticmethod
189
+ def text2svg(
190
+ text: str,
191
+ font: str | None,
192
+ slant: str,
193
+ weight: str,
194
+ size: float,
195
+ _, # for some there was a keyword here.
196
+ disable_liga: bool,
197
+ file_name: str,
198
+ START_X: int,
199
+ START_Y: int,
200
+ width: int,
201
+ height: int,
202
+ *, # keyword only arguments below
203
+ justify: bool | None = None,
204
+ indent: float | int | None = None,
205
+ line_spacing: float | None = None,
206
+ alignment: Alignment | None = None,
207
+ pango_width: int | None = None,
208
+ ) -> str:
209
+ """Render an SVG file from a :class:`manim.mobject.svg.text_mobject.MarkupText` object."""
210
+ cdef cairo_surface_t* surface
211
+ cdef cairo_t* context
212
+ cdef PangoFontDescription* font_desc
213
+ cdef PangoLayout* layout
214
+ cdef cairo_status_t status
215
+ cdef double font_size = size
216
+ cdef int temp_int # a temporary C integer for conversion
217
+ cdef PangoFontMap* fontmap
218
+
219
+ file_name_bytes = file_name.encode("utf-8")
220
+
221
+ if disable_liga:
222
+ text_bytes = f"<span font_features='liga=0,dlig=0,clig=0,hlig=0'>{text}</span>".encode("utf-8")
223
+ else:
224
+ text_bytes = text.encode("utf-8")
225
+
226
+ surface = cairo_svg_surface_create(file_name_bytes,width,height)
227
+ if surface == NULL:
228
+ raise MemoryError("Cairo.SVGSurface can't be created.")
229
+ context = cairo_create(surface)
230
+ status = cairo_status(context)
231
+ if context == NULL or status == CAIRO_STATUS_NO_MEMORY:
232
+ cairo_destroy(context)
233
+ cairo_surface_destroy(surface)
234
+ raise MemoryError("Cairo.Context can't be created.")
235
+ elif status != CAIRO_STATUS_SUCCESS:
236
+ cairo_destroy(context)
237
+ cairo_surface_destroy(surface)
238
+ raise Exception(cairo_status_to_string(status))
239
+
240
+ cairo_move_to(context,START_X,START_Y)
241
+ layout = pango_cairo_create_layout(context)
242
+ if layout == NULL:
243
+ cairo_destroy(context)
244
+ cairo_surface_destroy(surface)
245
+ raise MemoryError("Pango.Layout can't be created from Cairo Context.")
246
+
247
+ fontmap = pango_context_get_font_map (pango_layout_get_context (layout));
248
+
249
+ for font_item in registered_fonts:
250
+ if font_item.type == 'win32':
251
+ add_to_fontmap(fontmap, font_item.path)
252
+
253
+ if pango_width is None:
254
+ pango_layout_set_width(layout, pango_units_from_double(width))
255
+ else:
256
+ pango_layout_set_width(layout, pango_units_from_double(pango_width))
257
+
258
+ if justify:
259
+ pango_layout_set_justify(layout, justify)
260
+
261
+ if indent:
262
+ temp_int = pango_units_from_double(indent)
263
+ pango_layout_set_indent(layout, temp_int)
264
+
265
+ if line_spacing:
266
+ # Typical values are: 0, 1, 1.5, 2.
267
+ ret = set_line_width(layout, line_spacing)
268
+ if not ret:
269
+ # warn that line spacing don't work
270
+ # because of old Pango version they
271
+ # have
272
+ warnings.warn(
273
+ "Pango Version<1.44 found."
274
+ "Impossible to set line_spacing."
275
+ "Expect Ugly Output."
276
+ )
277
+
278
+ if alignment:
279
+ pango_layout_set_alignment(layout, alignment.value)
280
+
281
+ font_desc = pango_font_description_new()
282
+ if font_desc == NULL:
283
+ cairo_destroy(context)
284
+ cairo_surface_destroy(surface)
285
+ g_object_unref(layout)
286
+ raise MemoryError("Pango.FontDesc can't be created.")
287
+ pango_font_description_set_size(font_desc, pango_units_from_double(font_size))
288
+ if font is not None and len(font) != 0:
289
+ pango_font_description_set_family(font_desc, font.encode("utf-8"))
290
+ pango_font_description_set_style(font_desc, PangoUtils.str2style(slant).value)
291
+ pango_font_description_set_weight(font_desc, PangoUtils.str2weight(weight).value)
292
+ pango_layout_set_font_description(layout, font_desc)
293
+ pango_font_description_free(font_desc)
294
+
295
+ cairo_move_to(context,START_X,START_Y)
296
+ pango_cairo_update_layout(context,layout)
297
+ pango_layout_set_markup(layout,text_bytes,-1)
298
+ pango_cairo_show_layout(context, layout)
299
+
300
+ status = cairo_status(context)
301
+ if context == NULL or status == CAIRO_STATUS_NO_MEMORY:
302
+ cairo_destroy(context)
303
+ cairo_surface_destroy(surface)
304
+ g_object_unref(layout)
305
+ raise MemoryError("Cairo.Context can't be created.")
306
+ elif status != CAIRO_STATUS_SUCCESS:
307
+ cairo_destroy(context)
308
+ cairo_surface_destroy(surface)
309
+ g_object_unref(layout)
310
+ raise Exception(cairo_status_to_string(status).decode())
311
+
312
+ cairo_destroy(context)
313
+ cairo_surface_destroy(surface)
314
+ g_object_unref(layout)
315
+ return file_name
316
+
317
+ cpdef str pango_version():
318
+ return pango_version_string().decode('utf-8')
319
+
320
+ cpdef str cairo_version():
321
+ return cairo_version_string().decode('utf-8')
Binary file
manimpango/enums.pyx ADDED
@@ -0,0 +1,113 @@
1
+ from enum import Enum
2
+
3
+ from pango cimport *
4
+
5
+
6
+ class Style(Enum):
7
+ """
8
+ An enumeration specifying the various slant styles possible for a font.
9
+
10
+ Attributes
11
+ ----------
12
+
13
+ NORMAL :
14
+ the font is upright.
15
+
16
+ ITALIC :
17
+ the font is slanted, but in a roman style.
18
+
19
+ OBLIQUE:
20
+ the font is slanted in an italic style.
21
+ """
22
+ NORMAL = PANGO_STYLE_NORMAL
23
+ ITALIC = PANGO_STYLE_ITALIC
24
+ OBLIQUE = PANGO_STYLE_OBLIQUE
25
+
26
+ class Weight(Enum):
27
+ """
28
+ An enumeration specifying the weight (boldness) of a font.
29
+ This is a numerical value ranging from 100 to 1000, but there are some predefined values
30
+ Using numerical value other then that defined here is not supported.
31
+
32
+ Attributes
33
+ ----------
34
+
35
+ NORMAL :
36
+ the default weight (= 400)
37
+
38
+ BOLD :
39
+ the bold weight( = 700)
40
+
41
+ THIN :
42
+ the thin weight( = 100; Since: 1.24)
43
+
44
+ ULTRALIGHT :
45
+ the ultralight weight( = 200)
46
+
47
+ LIGHT :
48
+ the light weight( = 300)
49
+
50
+ BOOK :
51
+ the book weight( = 380; Since: 1.24)
52
+
53
+ MEDIUM :
54
+ the normal weight( = 500; Since: 1.24)
55
+
56
+ SEMIBOLD :
57
+ the semibold weight( = 600)
58
+
59
+ ULTRABOLD :
60
+ the ultrabold weight( = 800)
61
+
62
+ HEAVY :
63
+ the heavy weight( = 900)
64
+
65
+ ULTRAHEAVY :
66
+ the ultraheavy weight( = 1000; Since: 1.24)
67
+ """
68
+ NORMAL = PANGO_WEIGHT_NORMAL
69
+ BOLD = PANGO_WEIGHT_BOLD
70
+ THIN = PANGO_WEIGHT_THIN
71
+ ULTRALIGHT = PANGO_WEIGHT_ULTRALIGHT
72
+ LIGHT = PANGO_WEIGHT_LIGHT
73
+ BOOK = PANGO_WEIGHT_BOOK
74
+ MEDIUM = PANGO_WEIGHT_MEDIUM
75
+ SEMIBOLD = PANGO_WEIGHT_SEMIBOLD
76
+ ULTRABOLD = PANGO_WEIGHT_ULTRABOLD
77
+ HEAVY = PANGO_WEIGHT_HEAVY
78
+ ULTRAHEAVY = PANGO_WEIGHT_ULTRAHEAVY
79
+
80
+ class Variant(Enum):
81
+ """
82
+ An enumeration specifying capitalization variant of the font.
83
+
84
+ Attributes
85
+ ----------
86
+
87
+ NORMAL :
88
+ A normal font.
89
+
90
+ SMALL_CAPS :
91
+ A font with the lower case characters replaced by smaller variants
92
+ of the capital characters.
93
+ """
94
+ NORMAL = PANGO_VARIANT_NORMAL
95
+ SMALL_CAPS = PANGO_VARIANT_SMALL_CAPS
96
+
97
+ class Alignment(Enum):
98
+ """
99
+ An enumeration specifying alignment.
100
+
101
+ Attributes
102
+ ----------
103
+
104
+ NORMAL :
105
+ A normal font.
106
+
107
+ SMALL_CAPS :
108
+ A font with the lower case characters replaced by smaller variants
109
+ of the capital characters.
110
+ """
111
+ LEFT = PANGO_ALIGN_LEFT
112
+ CENTER = PANGO_ALIGN_CENTER
113
+ RIGHT = PANGO_ALIGN_RIGHT
manimpango/glib.pxd ADDED
@@ -0,0 +1,13 @@
1
+ cdef extern from "glib.h":
2
+ ctypedef void* gpointer
3
+ ctypedef int gint
4
+ ctypedef unsigned int guint
5
+ ctypedef gint gboolean
6
+ ctypedef unsigned short guint16
7
+ ctypedef char gchar
8
+ ctypedef struct GError:
9
+ gint code
10
+ gchar *message
11
+ void g_error_free (GError *error)
12
+ void g_object_unref(gpointer object)
13
+ void g_free(gpointer mem)
manimpango/pango.pxd ADDED
@@ -0,0 +1,193 @@
1
+ from cairo cimport *
2
+ from glib cimport *
3
+
4
+
5
+ cdef extern from "pango/pangocairo.h":
6
+ int PANGO_SCALE
7
+ int pango_units_from_double(double d)
8
+ double pango_units_to_double (int i)
9
+ ctypedef struct PangoLayout:
10
+ pass
11
+ ctypedef struct PangoContext:
12
+ pass
13
+ ctypedef struct PangoFontMap:
14
+ pass
15
+ ctypedef struct PangoFontDescription:
16
+ pass
17
+ ctypedef struct PangoFontFamily:
18
+ pass
19
+ ctypedef enum PangoStyle:
20
+ PANGO_STYLE_NORMAL
21
+ PANGO_STYLE_OBLIQUE
22
+ PANGO_STYLE_ITALIC
23
+ ctypedef enum PangoWeight:
24
+ PANGO_WEIGHT_THIN
25
+ PANGO_WEIGHT_ULTRALIGHT
26
+ PANGO_WEIGHT_LIGHT
27
+ PANGO_WEIGHT_BOOK
28
+ PANGO_WEIGHT_NORMAL
29
+ PANGO_WEIGHT_MEDIUM
30
+ PANGO_WEIGHT_SEMIBOLD
31
+ PANGO_WEIGHT_BOLD
32
+ PANGO_WEIGHT_ULTRABOLD
33
+ PANGO_WEIGHT_HEAVY
34
+ PANGO_WEIGHT_ULTRAHEAVY
35
+ ctypedef enum PangoVariant:
36
+ PANGO_VARIANT_NORMAL
37
+ PANGO_VARIANT_SMALL_CAPS
38
+ ctypedef enum PangoWrapMode:
39
+ PANGO_WRAP_WORD
40
+ PANGO_WRAP_CHAR
41
+ PANGO_WRAP_WORD_CHAR
42
+ ctypedef enum PangoAlignment:
43
+ PANGO_ALIGN_LEFT
44
+ PANGO_ALIGN_CENTER
45
+ PANGO_ALIGN_RIGHT
46
+ PangoLayout* pango_cairo_create_layout(cairo_t* cr)
47
+ void pango_cairo_show_layout(
48
+ cairo_t* cr,
49
+ PangoLayout* layout
50
+ )
51
+ void pango_cairo_update_layout(
52
+ cairo_t* cr,
53
+ PangoLayout* layout
54
+ )
55
+ PangoFontDescription* pango_font_description_new()
56
+ void pango_font_description_set_size(
57
+ PangoFontDescription* desc,
58
+ gint size
59
+ )
60
+ void pango_font_description_set_family(
61
+ PangoFontDescription* desc,
62
+ const char* family
63
+ )
64
+ void pango_font_description_set_style(
65
+ PangoFontDescription* desc,
66
+ PangoStyle style
67
+ )
68
+ void pango_font_description_set_weight(
69
+ PangoFontDescription* desc,
70
+ PangoWeight weight
71
+ )
72
+ void pango_font_description_set_variant(
73
+ PangoFontDescription* desc,
74
+ PangoVariant variant
75
+ )
76
+
77
+ void pango_layout_set_width(
78
+ PangoLayout* layout,
79
+ int width
80
+ )
81
+ void pango_layout_set_font_description(
82
+ PangoLayout* layout,
83
+ const PangoFontDescription* desc
84
+ )
85
+ void pango_layout_set_text(
86
+ PangoLayout* layout,
87
+ const char* text,
88
+ int length
89
+ )
90
+ void pango_layout_set_wrap(
91
+ PangoLayout *layout,
92
+ PangoWrapMode wrap
93
+ )
94
+ void pango_layout_set_markup(
95
+ PangoLayout *layout,
96
+ const char *markup,
97
+ int length
98
+ )
99
+ void pango_layout_get_size(
100
+ PangoLayout* layout,
101
+ int* width,
102
+ int* height
103
+ )
104
+ const char* pango_version_string()
105
+ void pango_font_description_free(
106
+ PangoFontDescription *desc
107
+ )
108
+ gboolean pango_parse_markup(
109
+ const char *markup_text,
110
+ int length,
111
+ unsigned int accel_marker,
112
+ void* attr_list,
113
+ void* text,
114
+ void* accel_char,
115
+ void* error
116
+ )
117
+ PangoFontMap* pango_cairo_font_map_new()
118
+ void pango_font_map_list_families(
119
+ PangoFontMap *fontmap,
120
+ PangoFontFamily ***families,
121
+ int *n_families
122
+ )
123
+ PangoFontFamily* pango_font_map_get_family(
124
+ PangoFontMap *fontmap,
125
+ const char *name
126
+ )
127
+ const char* pango_font_family_get_name(
128
+ PangoFontFamily *family
129
+ )
130
+ void pango_layout_set_justify(
131
+ PangoLayout *layout,
132
+ gboolean justify
133
+ )
134
+ void pango_layout_set_indent(
135
+ PangoLayout *layout,
136
+ int indent
137
+ )
138
+ void pango_layout_set_alignment(
139
+ PangoLayout *layout,
140
+ PangoAlignment alignment
141
+ )
142
+ PangoFontMap* pango_context_get_font_map(
143
+ PangoContext* context
144
+ )
145
+ PangoContext* pango_layout_get_context(
146
+ PangoLayout* layout
147
+ )
148
+
149
+
150
+
151
+ cdef extern from *:
152
+ """
153
+ #if _WIN32
154
+ #include <pango/pangowin32.h>
155
+ #endif
156
+ #if PANGO_VERSION_CHECK(1,44,0)
157
+ int set_line_width(PangoLayout *layout,float spacing)
158
+ {
159
+ pango_layout_set_line_spacing(layout, spacing);
160
+ return 1;
161
+ }
162
+ #else
163
+ int set_line_width(PangoLayout *layout,float spacing){return 0;}
164
+ #endif
165
+
166
+ #if _WIN32 && PANGO_VERSION_CHECK(1,52,0)
167
+ gboolean font_map_add_font_file(PangoFontMap *font_map,
168
+ const char *font_file_path,
169
+ GError **error)
170
+ {
171
+ return pango_win32_font_map_add_font_file(font_map, font_file_path, error);
172
+ }
173
+ #else
174
+ gboolean font_map_add_font_file(PangoFontMap *font_map,
175
+ const char *font_file_path,
176
+ GError **error)
177
+ {
178
+ return 1;
179
+ }
180
+ #endif
181
+
182
+ """
183
+ # The above docs string is C which is used to
184
+ # check for the Pango Version there at run time.
185
+ # pango_layout_set_line_spacing is only avaiable only for
186
+ # pango>=1.44.0 but we support pango>=1.30.0 that why this
187
+ # conditionals.
188
+ bint set_line_width(PangoLayout *layout,float spacing)
189
+
190
+ # only for windows and 1.52.0+
191
+ gboolean font_map_add_font_file(PangoFontMap *font_map,
192
+ const char *font_file_path,
193
+ GError **error)