Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b6a2f4a

Browse files
committed
Factor out common code between pdf and ps backends.
(The AFM cache only needs to cache on filename, not on font properties, because the fontprop->filename conversion is already cached by font_manager.)
1 parent 13a617b commit b6a2f4a

File tree

5 files changed

+132
-174
lines changed

5 files changed

+132
-174
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
API deprecations
2+
````````````````
3+
4+
The following API elements are deprecated:
5+
6+
- ``backend_pdf.RendererPdf.afm_font_cache``,
7+
- ``backend_ps.RendererPS.afmfontd``,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"""
2+
Common functionality between the PDF and PS backends.
3+
"""
4+
5+
import functools
6+
7+
from .. import font_manager, ft2font, rcParams
8+
from ..afm import AFM
9+
from ..backend_bases import RendererBase
10+
11+
12+
@functools.lru_cache(50)
13+
def _cached_get_afm_from_fname(fname):
14+
with open(fname, 'rb') as fh:
15+
return AFM(fh)
16+
17+
18+
class RendererPDFPSBase(RendererBase):
19+
# The following attributes must be defined by the subclasses:
20+
# - _afm_font_dir
21+
# - _use_afm_rc_name
22+
23+
def flipy(self):
24+
# docstring inherited
25+
return False # y increases from bottom to top.
26+
27+
def option_scale_image(self):
28+
# docstring inherited
29+
return True # PDF and PS support arbitrary image scaling.
30+
31+
def option_image_nocomposite(self):
32+
# docstring inherited
33+
# Decide whether to composite image based on rcParam value.
34+
return not rcParams['image.composite_image']
35+
36+
def get_text_width_height_descent(self, s, prop, ismath):
37+
# docstring inherited
38+
if rcParams['text.usetex']:
39+
texmanager = self.get_texmanager()
40+
fontsize = prop.get_size_in_points()
41+
w, h, d = texmanager.get_text_width_height_descent(
42+
s, fontsize, renderer=self)
43+
return w, h, d
44+
elif ismath:
45+
parse = self.mathtext_parser.parse(s, 72, prop)
46+
return parse.width, parse.height, parse.depth
47+
elif rcParams[self._use_afm_rc_name]:
48+
font = self._get_font_afm(prop)
49+
l, b, w, h, d = font.get_str_bbox_and_descent(s)
50+
scale = prop.get_size_in_points() / 1000
51+
w *= scale
52+
h *= scale
53+
d *= scale
54+
return w, h, d
55+
else:
56+
font = self._get_font_ttf(prop)
57+
font.set_text(s, 0.0, flags=ft2font.LOAD_NO_HINTING)
58+
w, h = font.get_width_height()
59+
d = font.get_descent()
60+
scale = 1 / 64
61+
w *= scale
62+
h *= scale
63+
d *= scale
64+
return w, h, d
65+
66+
def _get_font_afm(self, prop):
67+
fname = (
68+
font_manager.findfont(
69+
prop, fontext='afm', directory=self._afm_font_dir)
70+
or font_manager.findfont(
71+
"Helvetica", fontext='afm', directory=self._afm_font_dir))
72+
return _cached_get_afm_from_fname(fname)
73+
74+
def _get_font_ttf(self, prop):
75+
fname = font_manager.findfont(prop)
76+
font = font_manager.get_font(fname)
77+
font.clear()
78+
font.set_size(prop.get_size_in_points(), 72)
79+
return font

lib/matplotlib/backends/backend_pdf.py

Lines changed: 11 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
2727
RendererBase)
2828
from matplotlib.backends.backend_mixed import MixedModeRenderer
29-
from matplotlib.cbook import get_realpath_and_stat, maxdict
3029
from matplotlib.figure import Figure
3130
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
3231
from matplotlib.afm import AFM
@@ -41,6 +40,7 @@
4140
from matplotlib import _path
4241
from matplotlib import _png
4342
from matplotlib import ttconv
43+
from . import _backend_pdf_ps
4444

4545
_log = logging.getLogger(__name__)
4646

@@ -706,7 +706,7 @@ def writeFonts(self):
706706
else:
707707
# a normal TrueType font
708708
_log.debug('Writing TrueType font.')
709-
realpath, stat_key = get_realpath_and_stat(filename)
709+
realpath, stat_key = cbook.get_realpath_and_stat(filename)
710710
chars = self.used_characters.get(stat_key)
711711
if chars is not None and len(chars[1]):
712712
fonts[Fx] = self.embedTTF(realpath, chars[1])
@@ -1574,8 +1574,14 @@ def writeTrailer(self):
15741574
self.write(b"\nstartxref\n%d\n%%%%EOF\n" % self.startxref)
15751575

15761576

