|
25 | 25 | _Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
|
26 | 26 | GraphicsContextBase, RendererBase)
|
27 | 27 | from matplotlib.cbook import is_writable_file_like, file_requires_unicode
|
28 |
| -from matplotlib.font_manager import is_opentype_cff_font, get_font |
29 |
| -from matplotlib.ft2font import LOAD_NO_HINTING |
| 28 | +from matplotlib.font_manager import get_font |
| 29 | +from matplotlib.ft2font import LOAD_NO_HINTING, LOAD_NO_SCALE |
30 | 30 | from matplotlib._ttconv import convert_ttf_to_ps
|
31 | 31 | from matplotlib.mathtext import MathTextParser
|
32 | 32 | from matplotlib._mathtext_data import uni2type1
|
@@ -134,6 +134,70 @@ def _move_path_to_path_or_stream(src, dst):
|
134 | 134 | shutil.move(src, dst, copy_function=shutil.copyfile)
|
135 | 135 |
|
136 | 136 |
|
| 137 | +def _font_to_ps_type3(font_path, glyph_ids): |
| 138 | + font = get_font(font_path, hinting_factor=1) |
| 139 | + |
| 140 | + preamble = """\ |
| 141 | +%!PS-Adobe-3.0 Resource-Font |
| 142 | +%%Creator: Converted from TrueType to Type 3 by Matplotlib. |
| 143 | +10 dict begin |
| 144 | +/FontName /{font_name} def |
| 145 | +/PaintType 0 def |
| 146 | +/FontMatrix [{inv_units_per_em} 0 0 {inv_units_per_em} 0 0] def |
| 147 | +/FontBBox [{bbox}] def |
| 148 | +/FontType 3 def |
| 149 | +/Encoding [{encoding}] def |
| 150 | +/CharStrings {num_glyphs} dict dup begin |
| 151 | +/.notdef 0 def |
| 152 | +""".format(font_name=font.postscript_name, |
| 153 | + inv_units_per_em=1 / font.units_per_EM, |
| 154 | + bbox=" ".join(map(str, font.bbox)), |
| 155 | + encoding=" ".join("/{}".format(font.get_glyph_name(glyph_id)) |
| 156 | + for glyph_id in glyph_ids), |
| 157 | + num_glyphs=len(glyph_ids) + 1) |
| 158 | + postamble = """ |
| 159 | +end readonly def |
| 160 | +
|
| 161 | +/BuildGlyph { |
| 162 | + exch begin |
| 163 | + CharStrings exch |
| 164 | + 2 copy known not {pop /.notdef} if |
| 165 | + true 3 1 roll get exec |
| 166 | + end |
| 167 | +} d |
| 168 | +
|
| 169 | +/BuildChar { |
| 170 | + 1 index /Encoding get exch get |
| 171 | + 1 index /BuildGlyph get exec |
| 172 | +} d |
| 173 | +
|
| 174 | +FontName currentdict end definefont pop |
| 175 | +""" |
| 176 | + |
| 177 | + entries = [] |
| 178 | + for glyph_id in glyph_ids: |
| 179 | + g = font.load_glyph(glyph_id, LOAD_NO_SCALE) |
| 180 | + v, c = font.get_path() |
| 181 | + entries.append( |
| 182 | + "/%(name)s{%(bbox)s sc\n" % { |
| 183 | + "name": font.get_glyph_name(glyph_id), |
| 184 | + "bbox": " ".join(map(str, [g.horiAdvance, 0, *g.bbox])), |
| 185 | + } |
| 186 | + + _path.convert_to_string( |
| 187 | + # Convert back to TrueType's internal units (1/64's). |
| 188 | + # (Other dimensions are already in these units.) |
| 189 | + Path(v * 64, c), None, None, False, None, 0, |
| 190 | + # No code for quad Beziers triggers auto-conversion to cubics. |
| 191 | + # Drop intermediate closepolys (relying on the outline |
| 192 | + # decomposer always explicitly moving to the closing point |
| 193 | + # first). |
| 194 | + [b"m", b"l", b"", b"c", b""], True).decode("ascii") |
| 195 | + + "ce} d" |
| 196 | + ) |
| 197 | + |
| 198 | + return preamble + "\n".join(entries) + postamble |
| 199 | + |
| 200 | + |
137 | 201 | class RendererPS(_backend_pdf_ps.RendererPDFPSBase):
|
138 | 202 | """
|
139 | 203 | The renderer handles all the drawing primitives using a graphics
|
@@ -932,22 +996,18 @@ def print_figure_impl(fh):
|
932 | 996 | # Can't use more than 255 chars from a single Type 3 font.
|
933 | 997 | if len(glyph_ids) > 255:
|
934 | 998 | fonttype = 42
|
935 |
| - # The ttf to ps (subsetting) support doesn't work for |
936 |
| - # OpenType fonts that are Postscript inside (like the STIX |
937 |
| - # fonts). This will simply turn that off to avoid errors. |
938 |
| - if is_opentype_cff_font(font_path): |
939 |
| - raise RuntimeError( |
940 |
| - "OpenType CFF fonts can not be saved using " |
941 |
| - "the internal Postscript backend at this " |
942 |
| - "time; consider using the Cairo backend") |
943 | 999 | fh.flush()
|
944 |
| - try: |
945 |
| - convert_ttf_to_ps(os.fsencode(font_path), |
946 |
| - fh, fonttype, glyph_ids) |
947 |
| - except RuntimeError: |
948 |
| - _log.warning("The PostScript backend does not " |
949 |
| - "currently support the selected font.") |
950 |
| - raise |
| 1000 | + if fonttype == 3: |
| 1001 | + fh.write(_font_to_ps_type3(font_path, glyph_ids)) |
| 1002 | + else: |
| 1003 | + try: |
| 1004 | + convert_ttf_to_ps(os.fsencode(font_path), |
| 1005 | + fh, fonttype, glyph_ids) |
| 1006 | + except RuntimeError: |
| 1007 | + _log.warning( |
| 1008 | + "The PostScript backend does not currently " |
| 1009 | + "support the selected font.") |
| 1010 | + raise |
951 | 1011 | print("end", file=fh)
|
952 | 1012 | print("%%EndProlog", file=fh)
|
953 | 1013 |
|
@@ -1333,30 +1393,36 @@ def pstoeps(tmpfile, bbox=None, rotated=False):
|
1333 | 1393 | # The usage comments use the notation of the operator summary
|
1334 | 1394 | # in the PostScript Language reference manual.
|
1335 | 1395 | psDefs = [
|
| 1396 | + # name proc *d* - |
| 1397 | + "/d { bind def } bind def", |
1336 | 1398 | # x y *m* -
|
1337 |
| - "/m { moveto } bind def", |
| 1399 | + "/m { moveto } d", |
1338 | 1400 | # x y *l* -
|
1339 |
| - "/l { lineto } bind def", |
| 1401 | + "/l { lineto } d", |
1340 | 1402 | # x y *r* -
|
1341 |
| - "/r { rlineto } bind def", |
| 1403 | + "/r { rlineto } d", |
1342 | 1404 | # x1 y1 x2 y2 x y *c* -
|
1343 |
| - "/c { curveto } bind def", |
1344 |
| - # *closepath* - |
1345 |
| - "/cl { closepath } bind def", |
| 1405 | + "/c { curveto } d", |
| 1406 | + # *cl* - |
| 1407 | + "/cl { closepath } d", |
| 1408 | + # *ce* - |
| 1409 | + "/ce { closepath eofill } d", |
1346 | 1410 | # w h x y *box* -
|
1347 | 1411 | """/box {
|
1348 | 1412 | m
|
1349 | 1413 | 1 index 0 r
|
1350 | 1414 | 0 exch r
|
1351 | 1415 | neg 0 r
|
1352 | 1416 | cl
|
1353 |
| - } bind def""", |
| 1417 | + } d""", |
1354 | 1418 | # w h x y *clipbox* -
|
1355 | 1419 | """/clipbox {
|
1356 | 1420 | box
|
1357 | 1421 | clip
|
1358 | 1422 | newpath
|
1359 |
| - } bind def""", |
| 1423 | + } d""", |
| 1424 | + # wx wy llx lly urx ury *setcachedevice* - |
| 1425 | + "/sc { setcachedevice } d", |
1360 | 1426 | ]
|
1361 | 1427 |
|
1362 | 1428 |
|
|
0 commit comments