mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 18:56:17 +03:00
Merge pull request #209 from wiredfool/pr202
Fonts from Filelike Objects
This commit is contained in:
commit
44d97759af
|
@ -30,6 +30,11 @@ from __future__ import print_function
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os, sys
|
import os, sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import warnings
|
||||||
|
except ImportError:
|
||||||
|
warnings = None
|
||||||
|
|
||||||
class _imagingft_not_installed:
|
class _imagingft_not_installed:
|
||||||
# module placeholder
|
# module placeholder
|
||||||
def __getattr__(self, id):
|
def __getattr__(self, id):
|
||||||
|
@ -40,6 +45,13 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
core = _imagingft_not_installed()
|
core = _imagingft_not_installed()
|
||||||
|
|
||||||
|
if bytes is str:
|
||||||
|
def isStringType(t):
|
||||||
|
return isinstance(t, basestring)
|
||||||
|
else:
|
||||||
|
def isStringType(t):
|
||||||
|
return isinstance(t, str)
|
||||||
|
|
||||||
# FIXME: add support for pilfont2 format (see FontFile.py)
|
# FIXME: add support for pilfont2 format (see FontFile.py)
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
@ -129,9 +141,18 @@ class ImageFont:
|
||||||
class FreeTypeFont:
|
class FreeTypeFont:
|
||||||
"FreeType font wrapper (requires _imagingft service)"
|
"FreeType font wrapper (requires _imagingft service)"
|
||||||
|
|
||||||
def __init__(self, file, size, index=0, encoding=""):
|
def __init__(self, font=None, size=10, index=0, encoding="", file=None):
|
||||||
# FIXME: use service provider instead
|
# FIXME: use service provider instead
|
||||||
self.font = core.getfont(file, size, index, encoding)
|
if file:
|
||||||
|
if warnings:
|
||||||
|
warnings.warn('file parameter deprecated, please use font parameter instead.', DeprecationWarning)
|
||||||
|
font = file
|
||||||
|
|
||||||
|
if isStringType(font):
|
||||||
|
self.font = core.getfont(font, size, index, encoding)
|
||||||
|
else:
|
||||||
|
self.font_bytes = font.read()
|
||||||
|
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
|
||||||
|
@ -212,10 +233,16 @@ def load(filename):
|
||||||
# @return A font object.
|
# @return A font object.
|
||||||
# @exception IOError If the file could not be read.
|
# @exception IOError If the file could not be read.
|
||||||
|
|
||||||
def truetype(filename, size, index=0, encoding=""):
|
def truetype(font=None, size=10, index=0, encoding="", filename=None):
|
||||||
"Load a truetype font file."
|
"Load a truetype font file."
|
||||||
|
|
||||||
|
if filename:
|
||||||
|
if warnings:
|
||||||
|
warnings.warn('filename parameter deprecated, please use font parameter instead.', DeprecationWarning)
|
||||||
|
font = filename
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return FreeTypeFont(filename, size, index, encoding)
|
return FreeTypeFont(font, size, index, encoding)
|
||||||
except IOError:
|
except IOError:
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
# check the windows font repository
|
# check the windows font repository
|
||||||
|
@ -223,8 +250,8 @@ def truetype(filename, size, index=0, encoding=""):
|
||||||
# 1.5.2's os.environ.get()
|
# 1.5.2's os.environ.get()
|
||||||
windir = os.environ.get("WINDIR")
|
windir = os.environ.get("WINDIR")
|
||||||
if windir:
|
if windir:
|
||||||
filename = os.path.join(windir, "fonts", filename)
|
filename = os.path.join(windir, "fonts", font)
|
||||||
return FreeTypeFont(filename, size, index, encoding)
|
return FreeTypeFont(font, size, index, encoding)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
BIN
Tests/fonts/FreeMono.ttf
Normal file
BIN
Tests/fonts/FreeMono.ttf
Normal file
Binary file not shown.
|
@ -1,12 +1,61 @@
|
||||||
from tester import *
|
from tester import *
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import ImageFont
|
from PIL import ImageFont
|
||||||
ImageFont.core.getfont # check if freetype is available
|
ImageFont.core.getfont # check if freetype is available
|
||||||
except ImportError:
|
except ImportError:
|
||||||
skip()
|
skip()
|
||||||
|
|
||||||
def test_sanity():
|
from PIL import ImageDraw
|
||||||
|
|
||||||
|
font_path = "Tests/fonts/FreeMono.ttf"
|
||||||
|
font_size=20
|
||||||
|
|
||||||
|
def test_sanity():
|
||||||
assert_match(ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
assert_match(ImageFont.core.freetype2_version, "\d+\.\d+\.\d+$")
|
||||||
|
|
||||||
|
def test_font_with_name():
|
||||||
|
assert_no_exception(lambda: ImageFont.truetype(font_path, font_size))
|
||||||
|
assert_no_exception(lambda: _render(font_path))
|
||||||
|
|
||||||
|
def _font_as_bytes():
|
||||||
|
with open(font_path, 'rb') as f:
|
||||||
|
font_bytes = BytesIO(f.read())
|
||||||
|
return font_bytes
|
||||||
|
|
||||||
|
def test_font_with_filelike():
|
||||||
|
assert_no_exception(lambda: ImageFont.truetype(_font_as_bytes(), font_size))
|
||||||
|
assert_no_exception(lambda: _render(_font_as_bytes()))
|
||||||
|
# Usage note: making two fonts from the same buffer fails.
|
||||||
|
#shared_bytes = _font_as_bytes()
|
||||||
|
#assert_no_exception(lambda: _render(shared_bytes))
|
||||||
|
#assert_exception(Exception, lambda: _render(shared_bytes))
|
||||||
|
|
||||||
|
def test_font_with_open_file():
|
||||||
|
with open(font_path, 'rb') as f:
|
||||||
|
assert_no_exception(lambda: _render(f))
|
||||||
|
|
||||||
|
def test_font_old_parameters():
|
||||||
|
assert_warning(DeprecationWarning, lambda: ImageFont.truetype(filename=font_path, size=font_size))
|
||||||
|
|
||||||
|
def _render(font):
|
||||||
|
txt = "Hello World!"
|
||||||
|
ttf = ImageFont.truetype(font, font_size)
|
||||||
|
w, h = ttf.getsize(txt)
|
||||||
|
img = Image.new("RGB", (256, 64), "white")
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
d.text((10, 10), txt, font=ttf, fill='black')
|
||||||
|
|
||||||
|
img.save('font.png')
|
||||||
|
return img
|
||||||
|
|
||||||
|
def test_render_equal():
|
||||||
|
img_path = _render(font_path)
|
||||||
|
with open(font_path, 'rb') as f:
|
||||||
|
font_filelike = BytesIO(f.read())
|
||||||
|
img_filelike = _render(font_filelike)
|
||||||
|
|
||||||
|
assert_image_equal(img_path, img_filelike)
|
||||||
|
|
21
_imagingft.c
21
_imagingft.c
|
@ -99,17 +99,20 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
FontObject* self;
|
FontObject* self;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
char* filename;
|
char* filename = NULL;
|
||||||
int size;
|
int size;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
unsigned char* encoding = NULL;
|
unsigned char* encoding;
|
||||||
|
unsigned char* font_bytes;
|
||||||
|
int font_bytes_size = 0;
|
||||||
static char* kwlist[] = {
|
static char* kwlist[] = {
|
||||||
"filename", "size", "index", "encoding", NULL
|
"filename", "size", "index", "encoding", "font_bytes", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|is", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#", kwlist,
|
||||||
Py_FileSystemDefaultEncoding, &filename,
|
Py_FileSystemDefaultEncoding, &filename,
|
||||||
&size, &index, &encoding))
|
&size, &index, &encoding, &font_bytes,
|
||||||
|
&font_bytes_size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!library) {
|
if (!library) {
|
||||||
|
@ -124,8 +127,12 @@ getfont(PyObject* self_, PyObject* args, PyObject* kw)
|
||||||
if (!self)
|
if (!self)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
error = FT_New_Face(library, filename, index, &self->face);
|
if (filename && font_bytes_size <= 0) {
|
||||||
|
error = FT_New_Face(library, filename, index, &self->face);
|
||||||
|
} else {
|
||||||
|
error = FT_New_Memory_Face(library, (FT_Byte*)font_bytes, font_bytes_size, index, &self->face);
|
||||||
|
}
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
error = FT_Set_Pixel_Sizes(self->face, 0, size);
|
error = FT_Set_Pixel_Sizes(self->face, 0, size);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user