| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 825f518 commit 3deec88
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,8 +25,8 @@ | |||
| 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 | |
@@ -922,22 +986,18 @@ def print_figure_impl(fh): | |||
| 922 | 986 | # Can't use more than 255 chars from a single Type 3 font. | |
| 923 | 987 | if len(glyph_ids) > 255: | |
| 924 | 988 | fonttype = 42 | |
| 925 | - # The ttf to ps (subsetting) support doesn't work for | ||
| 926 | - # OpenType fonts that are Postscript inside (like the STIX | ||
| 927 | - # fonts). This will simply turn that off to avoid errors. | ||
| 928 | - if is_opentype_cff_font(font_path): | ||
| 929 | - raise RuntimeError( | ||
| 930 | - "OpenType CFF fonts can not be saved using " | ||
| 931 | - "the internal Postscript backend at this " | ||
| 932 | - "time; consider using the Cairo backend") | ||
| 933 | 989 | fh.flush() | |
| 934 | - try: | ||
| 935 | - convert_ttf_to_ps(os.fsencode(font_path), | ||
| 936 | - fh, fonttype, glyph_ids) | ||
| 937 | - except RuntimeError: | ||
| 938 | - _log.warning("The PostScript backend does not " | ||
| 939 | - "currently support the selected font.") | ||
| 940 | - raise | ||
| 990 | + if fonttype == 3: | ||
| 991 | + fh.write(_font_to_ps_type3(font_path, glyph_ids)) | ||
| 992 | + else: | ||
| 993 | + try: | ||
| 994 | + convert_ttf_to_ps(os.fsencode(font_path), | ||
| 995 | + fh, fonttype, glyph_ids) | ||
| 996 | + except RuntimeError: | ||
| 997 | + _log.warning( | ||
| 998 | + "The PostScript backend does not currently " | ||
| 999 | + "support the selected font.") | ||
| 1000 | + raise | ||
| 941 | 1001 | print("end", file=fh) | |
| 942 | 1002 | print("%%EndProlog", file=fh) | |
| 943 | 1003 | ||
@@ -1312,30 +1372,36 @@ def pstoeps(tmpfile, bbox=None, rotated=False): | |||
| 1312 | 1372 | # The usage comments use the notation of the operator summary | |
| 1313 | 1373 | # in the PostScript Language reference manual. | |
| 1314 | 1374 | psDefs = [ | |
| 1375 | + # name proc *d* - | ||
| 1376 | + "/d { bind def } bind def", | ||
| 1315 | 1377 | # x y *m* - | |
| 1316 | - "/m { moveto } bind def", | ||
| 1378 | + "/m { moveto } d", | ||
| 1317 | 1379 | # x y *l* - | |
| 1318 | - "/l { lineto } bind def", | ||
| 1380 | + "/l { lineto } d", | ||
| 1319 | 1381 | # x y *r* - | |
| 1320 | - "/r { rlineto } bind def", | ||
| 1382 | + "/r { rlineto } d", | ||
| 1321 | 1383 | # x1 y1 x2 y2 x y *c* - | |
| 1322 | - "/c { curveto } bind def", | ||
| 1323 | - # *closepath* - | ||
| 1324 | - "/cl { closepath } bind def", | ||
| 1384 | + "/c { curveto } d", | ||
| 1385 | + # *cl* - | ||
| 1386 | + "/cl { closepath } d", | ||
| 1387 | + # *ce* - | ||
| 1388 | + "/ce { closepath eofill } d", | ||
| 1325 | 1389 | # w h x y *box* - | |
| 1326 | 1390 | """/box { | |
| 1327 | 1391 | m | |
| 1328 | 1392 | 1 index 0 r | |
| 1329 | 1393 | 0 exch r | |
| 1330 | 1394 | neg 0 r | |
| 1331 | 1395 | cl | |
| 1332 | - } bind def""", | ||
| 1396 | + } d""", | ||
| 1333 | 1397 | # w h x y *clipbox* - | |
| 1334 | 1398 | """/clipbox { | |
| 1335 | 1399 | box | |
| 1336 | 1400 | clip | |
| 1337 | 1401 | newpath | |
| 1338 | - } bind def""", | ||
| 1402 | + } d""", | ||
| 1403 | + # wx wy llx lly urx ury *setcachedevice* - | ||
| 1404 | + "/sc { setcachedevice } d", | ||
| 1339 | 1405 | ] | |
| 1340 | 1406 | ||
| 1341 | 1407 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,112 @@ | |||
| 1 | + %!PS-Adobe-3.0 EPSF-3.0 | ||
| 2 | + %%Orientation: portrait | ||
| 3 | + %%BoundingBox: 18.0 180.0 594.0 612.0 | ||
| 4 | + %%EndComments | ||
| 5 | + %%BeginProlog | ||
| 6 | + /mpldict 11 dict def | ||
| 7 | + mpldict begin | ||
| 8 | + /d { bind def } bind def | ||
| 9 | + /m { moveto } d | ||
| 10 | + /l { lineto } d | ||
| 11 | + /r { rlineto } d | ||
| 12 | + /c { curveto } d | ||
| 13 | + /cl { closepath } d | ||
| 14 | + /ce { closepath eofill } d | ||
| 15 | + /box { | ||
| 16 | + m | ||
| 17 | + 1 index 0 r | ||
| 18 | + 0 exch r | ||
| 19 | + neg 0 r | ||
| 20 | + cl | ||
| 21 | + } d | ||
| 22 | + /clipbox { | ||
| 23 | + box | ||
| 24 | + clip | ||
| 25 | + newpath | ||
| 26 | + } d | ||
| 27 | + /sc { setcachedevice } d | ||
| 28 | + %!PS-Adobe-3.0 Resource-Font | ||
| 29 | + %%Creator: Converted from TrueType to Type 3 by Matplotlib. | ||
| 30 | + 10 dict begin | ||
| 31 | + /FontName /DejaVuSans def | ||
| 32 | + /PaintType 0 def | ||
| 33 | + /FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def | ||
| 34 | + /FontBBox [-2090 -948 3673 2524] def | ||
| 35 | + /FontType 3 def | ||
| 36 | + /Encoding [/I /J /slash] def | ||
| 37 | + /CharStrings 4 dict dup begin | ||
| 38 | + /.notdef 0 def | ||
| 39 | + /I{604 0 201 0 403 1493 sc | ||
| 40 | + 201 1493 m | ||
| 41 | + 403 1493 l | ||
| 42 | + 403 0 l | ||
| 43 | + 201 0 l | ||
| 44 | + 201 1493 l | ||
| 45 | + | ||
| 46 | + ce} d | ||
| 47 | + /J{604 0 -106 -410 403 1493 sc | ||
| 48 | + 201 1493 m | ||
| 49 | + 403 1493 l | ||
| 50 | + 403 104 l | ||
| 51 | + 403 -76 369 -207 300 -288 c | ||
| 52 | + 232 -369 122 -410 -29 -410 c | ||
| 53 | + -106 -410 l | ||
| 54 | + -106 -240 l | ||
| 55 | + -43 -240 l | ||
| 56 | + 46 -240 109 -215 146 -165 c | ||
| 57 | + 183 -115 201 -25 201 104 c | ||
| 58 | + 201 1493 l | ||
| 59 | + | ||
| 60 | + ce} d | ||
| 61 | + /slash{690 0 0 -190 690 1493 sc | ||
| 62 | + 520 1493 m | ||
| 63 | + 690 1493 l | ||
| 64 | + 170 -190 l | ||
| 65 | + 0 -190 l | ||
| 66 | + 520 1493 l | ||
| 67 | + | ||
| 68 | + ce} d | ||
| 69 | + end readonly def | ||
| 70 | + | ||
| 71 | + /BuildGlyph { | ||
| 72 | + exch begin | ||
| 73 | + CharStrings exch | ||
| 74 | + 2 copy known not {pop /.notdef} if | ||
| 75 | + true 3 1 roll get exec | ||
| 76 | + end | ||
| 77 | + } d | ||
| 78 | + | ||
| 79 | + /BuildChar { | ||
| 80 | + 1 index /Encoding get exch get | ||
| 81 | + 1 index /BuildGlyph get exec | ||
| 82 | + } d | ||
| 83 | + | ||
| 84 | + FontName currentdict end definefont pop | ||
| 85 | + end | ||
| 86 | + %%EndProlog | ||
| 87 | + mpldict begin | ||
| 88 | + 18 180 translate | ||
| 89 | + 576 432 0 0 clipbox | ||
| 90 | + gsave | ||
| 91 | + 0 0 m | ||
| 92 | + 576 0 l | ||
| 93 | + 576 432 l | ||
| 94 | + 0 432 l | ||
| 95 | + cl | ||
| 96 | + 1.000 setgray | ||
| 97 | + fill | ||
| 98 | + grestore | ||
| 99 | + 0.000 setgray | ||
| 100 | + /DejaVuSans findfont | ||
| 101 | + 12.000 scalefont | ||
| 102 | + setfont | ||
| 103 | + gsave | ||
| 104 | + 288.000000 216.000000 translate | ||
| 105 | + 0.000000 rotate | ||
| 106 | + 0.000000 0 m /I glyphshow | ||
| 107 | + 3.539062 0 m /slash glyphshow | ||
| 108 | + 7.582031 0 m /J glyphshow | ||
| 109 | + grestore | ||
| 110 | + | ||
| 111 | + end | ||
| 112 | + showpage | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -157,3 +157,8 @@ def test_useafm(): | |||
| 157 | 157 | ax.set_axis_off() | |
| 158 | 158 | ax.axhline(.5) | |
| 159 | 159 | ax.text(.5, .5, "qk") | |
| 160 | + | ||
| 161 | + | ||
| 162 | + @image_comparison(["type3.eps"]) | ||
| 163 | + def test_type3_font(): | ||
| 164 | + plt.figtext(.5, .5, "I/J") | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -120,11 +120,8 @@ def test_find_ttc(): | |||
| 120 | 120 | ||
| 121 | 121 | fig, ax = plt.subplots() | |
| 122 | 122 | ax.text(.5, .5, "\N{KANGXI RADICAL DRAGON}", fontproperties=fp) | |
| 123 | - fig.savefig(BytesIO(), format="raw") | ||
| 124 | - fig.savefig(BytesIO(), format="svg") | ||
| 125 | - fig.savefig(BytesIO(), format="pdf") | ||
| 126 | - with pytest.raises(RuntimeError): | ||
| 127 | - fig.savefig(BytesIO(), format="ps") | ||
| 123 | + for fmt in ["raw", "svg", "pdf", "ps"]: | ||
| 124 | + fig.savefig(BytesIO(), format=fmt) | ||
| 128 | 125 | ||
| 129 | 126 | ||
| 130 | 127 | def test_find_invalid(tmpdir): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments