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

Skip to content

Commit 6c21928

Browse files
committed
Prevent errors when using OpenType CFF fonts. This means turning off
subsetting on backend_pdf, and raising an exception in backend_ps. svn path=/trunk/matplotlib/; revision=4126
1 parent 6c156f6 commit 6c21928

5 files changed

Lines changed: 78 additions & 25 deletions

File tree

examples/mathtext_examples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
r'$\widehat{abc}\widetilde{def}$',
5050
r'$\Gamma \Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega$',
5151
r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu \nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$',
52-
ur'Generic symbol: $\u23ce \mathrm{\ue0f2}$'
52+
ur'Generic symbol: $\u23ce \mathrm{\ue0f2 \U0001D538}$'
5353
]
5454

5555
from pylab import *

lib/matplotlib/backends/backend_pdf.py

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import re
1010
import sys
1111
import time
12+
import warnings
1213
import zlib
1314

1415
import numpy as npy
@@ -25,7 +26,7 @@
2526
FigureManagerBase, FigureCanvasBase
2627
from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict, get_realpath_and_stat
2728
from matplotlib.figure import Figure
28-
from matplotlib.font_manager import findfont
29+
from matplotlib.font_manager import findfont, is_opentype_cff_font
2930
from matplotlib.afm import AFM
3031
import matplotlib.type1font as type1font
3132
import matplotlib.dviread as dviread
@@ -786,7 +787,8 @@ def embedTTFType42(font, characters, descriptor):
786787
glyph = font.load_char(ccode, flags=LOAD_NO_HINTING)
787788
# Why divided by 3.0 ??? Wish I knew... MGD
788789
widths.append((ccode, cvt(glyph.horiAdvance) / 3.0))
789-
cid_to_gid_map[ccode] = unichr(gind)
790+
if ccode < 65536:
791+
cid_to_gid_map[ccode] = unichr(gind)
790792
max_ccode = max(ccode, max_ccode)
791793
widths.sort()
792794
cid_to_gid_map = cid_to_gid_map[:max_ccode + 1]
@@ -876,6 +878,15 @@ def embedTTFType42(font, characters, descriptor):
876878
'StemV' : 0 # ???
877879
}
878880

881+
# The font subsetting to a Type 3 font does not work for
882+
# OpenType (.otf) that embed a Postscript CFF font, so avoid that --
883+
# save as a (non-subsetted) Type 42 font instead.
884+
if is_opentype_cff_font(filename):
885+
fonttype = 42
886+
warnings.warn(("'%s' can not be subsetted into a Type 3 font. " +
887+
"The entire font will be embedded in the output.") %
888+
os.path.basename(filename))
889+
879890
if fonttype == 3:
880891
return embedTTFType3(font, characters, descriptor)
881892
elif fonttype == 42:
@@ -1134,10 +1145,6 @@ def __init__(self, file, dpi):
11341145
self.truetype_font_cache = {}
11351146
self.afm_font_cache = {}
11361147
self.file.used_characters = self.used_characters = {}
1137-
if rcParams['pdf.fonttype'] == 3:
1138-
self.encode_string = self.encode_string_type3
1139-
else:
1140-
self.encode_string = self.encode_string_type42
11411148
self.mathtext_parser = MathTextParser("Pdf")
11421149
self.image_magnification = dpi/72.0
11431150
self.tex_font_map = None
@@ -1344,7 +1351,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
13441351
# When using Type 3 fonts, we can't use character codes higher
13451352
# than 255, so we use the "Do" command to render those
13461353
# instead.
1347-
fonttype = rcParams['pdf.fonttype']
1354+
global_fonttype = rcParams['pdf.fonttype']
13481355

13491356
# Set up a global transformation matrix for the whole math expression
13501357
a = angle / 180.0 * pi
@@ -1357,21 +1364,31 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
13571364
prev_font = None, None
13581365
oldx, oldy = 0, 0
13591366
for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
1367+
if is_opentype_cff_font(fontname):
1368+
fonttype = 42
1369+
else:
1370+
fonttype = global_fonttype
1371+
13601372
if fonttype == 42 or num <= 255:
13611373
self._setup_textpos(ox, oy, 0, oldx, oldy)
13621374
oldx, oldy = ox, oy
13631375
if (fontname, fontsize) != prev_font:
13641376
self.file.output(self.file.fontName(fontname), fontsize,
13651377
Op.selectfont)
13661378
prev_font = fontname, fontsize
1367-
self.file.output(self.encode_string(unichr(num)), Op.show)
1379+
self.file.output(self.encode_string(unichr(num), fonttype), Op.show)
13681380
self.file.output(Op.end_text)
13691381