1577-
class RendererPdf(RendererBase):
1578-
afm_font_cache = maxdict(50)
1577+
class RendererPdf(_backend_pdf_ps.RendererPDFPSBase):
1578+
@property
1579+
@cbook.deprecated("3.1")
1580+
def afm_font_cache(self, _cache=cbook.maxdict(50)):
1581+
return _cache
1582+
1583+
_afm_font_dir = os.path.join(rcParams['datapath'], 'fonts', 'pdfcorefonts')
1584+
_use_afm_rc_name = "pdf.use14corefonts"
15791585

15801586
def __init__(self, file, image_dpi, height, width):
15811587
RendererBase.__init__(self)
@@ -1623,7 +1629,7 @@ def track_characters(self, font, s):
16231629
fname = font
16241630
else:
16251631
fname = font.fname
1626-
realpath, stat_key = get_realpath_and_stat(fname)
1632+
realpath, stat_key = cbook.get_realpath_and_stat(fname)
16271633
used_characters = self.file.used_characters.setdefault(
16281634
stat_key, (realpath, set()))
16291635
used_characters[1].update(map(ord, s))
@@ -1637,14 +1643,6 @@ def merge_used_characters(self, other):
16371643
def get_image_magnification(self):
16381644
return self.image_dpi/72.0
16391645

1640-
def option_scale_image(self):
1641-
# docstring inherited
1642-
return True
1643-
1644-
def option_image_nocomposite(self):
1645-
# docstring inherited
1646-
return not rcParams['image.composite_image']
1647-
16481646
def draw_image(self, gc, x, y, im, transform=None):
16491647
# docstring inherited
16501648

@@ -2120,67 +2118,6 @@ def draw_text_woven(chunks):
21202118
else:
21212119
return draw_text_woven(chunks)
21222120

2123-
def get_text_width_height_descent(self, s, prop, ismath):
2124-
# docstring inherited
2125-
2126-
if rcParams['text.usetex']:
2127-
texmanager = self.get_texmanager()
2128-
fontsize = prop.get_size_in_points()
2129-
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
2130-
renderer=self)
2131-
return w, h, d
2132-
2133-
if ismath:
2134-
w, h, d, glyphs, rects, used_characters = \
2135-
self.mathtext_parser.parse(s, 72, prop)
2136-
2137-
elif rcParams['pdf.use14corefonts']:
2138-
font = self._get_font_afm(prop)
2139-
l, b, w, h, d = font.get_str_bbox_and_descent(s)
2140-
scale = prop.get_size_in_points()
2141-
w *= scale / 1000
2142-
h *= scale / 1000
2143-
d *= scale / 1000
2144-
else:
2145-
font = self._get_font_ttf(prop)
2146-
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
2147-
w, h = font.get_width_height()
2148-
scale = (1.0 / 64.0)
2149-
w *= scale
2150-
h *= scale
2151-
d = font.get_descent()
2152-
d *= scale
2153-
return w, h, d
2154-
2155-
def _get_font_afm(self, prop):
2156-
key = hash(prop)
2157-
font = self.afm_font_cache.get(key)
2158-
if font is None:
2159-
filename = findfont(
2160-
prop, fontext='afm', directory=self.file._core14fontdir)
2161-
if filename is None:
2162-
filename = findfont(
2163-
"Helvetica", fontext='afm',
2164-
directory=self.file._core14fontdir)
2165-
font = self.afm_font_cache.get(filename)
2166-
if font is None:
2167-
with open(filename, 'rb') as fh:
2168-
font = AFM(fh)
2169-
self.afm_font_cache[filename] = font
2170-
self.afm_font_cache[key] = font
2171-
return font
2172-
2173-
def _get_font_ttf(self, prop):
2174-
filename = findfont(prop)
2175-
font = get_font(filename)
2176-
font.clear()
2177-
font.set_size(prop.get_size_in_points(), 72)
2178-
return font
2179-
2180-
def flipy(self):
2181-
# docstring inherited
2182-
return False
2183-
21842121
def get_canvas_width_height(self):
21852122
# docstring inherited
21862123
return self.file.width * 72.0, self.file.height * 72.0

lib/matplotlib/backends/backend_ps.py

Lines changed: 13 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,22 @@
1717

1818
import numpy as np
1919

20-
from matplotlib import cbook, __version__, rcParams, checkdep_ghostscript
21-
from matplotlib.afm import AFM
20+
from matplotlib import (
21+
cbook, _path, __version__, rcParams, checkdep_ghostscript)
2222
from matplotlib.backend_bases import (
2323
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
2424
RendererBase)
2525
from matplotlib.cbook import (get_realpath_and_stat, is_writable_file_like,
26-
maxdict, file_requires_unicode)
27-
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
26+
file_requires_unicode)
27+
from matplotlib.font_manager import is_opentype_cff_font, get_font
2828
from matplotlib.ft2font import KERNING_DEFAULT, LOAD_NO_HINTING
2929
from matplotlib.ttconv import convert_ttf_to_ps
3030
from matplotlib.mathtext import MathTextParser
3131
from matplotlib._mathtext_data import uni2type1
3232
from matplotlib.path import Path
33-
from matplotlib import _path
3433
from matplotlib.transforms import Affine2D
3534
from matplotlib.backends.backend_mixed import MixedModeRenderer
35+
from . import _backend_pdf_ps
3636

