mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	add support for fonts with COLR data
This commit is contained in:
		
							parent
							
								
									877831be13
								
							
						
					
					
						commit
						82a28d12e2
					
				| 
						 | 
					@ -291,7 +291,7 @@ Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Draw a shape.
 | 
					    Draw a shape.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None)
 | 
					.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Draws the string at the given position.
 | 
					    Draws the string at the given position.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,7 +352,12 @@ Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .. versionadded:: 6.2.0
 | 
					        .. versionadded:: 6.2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None)
 | 
					    :param embedded_color: Whether to use embedded color info in COLR and CPAL tables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Draws the string at the given position.
 | 
					    Draws the string at the given position.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -399,6 +404,19 @@ Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                     .. versionadded:: 6.0.0
 | 
					                     .. versionadded:: 6.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param stroke_width: The width of the text stroke.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                     .. versionadded:: 6.2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param stroke_fill: Color to use for the text stroke. If not given, will default to
 | 
				
			||||||
 | 
					                        the ``fill`` parameter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                     .. versionadded:: 6.2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param embedded_color: Whether to use embedded color info in COLR and CPAL tables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
 | 
					.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Return the size of the given string, in pixels.
 | 
					    Return the size of the given string, in pixels.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,6 +282,7 @@ class ImageDraw:
 | 
				
			||||||
        language=None,
 | 
					        language=None,
 | 
				
			||||||
        stroke_width=0,
 | 
					        stroke_width=0,
 | 
				
			||||||
        stroke_fill=None,
 | 
					        stroke_fill=None,
 | 
				
			||||||
 | 
					        embedded_color=False,
 | 
				
			||||||
        *args,
 | 
					        *args,
 | 
				
			||||||
        **kwargs,
 | 
					        **kwargs,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