13701382
# If using Type 3 fonts, render all of the two-byte characters
13711383
# as XObjects using the 'Do' command.
1372-
if fonttype == 3:
1384+
if global_fonttype == 3:
13731385
for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
1374-
if num > 255:
1386+
if is_opentype_cff_font(fontname):
1387+
fonttype = 42
1388+
else:
1389+
fonttype = global_fonttype
1390+
1391+
if fonttype == 3 and num > 255:
13751392
self.file.output(Op.gsave,
13761393
0.001 * fontsize, 0,
13771394
0, 0.001 * fontsize,
@@ -1471,10 +1488,9 @@ def mytrans(x1, y1, x=x, y=y, a=angle / 180.0 * pi):
14711488
self.draw_polygon(boxgc, gc._rgb,
14721489
((x1,y1), (x2,y2), (x3,y3), (x4,y4)))
14731490

1474-
def encode_string_type3(self, s):
1475-
return s.encode('cp1252', 'replace')
1476-
1477-
def encode_string_type42(self, s):
1491+
def encode_string(self, s, fonttype):
1492+
if fonttype == 3:
1493+
return s.encode('cp1252', 'replace')
14781494
return s.encode('utf-16be', 'replace')
14791495

14801496
def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
@@ -1500,20 +1516,29 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
15001516
font = self._get_font_afm(prop)
15011517
l, b, w, h = font.get_str_bbox(s)
15021518
y -= b * fontsize / 1000
1519+
fonttype = 42
15031520
else:
15041521
font = self._get_font_ttf(prop)
15051522
self.track_characters(font, s)
15061523
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
15071524
y += font.get_descent() / 64.0
15081525

1526+
fonttype = rcParams['pdf.fonttype']
1527+
1528+
# We can't subset all OpenType fonts, so switch to Type 42
1529+
# in that case.
1530+
if is_opentype_cff_font(font.fname):
1531+
fonttype = 42
1532+
15091533
def check_simple_method(s):
15101534
"""Determine if we should use the simple or woven method
1511-
to output this text, and chunks the string into 1-bit and
1512-
2-bit sections if necessary."""
1535+
to output this text, and chunks the string into 1-byte and
1536+
2-byte sections if necessary."""
15131537
use_simple_method = True
15141538
chunks = []
1515-
if rcParams['pdf.fonttype'] == 3:
1516-
if not isinstance(s, str) and len(s) != 0:
1539+
1540+
if not rcParams['pdf.use14corefonts']:
1541+
if fonttype == 3 and not isinstance(s, str) and len(s) != 0:
15171542
# Break the string into chunks where each chunk is either
15181543
# a string of chars <= 255, or a single character > 255.
15191544
s = unicode(s)
@@ -1537,7 +1562,7 @@ def draw_text_simple():
15371562
prop.get_size_in_points(),
15381563
Op.selectfont)
15391564
self._setup_textpos(x, y, angle)
1540-
self.file.output(self.encode_string(s), Op.show, Op.end_text)
1565+
self.file.output(self.encode_string(s, fonttype), Op.show, Op.end_text)
15411566

15421567
def draw_text_woven(chunks):
15431568
"""Outputs text using the woven method, alternating
@@ -1567,7 +1592,7 @@ def draw_text_woven(chunks):
15671592
for chunk_type, chunk in chunks:
15681593
if mode == 1 and chunk_type == 1:
15691594
self._setup_textpos(newx, 0, 0, oldx, 0, 0)
1570-
self.file.output(self.encode_string(chunk), Op.show)
1595+
self.file.output(self.encode_string(chunk, fonttype), Op.show)
15711596
oldx = newx
15721597

15731598
lastgind = None

lib/matplotlib/backends/backend_ps.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def _fn_name(): return sys._getframe(1).f_code.co_name
1818
from matplotlib.cbook import is_string_like, izip, get_realpath_and_stat
1919
from matplotlib.figure import Figure
2020

21-
from matplotlib.font_manager import findfont
21+
from matplotlib.font_manager import findfont, is_opentype_cff_font
2222
from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
2323
from matplotlib.ttconv import convert_ttf_to_ps
2424
from matplotlib.mathtext import MathTextParser
@@ -1030,7 +1030,7 @@ def _print_ps(self, outfile, format, *args, **kwargs):
10301030
else:
10311031
self._print_figure(outfile, format, dpi, facecolor, edgecolor,
10321032
orientation, isLandscape, papertype)
1033-
1033+
10341034
def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
10351035
orientation='portrait', isLandscape=False, papertype=None):
10361036
"""
@@ -1134,7 +1134,15 @@ def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
11341134
for c in chars:
11351135
gind = cmap.get(ord(c)) or 0
11361136
glyph_ids.append(gind)
1137-
convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
1137+
# The ttf to ps (subsetting) support doesn't work for
1138+
# OpenType fonts that are Postscript inside (like the
1139+
# STIX fonts). This will simply turn that off to avoid
1140+
# errors.
1141+
if is_opentype_cff_font(font_filename):
1142+
raise RuntimeError("OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend.")
1143+
else:
1144+
fonttype = rcParams['ps.fonttype']
1145+
convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
11381146
print >>fh, "end"
11391147
print >>fh, "%%EndProlog"
11401148

lib/matplotlib/font_manager.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,25 @@ def lookup_name(name):
10591059
return self.defaultFont
10601060
return fname
10611061

1062+
1063+
_is_opentype_cff_font_cache = {}
1064+
def is_opentype_cff_font(filename):
1065+
"""
1066+
Returns True if the given font is a Postscript Compact Font Format
1067+
Font embedded in an OpenType wrapper.
1068+
"""
1069+
if os.path.splitext(filename)[1].lower() == '.otf':
1070+
result = _is_opentype_cff_font_cache.get(filename)
1071+
if result is None:
1072+
fd = open(filename, 'rb')
1073+
tag = fd.read(4)
1074+
fd.close()
1075+
result = (tag == 'OTTO')
1076+
_is_opentype_cff_font_cache[filename] = result
1077+
return result
1078+
return False
1079+
1080+
10621081
if USE_FONTCONFIG and sys.platform != 'win32':
10631082
import re
10641083

lib/matplotlib/mathtext.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1945,7 +1945,8 @@ def __init__(self):
19451945
) | Error(r"Expected \hspace{n}"))
19461946
).setParseAction(self.customspace).setName('customspace')
19471947

1948-
symbol =(Regex(ur"([a-zA-Z0-9 +\-*/<>=:,.;!'@()\u0080-\uffff])|(\\[%${}\[\]])")
1948+
unicode_range = u"\U00000080-\U0001ffff"
1949+
symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!'@()%s])|(\\[%%${}\[\]])" % unicode_range)
19491950
| Combine(
19501951
bslash
19511952
+ oneOf(tex2uni.keys())

0 commit comments

Comments
 (0)