mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-06-27 16:33:15 +03:00
Merge pull request #3693 from iwsfutcmd/text-set-language
Added ability to set language for text rendering
This commit is contained in:
commit
e2fda900cb
BIN
Tests/images/test_language.png
Normal file
BIN
Tests/images/test_language.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 777 B |
|
@ -525,6 +525,15 @@ class TestImageFont(PillowTestCase):
|
||||||
self.assertEqual(t.getsize_multiline('ABC\nA'), (36, 36))
|
self.assertEqual(t.getsize_multiline('ABC\nA'), (36, 36))
|
||||||
self.assertEqual(t.getsize_multiline('ABC\nAaaa'), (48, 36))
|
self.assertEqual(t.getsize_multiline('ABC\nAaaa'), (48, 36))
|
||||||
|
|
||||||
|
def test_complex_font_settings(self):
|
||||||
|
# Arrange
|
||||||
|
t = self.get_font()
|
||||||
|
# Act / Assert
|
||||||
|
if t.layout_engine == ImageFont.LAYOUT_BASIC:
|
||||||
|
self.assertRaises(KeyError, t.getmask, 'абвг', direction='rtl')
|
||||||
|
self.assertRaises(KeyError, t.getmask, 'абвг', features=['-kern'])
|
||||||
|
self.assertRaises(KeyError, t.getmask, 'абвг', language='sr')
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(HAS_RAQM, "Raqm not Available")
|
@unittest.skipUnless(HAS_RAQM, "Raqm not Available")
|
||||||
class TestImageFont_RaqmLayout(TestImageFont):
|
class TestImageFont_RaqmLayout(TestImageFont):
|
||||||
|
|
|
@ -130,3 +130,16 @@ class TestImagecomplextext(PillowTestCase):
|
||||||
target_img = Image.open(target)
|
target_img = Image.open(target)
|
||||||
|
|
||||||
self.assert_image_similar(im, target_img, .5)
|
self.assert_image_similar(im, target_img, .5)
|
||||||
|
|
||||||
|
def test_language(self):
|
||||||
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
|
im = Image.new(mode='RGB', size=(300, 100))
|
||||||
|
draw = ImageDraw.Draw(im)
|
||||||
|
draw.text((0, 0), 'абвг', font=ttf, fill=500,
|
||||||
|
language='sr')
|
||||||
|
|
||||||
|
target = 'Tests/images/test_language.png'
|
||||||
|
target_img = Image.open(target)
|
||||||
|
|
||||||
|
self.assert_image_similar(im, target_img, .5)
|
||||||
|
|
|
@ -255,7 +255,7 @@ Methods
|
||||||
|
|
||||||
Draw a shape.
|
Draw a shape.
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None)
|
.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None, language=None)
|
||||||
|
|
||||||
Draws the string at the given position.
|
Draws the string at the given position.
|
||||||
|
|
||||||
|
@ -287,7 +287,17 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None)
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
|
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None, language=None)
|
||||||
|
|
||||||
Draws the string at the given position.
|
Draws the string at the given position.
|
||||||
|
|
||||||
|
@ -316,7 +326,17 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None)
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
|
.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None)
|
||||||
|
|
||||||
Return the size of the given string, in pixels.
|
Return the size of the given string, in pixels.
|
||||||
|
|
||||||
|
@ -330,7 +350,6 @@ Methods
|
||||||
Requires libraqm.
|
Requires libraqm.
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
:param features: A list of OpenType font features to be used during text
|
:param features: A list of OpenType font features to be used during text
|
||||||
layout. This is usually used to turn on optional
|
layout. This is usually used to turn on optional
|
||||||
font features that are not enabled by default,
|
font features that are not enabled by default,
|
||||||
|
@ -343,8 +362,17 @@ Methods
|
||||||
Requires libraqm.
|
Requires libraqm.
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None)
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
|
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None)
|
||||||
|
|
||||||
Return the size of the given string, in pixels.
|
Return the size of the given string, in pixels.
|
||||||
|
|
||||||
|
@ -370,6 +398,16 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
.. py:method:: PIL.ImageDraw.getdraw(im=None, hints=None)
|
.. py:method:: PIL.ImageDraw.getdraw(im=None, hints=None)
|
||||||
|
|
||||||
.. warning:: This method is experimental.
|
.. warning:: This method is experimental.
|
||||||
|
|
|
@ -47,11 +47,45 @@ Functions
|
||||||
Methods
|
Methods
|
||||||
-------
|
-------
|
||||||
|
|
||||||
.. py:method:: PIL.ImageFont.ImageFont.getsize(text)
|
.. py:method:: PIL.ImageFont.ImageFont.getsize(text, direction=None, features=[], language=None)
|
||||||
|
|
||||||
|
Returns width and height (in pixels) of given text if rendered in font with
|
||||||
|
provided direction, features, and language.
|
||||||
|
|
||||||
|
:param text: Text to measure.
|
||||||
|
|
||||||
|
:param direction: Direction of the text. It can be 'rtl' (right to
|
||||||
|
left), 'ltr' (left to right) or 'ttb' (top to bottom).
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
|
:param features: A list of OpenType font features to be used during text
|
||||||
|
layout. This is usually used to turn on optional
|
||||||
|
font features that are not enabled by default,
|
||||||
|
for example 'dlig' or 'ss01', but can be also
|
||||||
|
used to turn off default font features for
|
||||||
|
example '-liga' to disable ligatures or '-kern'
|
||||||
|
to disable kerning. To get all supported
|
||||||
|
features, see
|
||||||
|
https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 6.0.0
|
||||||
|
|
||||||
:return: (width, height)
|
:return: (width, height)
|
||||||
|
|
||||||
.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='', direction=None, features=[])
|
.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='', direction=None, features=[], language=None)
|
||||||
|
|
||||||
Create a bitmap for the text.
|
Create a bitmap for the text.
|
||||||
|
|
||||||
|
@ -85,5 +119,15 @@ Methods
|
||||||
|
|
||||||
.. versionadded:: 4.2.0
|
.. versionadded:: 4.2.0
|
||||||
|
|
||||||
|
:param language: Language of the text. Different languages may use
|
||||||
|
different glyph shapes or ligatures. This parameter tells
|
||||||
|
the font which language the text is in, and to apply the
|
||||||
|
correct substitutions as appropriate, if available.
|
||||||
|
It should be a `BCP47 language code
|
||||||
|
<https://www.w3.org/International/articles/language-tags/>`
|
||||||
|
Requires libraqm.
|
||||||
|
|
||||||
|
.. versionadded:: 6.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.
|
||||||
|
|
|
@ -102,17 +102,32 @@ Use ``PIL.__version__`` instead.
|
||||||
API Additions
|
API Additions
|
||||||
=============
|
=============
|
||||||
|
|
||||||
DIB File Format
|
DIB file format
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Pillow now supports reading and writing the DIB "Device Independent Bitmap" file format.
|
Pillow now supports reading and writing the Device Independent Bitmap file format.
|
||||||
|
|
||||||
Image.quantize
|
Image.quantize
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The `dither` option is now a customisable parameter (was previously hardcoded to `1`). This parameter takes the same values used in `Image.convert`
|
The ``dither`` option is now a customisable parameter (was previously hardcoded to ``1``).
|
||||||
|
This parameter takes the same values used in ``Image.convert``.
|
||||||
|
|
||||||
PNG EXIF Data
|
New language parameter
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
These text-rendering functions now accept a ``language`` parameter to request
|
||||||
|
language-specific glyphs and ligatures from the font:
|
||||||
|
|
||||||
|
* ``ImageDraw.ImageDraw.multiline_text()``
|
||||||
|
* ``ImageDraw.ImageDraw.multiline_textsize()``
|
||||||
|
* ``ImageDraw.ImageDraw.text()``
|
||||||
|
* ``ImageDraw.ImageDraw.textsize()``
|
||||||
|
* ``ImageFont.ImageFont.getmask()``
|
||||||
|
* ``ImageFont.ImageFont.getsize_multiline()``
|
||||||
|
* ``ImageFont.ImageFont.getsize()``
|
||||||
|
|
||||||
|
PNG EXIF data
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
EXIF data can now be read from and saved to PNG images. However, unlike other image
|
EXIF data can now be read from and saved to PNG images. However, unlike other image
|
||||||
|
@ -130,4 +145,5 @@ Pillow can now read uncompressed RGB data from DDS images.
|
||||||
Reading TIFF with old-style JPEG compression
|
Reading TIFF with old-style JPEG compression
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Added support reading TIFF files with old-style JPEG compression through LibTIFF. All YCbCr TIFF images are now always read as RGB.
|
Added support reading TIFF files with old-style JPEG compression through LibTIFF. All YCbCr
|
||||||
|
TIFF images are now always read as RGB.
|
||||||
|
|
|
@ -282,13 +282,17 @@ class ImageDraw(object):
|
||||||
self.draw.draw_bitmap(xy, mask, ink)
|
self.draw.draw_bitmap(xy, mask, ink)
|
||||||
|
|
||||||
def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
|
def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
|
||||||
spacing=4, align="left", direction=None, features=None):
|
spacing=4, align="left", direction=None, features=None,
|
||||||
|
language=None):
|
||||||
widths = []
|
widths = []
|
||||||
max_width = 0
|
max_width = 0
|
||||||
lines = self._multiline_split(text)
|
lines = self._multiline_split(text)
|
||||||
line_spacing = self.textsize('A', font=font)[1] + spacing
|
line_spacing = self.textsize('A', font=font)[1] + spacing
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line_width, line_height = self.textsize(line, font)
|
line_width, line_height = self.textsize(line, font,
|
||||||
|
direction=direction,
|
||||||
|
features=features,
|
||||||
|
language=language)
|
||||||
widths.append(line_width)
|
widths.append(line_width)
|
||||||
max_width = max(max_width, line_width)
|
max_width = max(max_width, line_width)
|
||||||
left, top = xy
|
left, top = xy
|
||||||
|
@ -302,29 +306,30 @@ class ImageDraw(object):
|
||||||
else:
|
else:
|
||||||
raise ValueError('align must be "left", "center" or "right"')
|
raise ValueError('align must be "left", "center" or "right"')
|
||||||
self.text((left, top), line, fill, font, anchor,
|
self.text((left, top), line, fill, font, anchor,
|
||||||
direction=direction, features=features)
|
direction=direction, features=features, language=language)
|
||||||
top += line_spacing
|
top += line_spacing
|
||||||
left = xy[0]
|
left = xy[0]
|
||||||
|
|
||||||
def textsize(self, text, font=None, spacing=4, direction=None,
|
def textsize(self, text, font=None, spacing=4, direction=None,
|
||||||
features=None):
|
features=None, language=None):
|
||||||
"""Get the size of a given string, in pixels."""
|
"""Get the size of a given string, in pixels."""
|
||||||
if self._multiline_check(text):
|
if self._multiline_check(text):
|
||||||
return self.multiline_textsize(text, font, spacing,
|
return self.multiline_textsize(text, font, spacing,
|
||||||
direction, features)
|
direction, features, language)
|
||||||
|
|
||||||
if font is None:
|
if font is None:
|
||||||
font = self.getfont()
|
font = self.getfont()
|
||||||
return font.getsize(text, direction, features)
|
return font.getsize(text, direction, features, language)
|
||||||
|
|
||||||
def multiline_textsize(self, text, font=None, spacing=4, direction=None,
|
def multiline_textsize(self, text, font=None, spacing=4, direction=None,
|
||||||
features=None):
|
features=None, language=None):
|
||||||
max_width = 0
|
max_width = 0
|
||||||
lines = self._multiline_split(text)
|
lines = self._multiline_split(text)
|
||||||
line_spacing = self.textsize('A', font=font)[1] + spacing
|
line_spacing = self.textsize('A', font=font)[1] + spacing
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line_width, line_height = self.textsize(line, font, spacing,
|
line_width, line_height = self.textsize(line, font, spacing,
|
||||||
direction, features)
|
direction, features,
|
||||||
|
language)
|
||||||
max_width = max(max_width, line_width)
|
max_width = max(max_width, line_width)
|
||||||
return max_width, len(lines)*line_spacing - spacing
|
return max_width, len(lines)*line_spacing - spacing
|
||||||
|
|
||||||
|
|
|
@ -158,17 +158,17 @@ class FreeTypeFont(object):
|
||||||
def getmetrics(self):
|
def getmetrics(self):
|
||||||
return self.font.ascent, self.font.descent
|
return self.font.ascent, self.font.descent
|
||||||
|
|
||||||
def getsize(self, text, direction=None, features=None):
|
def getsize(self, text, direction=None, features=None, language=None):
|
||||||
size, offset = self.font.getsize(text, direction, features)
|
size, offset = self.font.getsize(text, direction, features, language)
|
||||||
return (size[0] + offset[0], size[1] + offset[1])
|
return (size[0] + offset[0], size[1] + offset[1])
|
||||||
|
|
||||||
def getsize_multiline(self, text, direction=None,
|
def getsize_multiline(self, text, direction=None, spacing=4,
|
||||||
spacing=4, features=None):
|
features=None, language=None):
|
||||||
max_width = 0
|
max_width = 0
|
||||||
lines = self._multiline_split(text)
|
lines = self._multiline_split(text)
|
||||||
line_spacing = self.getsize('A')[1] + spacing
|
line_spacing = self.getsize('A')[1] + spacing
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line_width, line_height = self.getsize(line, direction, features)
|
line_width, line_height = self.getsize(line, direction, features, language)
|
||||||
max_width = max(max_width, line_width)
|
max_width = max(max_width, line_width)
|
||||||
|
|
||||||
return max_width, len(lines)*line_spacing - spacing
|
return max_width, len(lines)*line_spacing - spacing
|
||||||
|
@ -176,15 +176,15 @@ class FreeTypeFont(object):
|
||||||
def getoffset(self, text):
|
def getoffset(self, text):
|
||||||
return self.font.getsize(text)[1]
|
return self.font.getsize(text)[1]
|
||||||
|
|
||||||
def getmask(self, text, mode="", direction=None, features=None):
|
def getmask(self, text, mode="", direction=None, features=None, language=None):
|
||||||
return self.getmask2(text, mode, direction=direction,
|
return self.getmask2(text, mode, direction=direction, features=features,
|
||||||
features=features)[0]
|
language=language)[0]
|
||||||
|
|
||||||
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None,
|
def getmask2(self, text, mode="", fill=Image.core.fill, direction=None,
|
||||||
features=None, *args, **kwargs):
|
features=None, language=None, *args, **kwargs):
|
||||||
size, offset = self.font.getsize(text, direction, features)
|
size, offset = self.font.getsize(text, direction, features, language)
|
||||||
im = fill("L", size, 0)
|
im = fill("L", size, 0)
|
||||||
self.font.render(text, im.id, mode == "1", direction, features)
|
self.font.render(text, im.id, mode == "1", direction, features, language)
|
||||||
return im, offset
|
return im, offset
|
||||||
|
|
||||||
def font_variant(self, font=None, size=None, index=None, encoding=None,
|
def font_variant(self, font=None, size=None, index=None, encoding=None,
|
||||||
|
|
|
@ -87,6 +87,10 @@ typedef bool (*t_raqm_set_text_utf8) (raqm_t *rq,
|
||||||
size_t len);
|
size_t len);
|
||||||
typedef bool (*t_raqm_set_par_direction) (raqm_t *rq,
|
typedef bool (*t_raqm_set_par_direction) (raqm_t *rq,
|
||||||
raqm_direction_t dir);
|
raqm_direction_t dir);
|
||||||
|
typedef bool (*t_raqm_set_language) (raqm_t *rq,
|
||||||
|
const char *lang,
|
||||||
|
size_t start,
|
||||||
|
size_t len);
|
||||||
typedef bool (*t_raqm_add_font_feature) (raqm_t *rq,
|
typedef bool (*t_raqm_add_font_feature) (raqm_t *rq,
|
||||||
const char *feature,
|
const char *feature,
|
||||||
int len);
|
int len);
|
||||||
|
@ -106,6 +110,7 @@ typedef struct {
|
||||||
t_raqm_set_text set_text;
|
t_raqm_set_text set_text;
|
||||||
t_raqm_set_text_utf8 set_text_utf8;
|
t_raqm_set_text_utf8 set_text_utf8;
|
||||||
t_raqm_set_par_direction set_par_direction;
|
t_raqm_set_par_direction set_par_direction;
|
||||||
|
t_raqm_set_language set_language;
|
||||||
t_raqm_add_font_feature add_font_feature;
|
t_raqm_add_font_feature add_font_feature;
|
||||||
t_raqm_set_freetype_face set_freetype_face;
|
t_raqm_set_freetype_face set_freetype_face;
|
||||||
t_raqm_layout layout;
|
t_raqm_layout layout;
|
||||||
|
@ -160,6 +165,7 @@ setraqm(void)
|
||||||
p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text");
|
p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text");
|
||||||
p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8");
|
p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8");
|
||||||
p_raqm.set_par_direction = (t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction");
|
p_raqm.set_par_direction = (t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction");
|
||||||
|
p_raqm.set_language = (t_raqm_set_language)dlsym(p_raqm.raqm, "raqm_set_language");
|
||||||
p_raqm.add_font_feature = (t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature");
|
p_raqm.add_font_feature = (t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature");
|
||||||
p_raqm.set_freetype_face = (t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face");
|
p_raqm.set_freetype_face = (t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face");
|
||||||
p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout");
|
p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout");
|
||||||
|
@ -176,6 +182,7 @@ setraqm(void)
|
||||||
p_raqm.set_text &&
|
p_raqm.set_text &&
|
||||||
p_raqm.set_text_utf8 &&
|
p_raqm.set_text_utf8 &&
|
||||||
p_raqm.set_par_direction &&
|
p_raqm.set_par_direction &&
|
||||||
|
p_raqm.set_language &&
|
||||||
p_raqm.add_font_feature &&
|
p_raqm.add_font_feature &&
|
||||||
p_raqm.set_freetype_face &&
|
p_raqm.set_freetype_face &&
|
||||||
p_raqm.layout &&
|
p_raqm.layout &&
|
||||||
|
@ -190,6 +197,7 @@ setraqm(void)
|
||||||
p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text");
|
p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text");
|
||||||
p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8");
|
p_raqm.set_text_utf8 = (t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8");
|
||||||
p_raqm.set_par_direction = (t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction");
|
p_raqm.set_par_direction = (t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction");
|
||||||
|
p_raqm.set_language = (t_raqm_set_language)GetProcAddress(p_raqm.raqm, "raqm_set_language");
|
||||||
p_raqm.add_font_feature = (t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature");
|
p_raqm.add_font_feature = (t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature");
|
||||||
p_raqm.set_freetype_face = (t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face");
|
p_raqm.set_freetype_face = (t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face");
|
||||||
p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout");
|
p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout");
|
||||||
|
@ -205,6 +213,7 @@ setraqm(void)
|
||||||
p_raqm.set_text &&
|
p_raqm.set_text &&
|
||||||
p_raqm.set_text_utf8 &&
|
p_raqm.set_text_utf8 &&
|
||||||
p_raqm.set_par_direction &&
|
p_raqm.set_par_direction &&
|
||||||
|
p_raqm.set_language &&
|
||||||
p_raqm.add_font_feature &&
|
p_raqm.add_font_feature &&
|
||||||
p_raqm.set_freetype_face &&
|
p_raqm.set_freetype_face &&
|
||||||
p_raqm.layout &&
|
p_raqm.layout &&
|
||||||
|
@ -332,8 +341,8 @@ 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,
|
text_layout_raqm(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
PyObject *features ,GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
raqm_t *rq;
|
raqm_t *rq;
|
||||||
|
@ -341,6 +350,7 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
||||||
raqm_glyph_t *glyphs = NULL;
|
raqm_glyph_t *glyphs = NULL;
|
||||||
raqm_glyph_t_01 *glyphs_01 = NULL;
|
raqm_glyph_t_01 *glyphs_01 = NULL;
|
||||||
raqm_direction_t direction;
|
raqm_direction_t direction;
|
||||||
|
size_t start = 0;
|
||||||
|
|
||||||
rq = (*p_raqm.create)();
|
rq = (*p_raqm.create)();
|
||||||
if (rq == NULL) {
|
if (rq == NULL) {
|
||||||
|
@ -360,6 +370,13 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
||||||
PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
|
PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
if (lang) {
|
||||||
|
if (!(*p_raqm.set_language)(rq, lang, start, size)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#if PY_VERSION_HEX < 0x03000000
|
#if PY_VERSION_HEX < 0x03000000
|
||||||
else if (PyString_Check(string)) {
|
else if (PyString_Check(string)) {
|
||||||
|
@ -372,6 +389,12 @@ text_layout_raqm(PyObject* string, FontObject* self, const char* dir,
|
||||||
PyErr_SetString(PyExc_ValueError, "raqm_set_text_utf8() failed");
|
PyErr_SetString(PyExc_ValueError, "raqm_set_text_utf8() failed");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
if (lang) {
|
||||||
|
if (!(*p_raqm.set_language)(rq, lang, start, size)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
|
@ -498,8 +521,8 @@ failed:
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
text_layout_fallback(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
PyObject *features ,GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask)
|
||||||
{
|
{
|
||||||
int error, load_flags;
|
int error, load_flags;
|
||||||
FT_ULong ch;
|
FT_ULong ch;
|
||||||
|
@ -509,8 +532,8 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
||||||
FT_UInt last_index = 0;
|
FT_UInt last_index = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (features != Py_None || dir != NULL) {
|
if (features != Py_None || dir != NULL || lang != NULL) {
|
||||||
PyErr_SetString(PyExc_KeyError, "setting text direction or font features is not supported without libraqm");
|
PyErr_SetString(PyExc_KeyError, "setting text direction, language or font features is not supported without libraqm");
|
||||||
}
|
}
|
||||||
#if PY_VERSION_HEX >= 0x03000000
|
#if PY_VERSION_HEX >= 0x03000000
|
||||||
if (!PyUnicode_Check(string)) {
|
if (!PyUnicode_Check(string)) {
|
||||||
|
@ -564,15 +587,15 @@ text_layout_fallback(PyObject* string, FontObject* self, const char* dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
text_layout(PyObject* string, FontObject* self, const char* dir,
|
text_layout(PyObject* string, FontObject* self, const char* dir, PyObject *features,
|
||||||
PyObject *features, GlyphInfo **glyph_info, int mask)
|
const char* lang, GlyphInfo **glyph_info, int mask)
|
||||||
{
|
{
|
||||||
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, glyph_info, mask);
|
count = text_layout_raqm(string, self, dir, features, lang, glyph_info, mask);
|
||||||
} else {
|
} else {
|
||||||
count = text_layout_fallback(string, self, dir, features, glyph_info, mask);
|
count = text_layout_fallback(string, self, dir, features, lang, glyph_info, mask);
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -584,6 +607,7 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
int xoffset, yoffset;
|
int xoffset, yoffset;
|
||||||
const char *dir = NULL;
|
const char *dir = NULL;
|
||||||
|
const char *lang = NULL;
|
||||||
size_t count;
|
size_t count;
|
||||||
GlyphInfo *glyph_info = NULL;
|
GlyphInfo *glyph_info = NULL;
|
||||||
PyObject *features = Py_None;
|
PyObject *features = Py_None;
|
||||||
|
@ -591,14 +615,14 @@ font_getsize(FontObject* self, PyObject* args)
|
||||||
/* calculate size and bearing for a given string */
|
/* calculate size and bearing for a given string */
|
||||||
|
|
||||||
PyObject* string;
|
PyObject* string;
|
||||||
if (!PyArg_ParseTuple(args, "O|zO:getsize", &string, &dir, &features))
|
if (!PyArg_ParseTuple(args, "O|zOz:getsize", &string, &dir, &features, &lang))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
face = NULL;
|
face = NULL;
|
||||||
xoffset = yoffset = 0;
|
xoffset = yoffset = 0;
|
||||||
y_max = y_min = 0;
|
y_max = y_min = 0;
|
||||||
|
|
||||||
count = text_layout(string, self, dir, features, &glyph_info, 0);
|
count = text_layout(string, self, dir, features, lang, &glyph_info, 0);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -691,16 +715,17 @@ font_render(FontObject* self, PyObject* args)
|
||||||
int temp;
|
int temp;
|
||||||
int xx, x0, x1;
|
int xx, x0, x1;
|
||||||
const char *dir = NULL;
|
const char *dir = NULL;
|
||||||
|
const char *lang = NULL;
|
||||||
size_t count;
|
size_t count;
|
||||||
GlyphInfo *glyph_info;
|
GlyphInfo *glyph_info;
|
||||||
PyObject *features = NULL;
|
PyObject *features = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features)) {
|
if (!PyArg_ParseTuple(args, "On|izOz:render", &string, &id, &mask, &dir, &features, &lang)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_info = NULL;
|
glyph_info = NULL;
|
||||||
count = text_layout(string, self, dir, features, &glyph_info, mask);
|
count = text_layout(string, self, dir, features, lang, &glyph_info, mask);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user