| 
						 | 
					@ -299,8 +300,12 @@ class ImageDraw:
 | 
				
			||||||
                language,
 | 
					                language,
 | 
				
			||||||
                stroke_width,
 | 
					                stroke_width,
 | 
				
			||||||
                stroke_fill,
 | 
					                stroke_fill,
 | 
				
			||||||
 | 
					                embedded_color,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if embedded_color and self.mode not in ("RGB", "RGBA"):
 | 
				
			||||||
 | 
					            raise ValueError("Embedded color supported only in RGB and RGBA modes")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if font is None:
 | 
					        if font is None:
 | 
				
			||||||
            font = self.getfont()
 | 
					            font = self.getfont()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -311,16 +316,20 @@ class ImageDraw:
 | 
				
			||||||
            return ink
 | 
					            return ink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def draw_text(ink, stroke_width=0, stroke_offset=None):
 | 
					        def draw_text(ink, stroke_width=0, stroke_offset=None):
 | 
				
			||||||
 | 
					            mode = self.fontmode
 | 
				
			||||||
 | 
					            if stroke_width == 0 and embedded_color:
 | 
				
			||||||
 | 
					                mode = "RGBA"
 | 
				
			||||||
            coord = xy
 | 
					            coord = xy
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                mask, offset = font.getmask2(
 | 
					                mask, offset = font.getmask2(
 | 
				
			||||||
                    text,
 | 
					                    text,
 | 
				
			||||||
                    self.fontmode,
 | 
					                    mode,
 | 
				
			||||||
                    direction=direction,
 | 
					                    direction=direction,
 | 
				
			||||||
                    features=features,
 | 
					                    features=features,
 | 
				
			||||||
                    language=language,
 | 
					                    language=language,
 | 
				
			||||||
                    stroke_width=stroke_width,
 | 
					                    stroke_width=stroke_width,
 | 
				
			||||||
                    anchor=anchor,
 | 
					                    anchor=anchor,
 | 
				
			||||||
 | 
					                    ink=ink,
 | 
				
			||||||
                    *args,
 | 
					                    *args,
 | 
				
			||||||
                    **kwargs,
 | 
					                    **kwargs,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
| 
						 | 
					@ -329,12 +338,13 @@ class ImageDraw:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    mask = font.getmask(
 | 
					                    mask = font.getmask(
 | 
				
			||||||
                        text,
 | 
					                        text,
 | 
				
			||||||
                        self.fontmode,
 | 
					                        mode,
 | 
				
			||||||
                        direction,
 | 
					                        direction,
 | 
				
			||||||
                        features,
 | 
					                        features,
 | 
				
			||||||
                        language,
 | 
					                        language,
 | 
				
			||||||
                        stroke_width,
 | 
					                        stroke_width,
 | 
				
			||||||
                        anchor,
 | 
					                        anchor,
 | 
				
			||||||
 | 
					                        ink,
 | 
				
			||||||
                        *args,
 | 
					                        *args,
 | 
				
			||||||
                        **kwargs,
 | 
					                        **kwargs,
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
| 
						 | 
					@ -342,7 +352,15 @@ class ImageDraw:
 | 
				
			||||||
                    mask = font.getmask(text)
 | 
					                    mask = font.getmask(text)
 | 
				
			||||||
            if stroke_offset:
 | 
					            if stroke_offset:
 | 
				
			||||||
                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
 | 
					                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
 | 
				
			||||||
            self.draw.draw_bitmap(coord, mask, ink)
 | 
					            if mode == "RGBA":
 | 
				
			||||||
 | 
					                # font.getmask2(mode="RGBA") returns color in RGB bands and mask in A
 | 
				
			||||||
 | 
					                # extract mask and set text alpha
 | 
				
			||||||
 | 
					                color, mask = mask, mask.getband(3)
 | 
				
			||||||
 | 
					                color.fillband(3, (ink >> 24) & 0xFF)
 | 
				
			||||||
 | 
					                coord2 = coord[0] + mask.size[0], coord[1] + mask.size[1]
 | 
				
			||||||
 | 
					                self.im.paste(color, coord + coord2, mask)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.draw.draw_bitmap(coord, mask, ink)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ink = getink(fill)
 | 
					        ink = getink(fill)
 | 
				
			||||||
        if ink is not None:
 | 
					        if ink is not None:
 | 
				
			||||||
| 
						 | 
					@ -374,6 +392,7 @@ class ImageDraw:
 | 
				
			||||||
        language=None,
 | 
					        language=None,
 | 
				
			||||||
        stroke_width=0,
 | 
					        stroke_width=0,
 | 
				
			||||||
        stroke_fill=None,
 | 
					        stroke_fill=None,
 | 
				
			||||||
 | 
					        embedded_color=False,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        if direction == "ttb":
 | 
					        if direction == "ttb":
 | 
				
			||||||
            raise ValueError("ttb direction is unsupported for multiline text")
 | 
					            raise ValueError("ttb direction is unsupported for multiline text")
 | 
				
			||||||
| 
						 | 
					@ -440,6 +459,7 @@ class ImageDraw:
 | 
				
			||||||
                language=language,
 | 
					                language=language,
 | 
				
			||||||
                stroke_width=stroke_width,
 | 
					                stroke_width=stroke_width,
 | 
				
			||||||
                stroke_fill=stroke_fill,
 | 
					                stroke_fill=stroke_fill,
 | 
				
			||||||
 | 
					                embedded_color=embedded_color,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            top += line_spacing
 | 
					            top += line_spacing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,7 +261,7 @@ class FreeTypeFont:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        # vertical offset is added for historical reasons
 | 
					        # vertical offset is added for historical reasons
 | 
				
			||||||
        # see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
 | 
					        # see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
 | 
				
			||||||
        size, offset = self.font.getsize(text, False, direction, features, language)
 | 
					        size, offset = self.font.getsize(text, "L", direction, features, language)
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            size[0] + stroke_width * 2,
 | 
					            size[0] + stroke_width * 2,
 | 
				
			||||||
            size[1] + stroke_width * 2 + offset[1],
 | 
					            size[1] + stroke_width * 2 + offset[1],
 | 
				
			||||||
| 
						 | 
					@ -348,12 +348,14 @@ class FreeTypeFont:
 | 
				
			||||||
        language=None,
 | 
					        language=None,
 | 
				
			||||||
        stroke_width=0,
 | 
					        stroke_width=0,
 | 
				
			||||||
        anchor=None,
 | 
					        anchor=None,
 | 
				
			||||||
 | 
					        ink=0,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create a bitmap for the text.
 | 
					        Create a bitmap for the text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        If the font uses antialiasing, the bitmap should have mode ``L`` and use a
 | 
					        If the font uses antialiasing, the bitmap should have mode ``L`` and use a
 | 
				
			||||||
        maximum value of 255. Otherwise, it should have mode ``1``.
 | 
					        maximum value of 255. If the font has embedded color data, the bitmap
 | 
				
			||||||
 | 
					        should have mode ``RGBA``. Otherwise, it should have mode ``1``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param text: Text to render.
 | 
					        :param text: Text to render.
 | 
				
			||||||
        :param mode: Used by some graphics drivers to indicate what mode the
 | 
					        :param mode: Used by some graphics drivers to indicate what mode the
 | 
				
			||||||
| 
						 | 
					@ -402,6 +404,10 @@ class FreeTypeFont:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                         .. versionadded:: 8.0.0
 | 
					                         .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param ink: Foreground ink for rendering in RGBA mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                         .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :return: An internal PIL storage memory instance as defined by the
 | 
					        :return: An internal PIL storage memory instance as defined by the
 | 
				
			||||||
                 :py:mod:`PIL.Image.core` interface module.
 | 
					                 :py:mod:`PIL.Image.core` interface module.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -413,6 +419,7 @@ class FreeTypeFont:
 | 
				
			||||||
            language=language,
 | 
					            language=language,
 | 
				
			||||||
            stroke_width=stroke_width,
 | 
					            stroke_width=stroke_width,
 | 
				
			||||||
            anchor=anchor,
 | 
					            anchor=anchor,
 | 
				
			||||||
 | 
					            ink=ink,
 | 
				
			||||||
        )[0]
 | 
					        )[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getmask2(
 | 
					    def getmask2(
 | 
				
			||||||
| 
						 | 
					@ -425,6 +432,7 @@ class FreeTypeFont:
 | 
				
			||||||
        language=None,
 | 
					        language=None,
 | 
				
			||||||
        stroke_width=0,
 | 
					        stroke_width=0,
 | 
				
			||||||
        anchor=None,
 | 
					        anchor=None,
 | 
				
			||||||
 | 
					        ink=0,
 | 
				
			||||||
        *args,
 | 
					        *args,
 | 
				
			||||||
        **kwargs,
 | 
					        **kwargs,
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
| 
						 | 
					@ -432,7 +440,8 @@ class FreeTypeFont:
 | 
				
			||||||
        Create a bitmap for the text.
 | 
					        Create a bitmap for the text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        If the font uses antialiasing, the bitmap should have mode ``L`` and use a
 | 
					        If the font uses antialiasing, the bitmap should have mode ``L`` and use a
 | 
				
			||||||
        maximum value of 255. Otherwise, it should have mode ``1``.
 | 
					        maximum value of 255. If the font has embedded color data, the bitmap
 | 
				
			||||||
 | 
					        should have mode ``RGBA``. Otherwise, it should have mode ``1``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param text: Text to render.
 | 
					        :param text: Text to render.
 | 
				
			||||||
        :param mode: Used by some graphics drivers to indicate what mode the
 | 
					        :param mode: Used by some graphics drivers to indicate what mode the
 | 
				
			||||||
| 
						 | 
					@ -481,18 +490,22 @@ class FreeTypeFont:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                         .. versionadded:: 8.0.0
 | 
					                         .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param ink: Foreground ink for rendering in RGBA mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                         .. versionadded:: 8.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :return: A tuple of an internal PIL storage memory instance as defined by the
 | 
					        :return: A tuple of an internal PIL storage memory instance as defined by the
 | 
				
			||||||
                 :py:mod:`PIL.Image.core` interface module, and the text offset, the
 | 
					                 :py:mod:`PIL.Image.core` interface module, and the text offset, the
 | 
				
			||||||
                 gap between the starting coordinate and the first marking
 | 
					                 gap between the starting coordinate and the first marking
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        size, offset = self.font.getsize(
 | 
					        size, offset = self.font.getsize(
 | 
				
			||||||
            text, mode == "1", direction, features, language, anchor
 | 
					            text, mode, direction, features, language, anchor
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
 | 
					        size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
 | 
				
			||||||
        offset = offset[0] - stroke_width, offset[1] - stroke_width
 | 
					        offset = offset[0] - stroke_width, offset[1] - stroke_width
 | 
				
			||||||
        im = fill("L", size, 0)
 | 
					        im = fill("RGBA" if mode == "RGBA" else "L", size, 0)
 | 
				
			||||||
        self.font.render(
 | 
					        self.font.render(
 | 
				
			||||||
            text, im.id, mode == "1", direction, features, language, stroke_width
 | 
					            text, im.id, mode, direction, features, language, stroke_width, ink
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return im, offset
 | 
					        return im, offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										123
									
								
								src/_imagingft.c
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								src/_imagingft.c
									
									
									
									
									
								
							| 
						 | 
					@ -28,6 +28,9 @@
 | 
				
			||||||
#include FT_STROKER_H
 | 
					#include FT_STROKER_H
 | 
				
			||||||
#include FT_MULTIPLE_MASTERS_H
 | 
					#include FT_MULTIPLE_MASTERS_H
 | 
				
			||||||
#include FT_SFNT_NAMES_H
 | 
					#include FT_SFNT_NAMES_H
 | 
				
			||||||
 | 
					#ifdef FT_COLOR_H
 | 
				
			||||||
 | 
					#include FT_COLOR_H
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define KEEP_PY_UNICODE
 | 
					#define KEEP_PY_UNICODE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,7 +353,7 @@ font_getchar(PyObject* string, int index, FT_ULong* char_out)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t
 | 
					static size_t
 | 
				
			||||||
text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
					text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
				
			||||||
                 const char* lang, GlyphInfo **glyph_info, int mask)
 | 
					                 const char* lang, GlyphInfo **glyph_info, int mask, int color)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    size_t i = 0, count = 0, start = 0;
 | 
					    size_t i = 0, count = 0, start = 0;
 | 
				
			||||||
    raqm_t *rq;
 | 
					    raqm_t *rq;
 | 
				
			||||||
| 
						 | 
					@ -529,7 +532,7 @@ failed:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t
 | 
					static size_t
 | 
				
			||||||
text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
					text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
				
			||||||
                     const char* lang, GlyphInfo **glyph_info, int mask)
 | 
					                     const char* lang, GlyphInfo **glyph_info, int mask, int color)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int error, load_flags;
 | 
					    int error, load_flags;
 | 
				
			||||||
    FT_ULong ch;
 | 
					    FT_ULong ch;
 | 
				
			||||||
| 
						 | 
					@ -565,6 +568,11 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje
 | 
				
			||||||
    if (mask) {
 | 
					    if (mask) {
 | 
				
			||||||
        load_flags |= FT_LOAD_TARGET_MONO;
 | 
					        load_flags |= FT_LOAD_TARGET_MONO;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					#ifdef FT_LOAD_COLOR
 | 
				
			||||||
 | 
					    if (color) {
 | 
				
			||||||
 | 
					        load_flags |= FT_LOAD_COLOR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    for (i = 0; font_getchar(string, i, &ch); i++) {
 | 
					    for (i = 0; font_getchar(string, i, &ch); i++) {
 | 
				
			||||||
        (*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
 | 
					        (*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch);
 | 
				
			||||||
        error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
 | 
					        error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags);
 | 
				
			||||||
| 
						 | 
					@ -595,14 +603,14 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObje
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static size_t
 | 
					static size_t
 | 
				
			||||||
text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
					text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
 | 
				
			||||||
            const char* lang, GlyphInfo **glyph_info, int mask)
 | 
					            const char* lang, GlyphInfo **glyph_info, int mask, int color)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    size_t count;
 | 
					    size_t count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
 | 
					    if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) {
 | 
				
			||||||
        count = text_layout_raqm(string, self, dir, features, lang, glyph_info,  mask);
 | 
					        count = text_layout_raqm(string, self, dir, features, lang, glyph_info,  mask, color);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask);
 | 
					        count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask, color);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return count;
 | 
					    return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -624,6 +632,8 @@ font_getsize(FontObject* self, PyObject* args)
 | 
				
			||||||
    size_t i, count; /* glyph_info index and length */
 | 
					    size_t i, count; /* glyph_info index and length */
 | 
				
			||||||
    int horizontal_dir; /* is primary axis horizontal? */
 | 
					    int horizontal_dir; /* is primary axis horizontal? */
 | 
				
			||||||
    int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
 | 
					    int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
 | 
				
			||||||
 | 
					    int color = 0; /* is FT_LOAD_COLOR enabled? */
 | 
				
			||||||
 | 
					    const char *mode = NULL;
 | 
				
			||||||
    const char *dir = NULL;
 | 
					    const char *dir = NULL;
 | 
				
			||||||
    const char *lang = NULL;
 | 
					    const char *lang = NULL;
 | 
				
			||||||
    const char *anchor = NULL;
 | 
					    const char *anchor = NULL;
 | 
				
			||||||
| 
						 | 
					@ -632,12 +642,15 @@ font_getsize(FontObject* self, PyObject* args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* calculate size and bearing for a given string */
 | 
					    /* calculate size and bearing for a given string */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "O|izOzz:getsize", &string, &mask, &dir, &features, &lang, &anchor)) {
 | 
					    if (!PyArg_ParseTuple(args, "O|zzOzz:getsize", &string, &mode, &dir, &features, &lang, &anchor)) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
					    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mask = mode && strcmp(mode, "1") == 0;
 | 
				
			||||||
 | 
					    color = mode && strcmp(mode, "RGBA") == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (anchor == NULL) {
 | 
					    if (anchor == NULL) {
 | 
				
			||||||
        anchor = horizontal_dir ? "la" : "lt";
 | 
					        anchor = horizontal_dir ? "la" : "lt";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -645,7 +658,7 @@ font_getsize(FontObject* self, PyObject* args)
 | 
				
			||||||
        goto bad_anchor;
 | 
					        goto bad_anchor;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
 | 
					    count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color);
 | 
				
			||||||
    if (PyErr_Occurred()) {
 | 
					    if (PyErr_Occurred()) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -657,6 +670,11 @@ font_getsize(FontObject* self, PyObject* args)
 | 
				
			||||||
    if (mask) {
 | 
					    if (mask) {
 | 
				
			||||||
        load_flags |= FT_LOAD_TARGET_MONO;
 | 
					        load_flags |= FT_LOAD_TARGET_MONO;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					#ifdef FT_LOAD_COLOR
 | 
				
			||||||
 | 
					    if (color) {
 | 
				
			||||||
 | 
					        load_flags |= FT_LOAD_COLOR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * text bounds are given by:
 | 
					     * text bounds are given by:
 | 
				
			||||||
| 
						 | 
					@ -834,7 +852,10 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    Py_ssize_t id;
 | 
					    Py_ssize_t id;
 | 
				
			||||||
    int horizontal_dir; /* is primary axis horizontal? */
 | 
					    int horizontal_dir; /* is primary axis horizontal? */
 | 
				
			||||||
    int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
 | 
					    int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
 | 
				
			||||||
 | 
					    int color = 0; /* is FT_LOAD_COLOR enabled? */
 | 
				
			||||||
    int stroke_width = 0;
 | 
					    int stroke_width = 0;
 | 
				
			||||||
 | 
					    PY_LONG_LONG foreground_ink = 0;
 | 
				
			||||||
 | 
					    const char *mode = NULL;
 | 
				
			||||||
    const char *dir = NULL;
 | 
					    const char *dir = NULL;
 | 
				
			||||||
    const char *lang = NULL;
 | 
					    const char *lang = NULL;
 | 
				
			||||||
    PyObject *features = Py_None;
 | 
					    PyObject *features = Py_None;
 | 
				
			||||||
| 
						 | 
					@ -843,14 +864,28 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    /* render string into given buffer (the buffer *must* have
 | 
					    /* render string into given buffer (the buffer *must* have
 | 
				
			||||||
       the right size, or this will crash) */
 | 
					       the right size, or this will crash) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "On|izOzi:render", &string,  &id, &mask, &dir, &features, &lang,
 | 
					    if (!PyArg_ParseTuple(args, "On|zzOziL:render", &string,  &id, &mode, &dir, &features, &lang,
 | 
				
			||||||
                                                   &stroke_width)) {
 | 
					                                                   &stroke_width, &foreground_ink)) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
					    horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
 | 
					    mask = mode && strcmp(mode, "1") == 0;
 | 
				
			||||||
 | 
					    color = mode && strcmp(mode, "RGBA") == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef FT_COLOR_H
 | 
				
			||||||
 | 
					    if (color) {
 | 
				
			||||||
 | 
					        FT_Color foreground_color;
 | 
				
			||||||
 | 
					        foreground_color.red = (FT_Byte) (foreground_ink);
 | 
				
			||||||
 | 
					        foreground_color.green = (FT_Byte) (foreground_ink >> 8);
 | 
				
			||||||
 | 
					        foreground_color.blue = (FT_Byte) (foreground_ink >> 16);
 | 
				
			||||||
 | 
					        foreground_color.alpha = (FT_Byte) 255; /* ink alpha is handled in ImageDraw.text */
 | 
				
			||||||
 | 
					        FT_Palette_Set_Foreground_Color(self->face, foreground_color);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color);
 | 
				
			||||||
    if (PyErr_Occurred()) {
 | 
					    if (PyErr_Occurred()) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -874,6 +909,11 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
    if (mask) {
 | 
					    if (mask) {
 | 
				
			||||||
        load_flags |= FT_LOAD_TARGET_MONO;
 | 
					        load_flags |= FT_LOAD_TARGET_MONO;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					#ifdef FT_LOAD_COLOR
 | 
				
			||||||
 | 
					    if (color) {
 | 
				
			||||||
 | 
					        load_flags |= FT_LOAD_COLOR;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * calculate x_min and y_max
 | 
					     * calculate x_min and y_max
 | 
				
			||||||
| 
						 | 
					@ -960,25 +1000,58 @@ font_render(FontObject* self, PyObject* args)
 | 
				
			||||||
            /* clip glyph bitmap height to target image bounds */
 | 
					            /* clip glyph bitmap height to target image bounds */
 | 
				
			||||||
            if (yy >= 0 && yy < im->ysize) {
 | 
					            if (yy >= 0 && yy < im->ysize) {
 | 
				
			||||||
                // blend this glyph into the buffer
 | 
					                // blend this glyph into the buffer
 | 
				
			||||||
                unsigned char *target = im->image8[yy] + xx;
 | 
					                if (color) {
 | 
				
			||||||
                if (mask) {
 | 
					                    /* target[RGB] returns the color, target[A] returns the mask */
 | 
				
			||||||
                    // use monochrome mask (on palette images, etc)
 | 
					                    /* target bands get split again in ImageDraw.text */
 | 
				
			||||||
                    int j, k, m = 128;
 | 
					                    unsigned char *target = im->image[yy] + xx * 4;
 | 
				
			||||||
                    for (j = k = 0; j < x1; j++) {
 | 
					#ifdef FT_LOAD_COLOR
 | 
				
			||||||
                        if (j >= x0 && (source[k] & m)) {
 | 
					                    if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
 | 
				
			||||||
                            target[j] = 255;
 | 
					                        // paste color glyph
 | 
				
			||||||
 | 
					                        int k;
 | 
				
			||||||
 | 
					                        for (k = x0; k < x1; k++) {
 | 
				
			||||||
 | 
					                            if (target[k * 4 + 3] < source[k * 4 + 3]) {
 | 
				
			||||||
 | 
					                                /* unpremultiply BGRa to RGBA */
 | 
				
			||||||
 | 
					                                target[k * 4 + 0] = CLIP8((255 * (int)source[k * 4 + 2]) / source[k * 4 + 3]);
 | 
				
			||||||
 | 
					                                target[k * 4 + 1] = CLIP8((255 * (int)source[k * 4 + 1]) / source[k * 4 + 3]);
 | 
				
			||||||
 | 
					                                target[k * 4 + 2] = CLIP8((255 * (int)source[k * 4 + 0]) / source[k * 4 + 3]);
 | 
				
			||||||
 | 
					                                target[k * 4 + 3] = source[k * 4 + 3];
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (!(m >>= 1)) {
 | 
					                    } else
 | 
				
			||||||
                            m = 128;
 | 
					#endif
 | 
				
			||||||
                            k++;
 | 
					                    { // pixel_mode should be FT_PIXEL_MODE_GRAY
 | 
				
			||||||
 | 
					                        // fill with ink
 | 
				
			||||||
 | 
					                        int k;
 | 
				
			||||||
 | 
					                        for (k = x0; k < x1; k++) {
 | 
				
			||||||
 | 
					                            if (target[k * 4 + 3] < source[k]) {
 | 
				
			||||||
 | 
					                                target[k * 4 + 0] = (unsigned char) (foreground_ink);
 | 
				
			||||||
 | 
					                                target[k * 4 + 1] = (unsigned char) (foreground_ink >> 8);
 | 
				
			||||||
 | 
					                                target[k * 4 + 2] = (unsigned char) (foreground_ink >> 16);
 | 
				
			||||||
 | 
					                                target[k * 4 + 3] = source[k];
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    // use antialiased rendering
 | 
					                    unsigned char *target = im->image8[yy] + xx;
 | 
				
			||||||
                    int k;
 | 
					                    if (mask) {
 | 
				
			||||||
                    for (k = x0; k < x1; k++) {
 | 
					                        // use monochrome mask (on palette images, etc)
 | 
				
			||||||
                        if (target[k] < source[k]) {
 | 
					                        int j, k, m = 128;
 | 
				
			||||||
                            target[k] = source[k];
 | 
					                        for (j = k = 0; j < x1; j++) {
 | 
				
			||||||
 | 
					                            if (j >= x0 && (source[k] & m)) {
 | 
				
			||||||
 | 
					                                target[j] = 255;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (!(m >>= 1)) {
 | 
				
			||||||
 | 
					                                m = 128;
 | 
				
			||||||
 | 
					                                k++;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        // use antialiased rendering
 | 
				
			||||||
 | 
					                        int k;
 | 
				
			||||||
 | 
					                        for (k = x0; k < x1; k++) {
 | 
				
			||||||
 | 
					                            if (target[k] < source[k]) {
 | 
				
			||||||
 | 
					                                target[k] = source[k];
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user