|
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,77 @@ 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 | +20 dict begin |
| 144 | +/_d {{bind def}} bind def |
| 145 | +/_m {{moveto}} _d |
| 146 | +/_l {{lineto}} _d |
| 147 | +/_ce {{closepath eofill}} _d |
| 148 | +/_c {{curveto}} _d |
| 149 | +/_sc {{setcachedevice}} _d |
| 150 | +/_e {{exec}} _d |
| 151 | +/FontName /{font_name} def |
| 152 | +/PaintType 0 def |
| 153 | +/FontMatrix [{inv_units_per_em} 0 0 {inv_units_per_em} 0 0] def |
| 154 | +/FontBBox [{bbox}] def |
| 155 | +/FontType 3 def |
| 156 | +/Encoding [{encoding}] def |
| 157 | +/CharStrings {num_glyphs} dict dup begin |
| 158 | +/.notdef 0 def |
| 159 | +""".format(font_name=font.postscript_name, |
| 160 | + inv_units_per_em=1 / font.units_per_EM, |
| 161 | + bbox=" ".join(map(str, font.bbox)), |
| 162 | + encoding=" ".join("/{}".format(font.get_glyph_name(glyph_id)) |
| 163 | + for glyph_id in glyph_ids), |
| 164 | + num_glyphs=len(glyph_ids) + 1) |
| 165 | + postamble = """ |
| 166 | +end readonly def |
| 167 | +
|
| 168 | +/BuildGlyph { |
| 169 | + exch begin |
| 170 | + CharStrings exch |
| 171 | + 2 copy known not {pop /.notdef} if |
| 172 | + true 3 1 roll get exec |
| 173 | + end |
| 174 | +}_d |
| 175 | +
|
| 176 | +/BuildChar { |
| 177 | + 1 index /Encoding get exch get |
| 178 | + 1 index /BuildGlyph get exec |
| 179 | +}_d |
| 180 | +
|
| 181 | +FontName currentdict end definefont pop |
| 182 | +""" |
| 183 | + |
| 184 | + entries = [] |
| 185 | + for glyph_id in glyph_ids: |
| 186 | + g = font.load_glyph(glyph_id, LOAD_NO_SCALE) |
| 187 | + v, c = font.get_path() |
| 188 | + entries.append( |
| 189 | + "/%(name)s{%(bbox)s _sc\n" % { |
| 190 | + "name": font.get_glyph_name(glyph_id), |
| 191 | + "bbox": " ".join(map(str, [g.horiAdvance, 0, *g.bbox])), |
| 192 | + } |
| 193 | + + _path.convert_to_string( |
| 194 | + # Convert back to TrueType's internal units (1/64's). |
| 195 | + # (Other dimensions are already in these units.) |
| 196 | + Path(v * 64, c), None, None, False, None, 0, |
| 197 | + # No code for quad Beziers triggers auto-conversion to cubics. |
| 198 | + # Drop intermediate closepolys (relying on the outline |
| 199 | + # decomposer always explicitly moving to the closing point |
| 200 | + # first). |
| 201 | + [b"_m", b"_l", b"", b"_c", b""], True).decode("ascii") |
| 202 | + + "_ce}_d" |
| 203 | + ) |
| 204 | + |
| 205 | + return preamble + "\n".join(entries) + postamble |
| 206 | + |
| 207 | + |
137 | 208 | class RendererPS(_backend_pdf_ps.RendererPDFPSBase):
|
138 | 209 | """
|
139 | 210 | The renderer handles all the drawing primitives using a graphics
|
@@ -932,22 +1003,18 @@ def print_figure_impl(fh):
|
932 | 1003 | # Can't use more than 255 chars from a single Type 3 font.
|
933 | 1004 | if len(glyph_ids) > 255:
|
934 | 1005 | 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 | 1006 | 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 |
| 1007 | + if fonttype == 3: |
| 1008 | + fh.write(_font_to_ps_type3(font_path, glyph_ids)) |
| 1009 | + else: |
| 1010 | + try: |
| 1011 | + convert_ttf_to_ps(os.fsencode(font_path), |
| 1012 | + fh, fonttype, glyph_ids) |
| 1013 | + except RuntimeError: |
| 1014 | + _log.warning( |
| 1015 | + "The PostScript backend does not currently " |
| 1016 | + "support the selected font.") |
| 1017 | + raise |
951 | 1018 | print("end", file=fh)
|
952 | 1019 | print("%%EndProlog", file=fh)
|
953 | 1020 |
|
|
0 commit comments