Testing complex text layout.
|  | @ -203,12 +203,10 @@ class ImageDraw(object): | ||||||
|         return text.split(split_character) |         return text.split(split_character) | ||||||
| 
 | 
 | ||||||
|     def text(self, xy, text, fill=None, font=None, anchor=None, |     def text(self, xy, text, fill=None, font=None, anchor=None, | ||||||
|              *args, **kwargs, direction=None, features=None): |              direction=None, features=None, *args, **kwargs): | ||||||
| 
 |  | ||||||
|         if self._multiline_check(text): |         if self._multiline_check(text): | ||||||
|             return self.multiline_text(xy, text, fill, font, anchor, |             return self.multiline_text(xy, text, fill, font, anchor, | ||||||
|                                        *args, **kwargs, direction=direction, features=features) |                                        direction=direction, features=features, *args, **kwargs) | ||||||
| 
 |  | ||||||
|         ink, fill = self._getink(fill) |         ink, fill = self._getink(fill) | ||||||
|         if font is None: |         if font is None: | ||||||
|             font = self.getfont() |             font = self.getfont() | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ modules = { | ||||||
|     "tkinter": "PIL._tkinter_finder", |     "tkinter": "PIL._tkinter_finder", | ||||||
|     "freetype2": "PIL._imagingft", |     "freetype2": "PIL._imagingft", | ||||||
|     "littlecms2": "PIL._imagingcms", |     "littlecms2": "PIL._imagingcms", | ||||||
|  |     "raqm": "PIL._imagingft", | ||||||
|     "webp": "PIL._webp", |     "webp": "PIL._webp", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								Tests/fonts/NotoNastaliqUrdu-Regular.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_Nastalifont_text.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_arabictext_features.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_complex_unicode_text.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_direction_ltr.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_direction_rtl.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_kerning_features.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 963 B | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_ligature_features.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 605 B | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_text.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Tests/images/test_y_offset.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										136
									
								
								Tests/test_imagefontctl.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,136 @@ | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from helper import unittest, PillowTestCase | ||||||
|  | from PIL import Image | ||||||
|  | from PIL import ImageDraw | ||||||
|  | 
 | ||||||
|  | FONT_SIZE = 20 | ||||||
|  | FONT_PATH = "Tests/fonts/DejaVuSans.ttf" | ||||||
|  | 
 | ||||||
|  | try: | ||||||
|  |     from PIL import ImageFont | ||||||
|  | 
 | ||||||
|  |     # check if raqm is available | ||||||
|  |     ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  |     im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |     draw = ImageDraw.Draw(im) | ||||||
|  |     draw.text((0, 0), 'TEST', font=ttf, fill=500, direction='ltr') | ||||||
|  | 
 | ||||||
|  |     class TestImagecomplextext(PillowTestCase): | ||||||
|  | 
 | ||||||
|  |         def test_complex_text(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) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_text.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_y_offset(self): | ||||||
|  |             ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), 'هنا عمان', font=ttf, fill=500) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_y_offset.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_complex_unicode_text(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), u'مرحبا بكم', font=ttf, fill=500) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_complex_unicode_text.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_text_direction_rtl(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), 'English عربي', font=ttf, fill=500, direction='rtl') | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_direction_rtl.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_text_direction_ltr(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0),  'سلطنة عمان Oman', font=ttf, fill=500, direction='ltr') | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_direction_ltr.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_text_direction_rtl2(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), 'Oman سلطنة عمان', font=ttf, fill=500, direction='rtl') | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_direction_ltr.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_ligature_features(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), 'filling', font=ttf, fill=500, features=['-liga']) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_ligature_features.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_kerning_features(self): | ||||||
|  |             ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) | ||||||
|  | 
 | ||||||
|  |             im = Image.new(mode='RGB', size=(300, 100)) | ||||||
|  |             draw = ImageDraw.Draw(im) | ||||||
|  |             draw.text((0, 0), 'TeToAV', font=ttf, fill=500, features=['-kern']) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_kerning_features.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  |         def test_arabictext_features(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, features=['-fina','-init','-medi']) | ||||||
|  | 
 | ||||||
