mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Merge pull request #789 from wiredfool/hugovk_pr_772
Merge of #772 and master
This commit is contained in:
commit
98ebc16bc0
|
@ -11,4 +11,4 @@ exclude_lines =
|
||||||
if __name__ == .__main__.:
|
if __name__ == .__main__.:
|
||||||
# Don't complain about debug code
|
# Don't complain about debug code
|
||||||
if Image.DEBUG:
|
if Image.DEBUG:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
|
|
|
@ -29,13 +29,15 @@ from __future__ import print_function
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL._util import isDirectory, isPath
|
from PIL._util import isDirectory, isPath
|
||||||
import os, sys
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import warnings
|
import warnings
|
||||||
except ImportError:
|
except ImportError:
|
||||||
warnings = None
|
warnings = None
|
||||||
|
|
||||||
|
|
||||||
class _imagingft_not_installed:
|
class _imagingft_not_installed:
|
||||||
# module placeholder
|
# module placeholder
|
||||||
def __getattr__(self, id):
|
def __getattr__(self, id):
|
||||||
|
@ -90,8 +92,8 @@ class ImageFont:
|
||||||
# read PILfont header
|
# read PILfont header
|
||||||
if file.readline() != b"PILfont\n":
|
if file.readline() != b"PILfont\n":
|
||||||
raise SyntaxError("Not a PILfont file")
|
raise SyntaxError("Not a PILfont file")
|
||||||
d = file.readline().split(b";")
|
file.readline().split(b";")
|
||||||
self.info = [] # FIXME: should be a dictionary
|
self.info = [] # FIXME: should be a dictionary
|
||||||
while True:
|
while True:
|
||||||
s = file.readline()
|
s = file.readline()
|
||||||
if not s or s == b"DATA\n":
|
if not s or s == b"DATA\n":
|
||||||
|
@ -113,6 +115,7 @@ class ImageFont:
|
||||||
self.getsize = self.font.getsize
|
self.getsize = self.font.getsize
|
||||||
self.getmask = self.font.getmask
|
self.getmask = self.font.getmask
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper for FreeType fonts. Application code should use the
|
# Wrapper for FreeType fonts. Application code should use the
|
||||||
# <b>truetype</b> factory function to create font objects.
|
# <b>truetype</b> factory function to create font objects.
|
||||||
|
@ -124,14 +127,18 @@ class FreeTypeFont:
|
||||||
# FIXME: use service provider instead
|
# FIXME: use service provider instead
|
||||||
if file:
|
if file:
|
||||||
if warnings:
|
if warnings:
|
||||||
warnings.warn('file parameter deprecated, please use font parameter instead.', DeprecationWarning)
|
warnings.warn(
|
||||||
|
'file parameter deprecated, '
|
||||||
|
'please use font parameter instead.',
|
||||||
|
DeprecationWarning)
|
||||||
font = file
|
font = file
|
||||||
|
|
||||||
if isPath(font):
|
if isPath(font):
|
||||||
self.font = core.getfont(font, size, index, encoding)
|
self.font = core.getfont(font, size, index, encoding)
|
||||||
else:
|
else:
|
||||||
self.font_bytes = font.read()
|
self.font_bytes = font.read()
|
||||||
self.font = core.getfont("", size, index, encoding, self.font_bytes)
|
self.font = core.getfont(
|
||||||
|
"", size, index, encoding, self.font_bytes)
|
||||||
|
|
||||||
def getname(self):
|
def getname(self):
|
||||||
return self.font.family, self.font.style
|
return self.font.family, self.font.style
|
||||||
|
@ -152,7 +159,7 @@ class FreeTypeFont:
|
||||||
def getmask2(self, text, mode="", fill=Image.core.fill):
|
def getmask2(self, text, mode="", fill=Image.core.fill):
|
||||||
size, offset = self.font.getsize(text)
|
size, offset = self.font.getsize(text)
|
||||||
im = fill("L", size, 0)
|
im = fill("L", size, 0)
|
||||||
self.font.render(text, im.id, mode=="1")
|
self.font.render(text, im.id, mode == "1")
|
||||||
return im, offset
|
return im, offset
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -164,12 +171,13 @@ class FreeTypeFont:
|
||||||
# be one of Image.FLIP_LEFT_RIGHT, Image.FLIP_TOP_BOTTOM,
|
# be one of Image.FLIP_LEFT_RIGHT, Image.FLIP_TOP_BOTTOM,
|
||||||
# Image.ROTATE_90, Image.ROTATE_180, or Image.ROTATE_270.
|
# Image.ROTATE_90, Image.ROTATE_180, or Image.ROTATE_270.
|
||||||
|
|
||||||
|
|
||||||
class TransposedFont:
|
class TransposedFont:
|
||||||
"Wrapper for writing rotated or mirrored text"
|
"Wrapper for writing rotated or mirrored text"
|
||||||
|
|
||||||
def __init__(self, font, orientation=None):
|
def __init__(self, font, orientation=None):
|
||||||
self.font = font
|
self.font = font
|
||||||
self.orientation = orientation # any 'transpose' argument, or None
|
self.orientation = orientation # any 'transpose' argument, or None
|
||||||
|
|
||||||
def getsize(self, text):
|
def getsize(self, text):
|
||||||
w, h = self.font.getsize(text)
|
w, h = self.font.getsize(text)
|
||||||
|
@ -222,7 +230,10 @@ def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
if warnings:
|
if warnings:
|
||||||
warnings.warn('filename parameter deprecated, please use font parameter instead.', DeprecationWarning)
|
warnings.warn(
|
||||||
|
'filename parameter deprecated, '
|
||||||
|
'please use font parameter instead.',
|
||||||
|
DeprecationWarning)
|
||||||
font = filename
|
font = filename
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -273,8 +284,8 @@ def load_default():
|
||||||
import base64
|
import base64
|
||||||
f = ImageFont()
|
f = ImageFont()
|
||||||
f._load_pilfont_data(
|
f._load_pilfont_data(
|
||||||
# courB08
|
# courB08
|
||||||
BytesIO(base64.decodestring(b'''
|
BytesIO(base64.decodestring(b'''
|
||||||
UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
@ -393,15 +404,4 @@ w7IkEbzhVQAAAABJRU5ErkJggg==
|
||||||
'''))))
|
'''))))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
# End of file
|
||||||
if __name__ == "__main__":
|
|
||||||
# create font data chunk for embedding
|
|
||||||
import base64, os, sys
|
|
||||||
font = "../Tests/images/courB08"
|
|
||||||
print(" f._load_pilfont_data(")
|
|
||||||
print(" # %s" % os.path.basename(font))
|
|
||||||
print(" BytesIO(base64.decodestring(b'''")
|
|
||||||
base64.encode(open(font + ".pil", "rb"), sys.stdout)
|
|
||||||
print("''')), Image.open(BytesIO(base64.decodestring(b'''")
|
|
||||||
base64.encode(open(font + ".pbm", "rb"), sys.stdout)
|
|
||||||
print("'''))))")
|
|
||||||
|
|
16
Scripts/createfontdatachunk.py
Normal file
16
Scripts/createfontdatachunk.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import base64
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# create font data chunk for embedding
|
||||||
|
font = "Tests/images/courB08"
|
||||||
|
print(" f._load_pilfont_data(")
|
||||||
|
print(" # %s" % os.path.basename(font))
|
||||||
|
print(" BytesIO(base64.decodestring(b'''")
|
||||||
|
base64.encode(open(font + ".pil", "rb"), sys.stdout)
|
||||||
|
print("''')), Image.open(BytesIO(base64.decodestring(b'''")
|
||||||
|
base64.encode(open(font + ".pbm", "rb"), sys.stdout)
|
||||||
|
print("'''))))")
|
||||||
|
|
||||||
|
# End of file
|
BIN
Tests/images/default_font.png
Normal file
BIN
Tests/images/default_font.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 586 B |
|
@ -5,8 +5,8 @@ from PIL import ImageDraw
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import os
|
import os
|
||||||
|
|
||||||
font_path = "Tests/fonts/FreeMono.ttf"
|
FONT_PATH = "Tests/fonts/FreeMono.ttf"
|
||||||
font_size = 20
|
FONT_SIZE = 20
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -20,17 +20,17 @@ try:
|
||||||
ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
||||||
|
|
||||||
def test_font_with_name(self):
|
def test_font_with_name(self):
|
||||||
ImageFont.truetype(font_path, font_size)
|
ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
self._render(font_path)
|
self._render(FONT_PATH)
|
||||||
self._clean()
|
self._clean()
|
||||||
|
|
||||||
def _font_as_bytes(self):
|
def _font_as_bytes(self):
|
||||||
with open(font_path, 'rb') as f:
|
with open(FONT_PATH, 'rb') as f:
|
||||||
font_bytes = BytesIO(f.read())
|
font_bytes = BytesIO(f.read())
|
||||||
return font_bytes
|
return font_bytes
|
||||||
|
|
||||||
def test_font_with_filelike(self):
|
def test_font_with_filelike(self):
|
||||||
ImageFont.truetype(self._font_as_bytes(), font_size)
|
ImageFont.truetype(self._font_as_bytes(), FONT_SIZE)
|
||||||
self._render(self._font_as_bytes())
|
self._render(self._font_as_bytes())
|
||||||
# Usage note: making two fonts from the same buffer fails.
|
# Usage note: making two fonts from the same buffer fails.
|
||||||
# shared_bytes = self._font_as_bytes()
|
# shared_bytes = self._font_as_bytes()
|
||||||
|
@ -39,18 +39,18 @@ try:
|
||||||
self._clean()
|
self._clean()
|
||||||
|
|
||||||
def test_font_with_open_file(self):
|
def test_font_with_open_file(self):
|
||||||
with open(font_path, 'rb') as f:
|
with open(FONT_PATH, 'rb') as f:
|
||||||
self._render(f)
|
self._render(f)
|
||||||
self._clean()
|
self._clean()
|
||||||
|
|
||||||
def test_font_old_parameters(self):
|
def test_font_old_parameters(self):
|
||||||
self.assert_warning(
|
self.assert_warning(
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
lambda: ImageFont.truetype(filename=font_path, size=font_size))
|
lambda: ImageFont.truetype(filename=FONT_PATH, size=FONT_SIZE))
|
||||||
|
|
||||||
def _render(self, font):
|
def _render(self, font):
|
||||||
txt = "Hello World!"
|
txt = "Hello World!"
|
||||||
ttf = ImageFont.truetype(font, font_size)
|
ttf = ImageFont.truetype(font, FONT_SIZE)
|
||||||
w, h = ttf.getsize(txt)
|
w, h = ttf.getsize(txt)
|
||||||
img = Image.new("RGB", (256, 64), "white")
|
img = Image.new("RGB", (256, 64), "white")
|
||||||
d = ImageDraw.Draw(img)
|
d = ImageDraw.Draw(img)
|
||||||
|
@ -63,8 +63,8 @@ try:
|
||||||
os.unlink('font.png')
|
os.unlink('font.png')
|
||||||
|
|
||||||
def test_render_equal(self):
|
def test_render_equal(self):
|
||||||
img_path = self._render(font_path)
|
img_path = self._render(FONT_PATH)
|
||||||
with open(font_path, 'rb') as f:
|
with open(FONT_PATH, 'rb') as f:
|
||||||
font_filelike = BytesIO(f.read())
|
font_filelike = BytesIO(f.read())
|
||||||
img_filelike = self._render(font_filelike)
|
img_filelike = self._render(font_filelike)
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ try:
|
||||||
def test_textsize_equal(self):
|
def test_textsize_equal(self):
|
||||||
im = Image.new(mode='RGB', size=(300, 100))
|
im = Image.new(mode='RGB', size=(300, 100))
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
ttf = ImageFont.truetype(font_path, font_size)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
txt = "Hello World!"
|
txt = "Hello World!"
|
||||||
size = draw.textsize(txt, ttf)
|
size = draw.textsize(txt, ttf)
|
||||||
|
@ -88,7 +88,7 @@ try:
|
||||||
def test_render_multiline(self):
|
def test_render_multiline(self):
|
||||||
im = Image.new(mode='RGB', size=(300, 100))
|
im = Image.new(mode='RGB', size=(300, 100))
|
||||||
draw = ImageDraw.Draw(im)
|
draw = ImageDraw.Draw(im)
|
||||||
ttf = ImageFont.truetype(font_path, font_size)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
line_spacing = draw.textsize('A', font=ttf)[1] + 4
|
line_spacing = draw.textsize('A', font=ttf)[1] + 4
|
||||||
lines = ['hey you', 'you are awesome', 'this looks awkward']
|
lines = ['hey you', 'you are awesome', 'this looks awkward']
|
||||||
y = 0
|
y = 0
|
||||||
|
@ -108,7 +108,7 @@ try:
|
||||||
img_grey = Image.new("L", (100, 100))
|
img_grey = Image.new("L", (100, 100))
|
||||||
draw = ImageDraw.Draw(img_grey)
|
draw = ImageDraw.Draw(img_grey)
|
||||||
word = "testing"
|
word = "testing"
|
||||||
font = ImageFont.truetype(font_path, font_size)
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
orientation = Image.ROTATE_90
|
orientation = Image.ROTATE_90
|
||||||
transposed_font = ImageFont.TransposedFont(
|
transposed_font = ImageFont.TransposedFont(
|
||||||
|
@ -130,7 +130,7 @@ try:
|
||||||
img_grey = Image.new("L", (100, 100))
|
img_grey = Image.new("L", (100, 100))
|
||||||
draw = ImageDraw.Draw(img_grey)
|
draw = ImageDraw.Draw(img_grey)
|
||||||
word = "testing"
|
word = "testing"
|
||||||
font = ImageFont.truetype(font_path, font_size)
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
orientation = None
|
orientation = None
|
||||||
transposed_font = ImageFont.TransposedFont(
|
transposed_font = ImageFont.TransposedFont(
|
||||||
|
@ -147,6 +147,52 @@ try:
|
||||||
# Check boxes a and b are same size
|
# Check boxes a and b are same size
|
||||||
self.assertEqual(box_size_a, box_size_b)
|
self.assertEqual(box_size_a, box_size_b)
|
||||||
|
|
||||||
|
def test_free_type_font_get_name(self):
|
||||||
|
# Arrange
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
name = font.getname()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(('FreeMono', 'Regular'), name)
|
||||||
|
|
||||||
|
def test_free_type_font_get_metrics(self):
|
||||||
|
# Arrange
|
||||||
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
ascent, descent = font.getmetrics()
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertIsInstance(ascent, int)
|
||||||
|
self.assertIsInstance(descent, int)
|
||||||
|
self.assertEqual((ascent, descent), (16, 4)) # too exact check?
|
||||||
|
|
||||||
|
def test_load_path_not_found(self):
|
||||||
|
# Arrange
|
||||||
|
filename = "somefilenamethatdoesntexist.ttf"
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.assertRaises(IOError, lambda: ImageFont.load_path(filename))
|
||||||
|
|
||||||
|
def test_default_font(self):
|
||||||
|
# Arrange
|
||||||
|
txt = 'This is a "better than nothing" default font.'
|
||||||
|
im = Image.new(mode='RGB', size=(300, 100))
|
||||||
|
draw = ImageDraw.Draw(im)
|
||||||
|
|
||||||
|
target = 'Tests/images/default_font.png'
|
||||||
|
target_img = Image.open(target)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
default_font = ImageFont.load_default()
|
||||||
|
draw.text((10, 10), txt, font=default_font)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assert_image_equal(im, target_img)
|
||||||
|
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
class TestImageFont(PillowTestCase):
|
class TestImageFont(PillowTestCase):
|
||||||
def test_skip(self):
|
def test_skip(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user