Skip to content

Commit 8cad163

Browse files
committed
New FreeType wrapper.
TODO: ttc support violates the assumption that the filename suffices to identify the face (when caching). We need to generate a uniquer id or just key off the face object. [ci skip]
1 parent f3760b2 commit 8cad163

20 files changed

+1276
-454
lines changed

examples/misc/font_indexing.py

+7-11
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99
"""
1010
from __future__ import print_function
1111
import matplotlib
12-
from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, KERNING_UNFITTED, KERNING_UNSCALED
12+
from matplotlib import _ft2
1313

1414

15-
#fname = '/usr/share/fonts/sfd/FreeSans.ttf'
1615
fname = matplotlib.get_data_path() + '/fonts/ttf/DejaVuSans.ttf'
17-
font = FT2Font(fname)
18-
font.set_charmap(0)
16+
font = _ft2.Face(fname)
17+
font.set_charmap(0) # FIXME
1918

2019
codes = font.get_charmap().items()
2120
#dsu = [(ccode, glyphind) for ccode, glyphind in codes]
@@ -34,11 +33,8 @@
3433
coded[name] = ccode
3534
glyphd[name] = glyphind
3635

37-
code = coded['A']
38-
glyph = font.load_char(code)
39-
#print(glyph.bbox)
4036
print(glyphd['A'], glyphd['V'], coded['A'], coded['V'])
41-
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], KERNING_DEFAULT))
42-
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], KERNING_UNFITTED))
43-
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], KERNING_UNSCALED))
44-
print('AV', font.get_kerning(glyphd['A'], glyphd['T'], KERNING_UNSCALED))
37+
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], _ft2.Kerning.DEFAULT))
38+
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], _ft2.Kerning.UNFITTED))
39+
print('AV', font.get_kerning(glyphd['A'], glyphd['V'], _ft2.Kerning.UNSCALED))
40+
print('AV', font.get_kerning(glyphd['A'], glyphd['T'], _ft2.Kerning.UNSCALED))

examples/misc/ftface_props.py

+50-64
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,54 @@
11
"""
2-
============
3-
Ftface Props
4-
============
5-
6-
This is a demo script to show you how to use all the properties of an
7-
FT2Font object. These describe global font properties. For
8-
individual character metrics, use the Glyph object, as returned by
9-
load_char
2+
===============
3+
Face properties
4+
===============
5+
6+
This is a demo script to show you how to use all the properties of a Face
7+
object. These describe global font properties. For individual character
8+
metrics, use the Glyph object, as loaded from the glyph attribute after calling
9+
load_char.
1010
"""
1111
from __future__ import print_function
1212
import matplotlib
13-
import matplotlib.ft2font as ft
14-
15-
16-
#fname = '/usr/local/share/matplotlib/VeraIt.ttf'
17-
fname = matplotlib.get_data_path() + '/fonts/ttf/DejaVuSans-Oblique.ttf'
18-
#fname = '/usr/local/share/matplotlib/cmr10.ttf'
19-
20-
font = ft.FT2Font(fname)
21-
22-
print('Num faces :', font.num_faces) # number of faces in file
23-
print('Num glyphs :', font.num_glyphs) # number of glyphs in the face
24-
print('Family name :', font.family_name) # face family name
25-
print('Style name :', font.style_name) # face style name
26-
print('PS name :', font.postscript_name) # the postscript name
27-
print('Num fixed :', font.num_fixed_sizes) # number of embedded bitmap in face
28-
29-
# the following are only available if face.scalable
30-
if font.scalable:
31-
# the face global bounding box (xmin, ymin, xmax, ymax)
32-
print('Bbox :', font.bbox)
33-
# number of font units covered by the EM
34-
print('EM :', font.units_per_EM)
35-
# the ascender in 26.6 units
36-
print('Ascender :', font.ascender)
37-
# the descender in 26.6 units
38-
print('Descender :', font.descender)
39-
# the height in 26.6 units
40-
print('Height :', font.height)
41-
# maximum horizontal cursor advance
42-
print('Max adv width :', font.max_advance_width)
43-
# same for vertical layout
44-
print('Max adv height :', font.max_advance_height)
45-
# vertical position of the underline bar
46-
print('Underline pos :', font.underline_position)
47-
# vertical thickness of the underline
48-
print('Underline thickness :', font.underline_thickness)
49-
50-
for style in ('Italic',
51-
'Bold',
52-
'Scalable',
53-
'Fixed sizes',
54-
'Fixed width',
55-
'SFNT',
56-
'Horizontal',
57-
'Vertical',
58-
'Kerning',
59-
'Fast glyphs',
60-
'Multiple masters',
61-
'Glyph names',
62-
'External stream'):
63-
bitpos = getattr(ft, style.replace(' ', '_').upper()) - 1
64-
print('%-17s:' % style, bool(font.style_flags & (1 << bitpos)))
65-
66-
print(dir(font))
67-
68-
print(font.get_kerning)
13+
from matplotlib import font_manager, _ft2
14+
15+
16+
fname = matplotlib.get_data_path() + "/fonts/ttf/DejaVuSans-Oblique.ttf"
17+
font = font_manager.get_font(fname)
18+
19+
print("Faces in file :", font.num_faces)
20+
print("Glyphs in face :", font.num_glyphs)
21+
print("Family name :", font.family_name)
22+
print("Style name :", font.style_name)
23+
print("Postscript name :", font.get_postscript_name())
24+
print("Embedded bitmap strikes:", font.num_fixed_sizes)
25+
26+
if font.face_flags & _ft2.FACE_FLAG_SCALABLE:
27+
print('Global bbox (xmin, ymin, xmax, ymax):', font.bbox)
28+
print('Font units per EM :', font.units_per_EM)
29+
print('Ascender (pixels) :', font.ascender)
30+
print('Descender (pixels) :', font.descender)
31+
print('Height (pixels) :', font.height)
32+
print('Max horizontal advance :', font.max_advance_width)
33+
print('Max vertical advance :', font.max_advance_height)
34+
print('Underline position :', font.underline_position)
35+
print('Underline thickness :', font.underline_thickness)
36+
37+
for style in ['Style flag italic',
38+
'Style flag bold']:
39+
flag = getattr(_ft2, style.replace(' ', '_').upper()) - 1
40+
print('%-26s:' % style, bool(font.style_flags & flag))
41+
42+
for style in ['Face flag scalable',
43+
'Face flag fixed sizes',
44+
'Face flag fixed width',
45+
'Face flag SFNT',
46+
'Face flag horizontal',
47+
'Face flag vertical',
48+
'Face flag kerning',
49+
'Face flag fast glyphs',
50+
'Face flag multiple masters',
51+
'Face flag glyph names',
52+
'Face flag external stream']:
53+
flag = getattr(_ft2, style.replace(' ', '_').upper())
54+
print('%-26s:' % style, bool(font.face_flags & flag))

examples/text_labels_and_annotations/font_table_ttf_sgskip.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import os
1616

1717
import matplotlib
18-
from matplotlib.ft2font import FT2Font
18+
from matplotlib import _ft2
1919
from matplotlib.font_manager import FontProperties
2020
import matplotlib.pyplot as plt
2121

@@ -35,8 +35,8 @@
3535
fontname = os.path.join(matplotlib.get_data_path(),
3636
'fonts', 'ttf', 'DejaVuSans.ttf')
3737

38-
font = FT2Font(fontname)
39-
codes = sorted(font.get_charmap().items())
38+
font = _ft2.Face(fontname)
39+
codes = sorted(font.get_charmap().items()) # FIXME
4040

4141
# a 16,16 array of character strings
4242
chars = [['' for c in range(16)] for r in range(16)]

lib/matplotlib/backends/backend_agg.py

+25-44
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* alpha blending
1313
* DPI scaling properly - everything scales properly (dashes, linewidths, etc)
1414
* draw polygon
15-
* freetype2 w/ ft2font
15+
* freetype2
1616
1717
TODO:
1818
@@ -28,19 +28,15 @@
2828
import numpy as np
2929
from collections import OrderedDict
3030
from math import radians, cos, sin
31-
from matplotlib import cbook, rcParams, __version__
31+
32+
from matplotlib import (
33+
_ft2, _png, cbook, colors as mcolors, font_manager, rcParams, __version__)
3234
from matplotlib.backend_bases import (
3335
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors)
34-
from matplotlib.font_manager import findfont, get_font
35-
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
36-
LOAD_DEFAULT, LOAD_NO_AUTOHINT)
36+
from matplotlib.backends._backend_agg import RendererAgg as _RendererAgg
3737
from matplotlib.mathtext import MathTextParser
3838
from matplotlib.path import Path
3939
from matplotlib.transforms import Bbox, BboxBase
40-
from matplotlib import colors as mcolors
41-
42-
from matplotlib.backends._backend_agg import RendererAgg as _RendererAgg
43-
from matplotlib import _png
4440

4541
try:
4642
from PIL import Image
@@ -52,12 +48,12 @@
5248

5349
def get_hinting_flag():
5450
mapping = {
55-
True: LOAD_FORCE_AUTOHINT,
56-
False: LOAD_NO_HINTING,
57-
'either': LOAD_DEFAULT,
58-
'native': LOAD_NO_AUTOHINT,
59-
'auto': LOAD_FORCE_AUTOHINT,
60-
'none': LOAD_NO_HINTING
51+
True: _ft2.LOAD_FORCE_AUTOHINT,
52+
False: _ft2.LOAD_NO_HINTING,
53+
'either': _ft2.LOAD_DEFAULT,
54+
'native': _ft2.LOAD_NO_AUTOHINT,
55+
'auto': _ft2.LOAD_FORCE_AUTOHINT,
56+
'none': _ft2.LOAD_NO_HINTING
6157
}
6258
return mapping[rcParams['text.hinting']]
6359

@@ -110,9 +106,9 @@ def __setstate__(self, state):
110106

111107
def _get_hinting_flag(self):
112108
if rcParams['text.hinting']:
113-
return LOAD_FORCE_AUTOHINT
109+
return _ft2.LOAD_FORCE_AUTOHINT
114110
else:
115-
return LOAD_NO_HINTING
111+
return _ft2.LOAD_NO_HINTING
116112

117113
# for filtering to work with rasterization, methods needs to be wrapped.
118114
# maybe there is better way to do it.
@@ -183,7 +179,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
183179
yd = descent * cos(radians(angle))
184180
x = np.round(x + ox + xd)
185181
y = np.round(y - oy + yd)
186-
self._renderer.draw_text_image(font_image, x, y + 1, angle, gc)
182+
self._renderer.draw_text_image(font_image, x, y, angle, gc)
187183

188184
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
189185
"""
@@ -197,24 +193,15 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
197193