|  |             target = 'Tests/images/test_arabictext_features.png' | ||||||
|  |             target_img = Image.open(target) | ||||||
|  | 
 | ||||||
|  |             self.assert_image_similar(im, target_img, .5) | ||||||
|  | 
 | ||||||
|  | except (KeyError, ImportError): | ||||||
|  |     class TestImagecomplextext(PillowTestCase): | ||||||
|  |         def test_skip(self): | ||||||
|  |             self.skipTest("KeyError") | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     unittest.main() | ||||||
|  | 
 | ||||||
|  | # End of file | ||||||
							
								
								
									
										10
									
								
								_imagingft.c
									
									
									
									
									
								
							
							
						
						|  | @ -588,17 +588,21 @@ font_render(FontObject* self, PyObject* args) | ||||||
| 
 | 
 | ||||||
|     for (x = i = 0; i < count; i++) { |     for (x = i = 0; i < count; i++) { | ||||||
|         if (i == 0 && self->face->glyph->metrics.horiBearingX < 0) |         if (i == 0 && self->face->glyph->metrics.horiBearingX < 0) | ||||||
|             x = -PIXEL(self->face->glyph->metrics.horiBearingX); |             x = -self->face->glyph->metrics.horiBearingX; | ||||||
|         index = glyph_info[i].index; |         index = glyph_info[i].index; | ||||||
| 
 | 
 | ||||||
|         error = FT_Load_Glyph(self->face, index, load_flags); |         error = FT_Load_Glyph(self->face, index, load_flags); | ||||||
|         if (error) |         if (error) | ||||||
|             return geterror(error); |             return geterror(error); | ||||||
| 
 | 
 | ||||||
|  |         if (i == 0 && self->face->glyph->metrics.horiBearingX < 0) { | ||||||
|  |             x = -self->face->glyph->metrics.horiBearingX; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         glyph = self->face->glyph; |         glyph = self->face->glyph; | ||||||
| 
 | 
 | ||||||
|         source = (unsigned char*) glyph->bitmap.buffer; |         source = (unsigned char*) glyph->bitmap.buffer; | ||||||
|         xx = x + glyph->bitmap_left; |         xx = PIXEL(x) + glyph->bitmap_left; | ||||||
|         xx += PIXEL(glyph_info[i].x_offset); |         xx += PIXEL(glyph_info[i].x_offset); | ||||||
|         x0 = 0; |         x0 = 0; | ||||||
|         x1 = glyph->bitmap.width; |         x1 = glyph->bitmap.width; | ||||||
|  | @ -644,7 +648,7 @@ font_render(FontObject* self, PyObject* args) | ||||||
|                 source += glyph->bitmap.pitch; |                 source += glyph->bitmap.pitch; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         x += PIXEL(glyph_info[i].x_advance); |         x += glyph_info[i].x_advance; | ||||||
|     } |     } | ||||||
|     PyMem_Del(glyph_info); |     PyMem_Del(glyph_info); | ||||||
|     Py_RETURN_NONE; |     Py_RETURN_NONE; | ||||||
|  |  | ||||||
|  | @ -183,7 +183,8 @@ if __name__ == "__main__": | ||||||
|         ("jpg", "JPEG"), |         ("jpg", "JPEG"), | ||||||
|         ("jpg_2000", "OPENJPEG (JPEG2000)"), |         ("jpg_2000", "OPENJPEG (JPEG2000)"), | ||||||
|         ("zlib", "ZLIB (PNG/ZIP)"), |         ("zlib", "ZLIB (PNG/ZIP)"), | ||||||
|         ("libtiff", "LIBTIFF") |         ("libtiff", "LIBTIFF"), | ||||||
|  |         ("raqm", "RAQM") | ||||||
|     ]: |     ]: | ||||||
|         if features.check(name): |         if features.check(name): | ||||||
|             print("---", feature, "support ok") |             print("---", feature, "support ok") | ||||||
|  |  | ||||||