3737
_log = logging.getLogger(__name__)
3838

@@ -180,13 +180,19 @@ def _move_path_to_path_or_stream(src, dst):
180180
shutil.move(src, dst, copy_function=shutil.copyfile)
181181

182182

183-
class RendererPS(RendererBase):
183+
class RendererPS(_backend_pdf_ps.RendererPDFPSBase):
184184
"""
185185
The renderer handles all the drawing primitives using a graphics
186186
context instance that controls the colors/styles.
187187
"""
188188

189-
afmfontd = maxdict(50)
189+
@property
190+
@cbook.deprecated("3.1")
191+
def afmfontd(self, _cache=cbook.maxdict(50)):
192+
return _cache
193+
194+
_afm_font_dir = os.path.join(rcParams['datapath'], 'fonts', 'afm')
195+
_use_afm_rc_name = "ps.useafm"
190196

191197
def __init__(self, width, height, pswriter, imagedpi=72):
192198
# Although postscript itself is dpi independent, we need to imform the
@@ -217,9 +223,6 @@ def __init__(self, width, height, pswriter, imagedpi=72):
217223
self.used_characters = {}
218224
self.mathtext_parser = MathTextParser("PS")
219225

220-
self._afm_font_dir = os.path.join(
221-
rcParams['datapath'], 'fonts', 'afm')
222-
223226
def track_characters(self, font, s):
224227
"""Keeps track of which characters are required from each font."""
225228
realpath, stat_key = get_realpath_and_stat(font.fname)
@@ -327,71 +330,6 @@ def get_canvas_width_height(self):
327330
# docstring inherited
328331
return self.width * 72.0, self.height * 72.0
329332

330-
def get_text_width_height_descent(self, s, prop, ismath):
331-
# docstring inherited
332-
333-
if rcParams['text.usetex']:
334-
texmanager = self.get_texmanager()
335-
fontsize = prop.get_size_in_points()
336-
w, h, d = texmanager.get_text_width_height_descent(s, fontsize,
337-
renderer=self)
338-
return w, h, d
339-
340-
if ismath:
341-
width, height, descent, pswriter, used_characters = \
342-
self.mathtext_parser.parse(s, 72, prop)
343-
return width, height, descent
344-
345-
if rcParams['ps.useafm']:
346-
if ismath:
347-
s = s[1:-1]
348-
font = self._get_font_afm(prop)
349-
l, b, w, h, d = font.get_str_bbox_and_descent(s)
350-
351-
fontsize = prop.get_size_in_points()
352-
scale = 0.001 * fontsize
353-
w *= scale
354-
h *= scale
355-
d *= scale
356-
return w, h, d
357-
358-
font = self._get_font_ttf(prop)
359-
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
360-
w, h = font.get_width_height()
361-
w /= 64 # convert from subpixels
362-
h /= 64
363-
d = font.get_descent()
364-
d /= 64
365-
return w, h, d
366-
367-
def flipy(self):
368-
# docstring inherited
369-
return False
370-
371-
def _get_font_afm(self, prop):
372-
key = hash(prop)
373-
font = self.afmfontd.get(key)
374-
if font is None:
375-
fname = findfont(prop, fontext='afm', directory=self._afm_font_dir)
376-
if fname is None:
377-
fname = findfont(
378-
"Helvetica", fontext='afm', directory=self._afm_font_dir)
379-
font = self.afmfontd.get(fname)
380-
if font is None:
381-
with open(fname, 'rb') as fh:
382-
font = AFM(fh)
383-
self.afmfontd[fname] = font
384-
self.afmfontd[key] = font
385-
return font
386-
387-
def _get_font_ttf(self, prop):
388-
fname = findfont(prop)
389-
font = get_font(fname)
390-
font.clear()
391-
size = prop.get_size_in_points()
392-
font.set_size(size, 72.0)
393-
return font
394-
395333
def _rgb(self, rgba):
396334
h, w = rgba.shape[:2]
397335
rgb = rgba[::-1, :, :3]
@@ -414,14 +352,6 @@ def get_image_magnification(self):
414352
"""
415353
return self.image_magnification
416354

417-
def option_scale_image(self):
418-
# docstring inherited
419-
return True
420-
421-
def option_image_nocomposite(self):
422-
# docstring inherited
423-
return not rcParams['image.composite_image']
424-
425355
def _get_image_h_w_bits_command(self, im):
426356
h, w, bits = self._rgb(im)
427357
imagecmd = "false 3 colorimage"

0 commit comments

Comments
 (0)