198194
if font is None:
199195
return None
200-
if len(s) == 1 and ord(s) > 127:
201-
font.load_char(ord(s), flags=flags)
202-
else:
203-
# We pass '0' for angle here, since it will be rotated (in raster
204-
# space) in the following call to draw_text_image).
205-
font.set_text(s, 0, flags=flags)
206-
font.draw_glyphs_to_bitmap(antialiased=rcParams['text.antialiased'])
207-
d = font.get_descent() / 64.0
196+
layout = _ft2.Layout.simple(s, font, flags)
197+
d = -np.floor(layout.yMin)
208198
# The descent needs to be adjusted for the angle
209-
xo, yo = font.get_bitmap_offset()
210-
xo /= 64.0
211-
yo /= 64.0
212199
xd = -d * sin(radians(angle))
213200
yd = d * cos(radians(angle))
214201

215-
#print x, y, int(x), int(y), s
216202
self._renderer.draw_text_image(
217-
font, np.round(x - xd + xo), np.round(y + yd + yo) + 1, angle, gc)
203+
layout.render(), # FIXME Antialiasing.
204+
np.round(x - xd), np.round(y + yd), angle, gc)
218205

219206
def get_text_width_height_descent(self, s, prop, ismath):
220207
"""
@@ -238,13 +225,10 @@ def get_text_width_height_descent(self, s, prop, ismath):
238225

239226
flags = get_hinting_flag()
240227
font = self._get_agg_font(prop)
241-
font.set_text(s, 0.0, flags=flags)
242-
w, h = font.get_width_height() # width and height of unrotated string
243-
d = font.get_descent()
244-
w /= 64.0 # convert from subpixels
245-
h /= 64.0
246-
d /= 64.0
247-
return w, h, d
228+
layout = _ft2.Layout.simple(s, font, flags)
229+
return (layout.xMax - layout.xMin,
230+
layout.yMax - layout.yMin,
231+
-layout.yMin)
248232

249233
def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None):
250234
# todo, handle props, angle, origins
@@ -271,13 +255,10 @@ def _get_agg_font(self, prop):
271255
"""
272256
Get the font for text instance t, cacheing for efficiency
273257
"""
274-
fname = findfont(prop)
275-
font = get_font(fname)
276-
277-
font.clear()
258+
fname = font_manager.findfont(prop)
259+
font = font_manager.get_font(fname)
278260
size = prop.get_size_in_points()
279-
font.set_size(size, self.dpi)
280-
261+
font.set_char_size(size, self.dpi)
281262
return font
282263

283264
def points_to_pixels(self, points):

0 commit comments

Comments
 (0)