Merge pull request #789 from wiredfool/hugovk_pr_772

Merge of #772 and master
This commit is contained in:
wiredfool 2014-07-08 10:53:24 -07:00
commit 98ebc16bc0
5 changed files with 100 additions and 38 deletions

View File

@ -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:

View File

@ -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("'''))))")

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

View File

@ -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):