def test_hinting_factor(factor): font = findfont(FontProperties(family=["sans-serif"])) font1 = get_font(font, hinting_factor=1) font1.clear() font1.set_size(12, 100) font1.set_text('abc') expected = font1.get_width_height() hinted_font = get_font(font, hinting_factor=factor) hinted_font.clear() hinted_font.set_size(12, 100) hinted_font.set_text('abc') # Check that hinting only changes text layout by a small (10%) amount. np.testing.assert_allclose(hinted_font.get_width_height(), expected, rtol=0.1)
def _get_font(self, prop): fname = findfont(prop) font = get_font(fname) font.clear() size = prop.get_size_in_points() font.set_size(size, 72.0) return font
def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return writer = self.writer writer.start('defs') for font_fname, chars in six.iteritems(self._fonts): font = get_font(font_fname) font.set_size(72, 72) sfnt = font.get_sfnt() writer.start('font', id=sfnt[(1, 0, 0, 4)]) writer.element( 'font-face', attrib={ 'font-family': font.family_name, 'font-style': font.style_name.lower(), 'units-per-em': '72', 'bbox': ' '.join( short_float_fmt(x / 64.0) for x in font.bbox)}) for char in chars: glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', d=path_data, attrib={ # 'glyph-name': name, 'unicode': unichr(char), 'horiz-adv-x': short_float_fmt(glyph.linearHoriAdvance / 65536.0)}) writer.end('font') writer.end('defs')
def _get_ps_font_and_encoding(texname): tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) font_bunch = tex_font_map[texname] if font_bunch.filename is None: raise ValueError( ("No usable font file found for %s (%s). " "The font may lack a Type-1 version.") % (font_bunch.psname, texname)) font = get_font(font_bunch.filename) for charmap_name, charmap_code in [("ADOBE_CUSTOM", 1094992451), ("ADOBE_STANDARD", 1094995778)]: try: font.select_charmap(charmap_code) except (ValueError, RuntimeError): pass else: break else: charmap_name = "" warnings.warn("No supported encoding in font (%s)." % font_bunch.filename) if charmap_name == "ADOBE_STANDARD" and font_bunch.encoding: enc0 = dviread.Encoding(font_bunch.encoding) enc = {i: _get_adobe_standard_encoding().get(c, None) for i, c in enumerate(enc0.encoding)} else: enc = {} return font, enc
def _get_font(self, prop): """ Find the `FT2Font` matching font properties *prop*, with its size set. """ fname = font_manager.findfont(prop) font = get_font(fname) font.set_size(self.FONT_SCALE, self.DPI) return font
def _get_font(self, prop): """ find a ttf font. """ fname = font_manager.findfont(prop) font = get_font(fname) font.set_size(self.FONT_SCALE, self.DPI) return font
def test_font_priority(): with rc_context(rc={"font.sans-serif": ["cmmi10", "Bitstream Vera Sans"]}): font = findfont(FontProperties(family=["sans-serif"])) assert_equal(os.path.basename(font), "cmmi10.ttf") # Smoketest get_charmap, which isn't used internally anymore font = get_font(font) cmap = font.get_charmap() assert len(cmap) == 131 assert cmap[8729] == 30
def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency """ fname = findfont(prop) font = get_font(fname) font.clear() size = prop.get_size_in_points() font.set_size(size, self.dpi) return font
def test_font_priority(): with rc_context(rc={ 'font.sans-serif': ['cmmi10', 'Bitstream Vera Sans']}): font = findfont(FontProperties(family=["sans-serif"])) assert Path(font).name == 'cmmi10.ttf' # Smoketest get_charmap, which isn't used internally anymore font = get_font(font) cmap = font.get_charmap() assert len(cmap) == 131 assert cmap[8729] == 30
def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency """ if __debug__: verbose.report("RendererAgg._get_agg_font", "debug-annoying") fname = findfont(prop) font = get_font(fname, hinting_factor=rcParams["text.hinting_factor"]) font.clear() size = prop.get_size_in_points() font.set_size(size, self.dpi) return font
def _get_ps_font_and_encoding(texname): tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) font_bunch = tex_font_map[texname] if font_bunch.filename is None: raise ValueError( f"No usable font file found for {font_bunch.psname} " f"({texname}). The font may lack a Type-1 version.") font = get_font(font_bunch.filename) if font_bunch.encoding: # If psfonts.map specifies an encoding, use it: it gives us a # mapping of glyph indices to Adobe glyph names; use it to convert # dvi indices to glyph names and use the FreeType-synthesized # unicode charmap to convert glyph names to glyph indices (with # FT_Get_Name_Index/get_name_index), and load the glyph using # FT_Load_Glyph/load_glyph. (That charmap has a coverage at least # as good as, and possibly better than, the native charmaps.) enc = dviread._parse_enc(font_bunch.encoding) else: # If psfonts.map specifies no encoding, the indices directly # map to the font's "native" charmap; so don't use the # FreeType-synthesized charmap but the native ones (we can't # directly identify it but it's typically an Adobe charmap), and # directly load the dvi glyph indices using FT_Load_Char/load_char. for charmap_code in [ 1094992451, # ADOBE_CUSTOM. 1094995778, # ADOBE_STANDARD. ]: try: font.select_charmap(charmap_code) except (ValueError, RuntimeError): pass else: break else: _log.warning("No supported encoding in font (%s).", font_bunch.filename) enc = None return font, enc
def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return writer = self.writer writer.start('defs') for font_fname, chars in six.iteritems(self._fonts): font = get_font(font_fname) font.set_size(72, 72) sfnt = font.get_sfnt() writer.start('font', id=sfnt[1, 0, 0, 4].decode("mac_roman")) writer.element( 'font-face', attrib={ 'font-family': font.family_name, 'font-style': font.style_name.lower(), 'units-per-em': '72', 'bbox': ' '.join(short_float_fmt(x / 64.0) for x in font.bbox) }) for char in chars: glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', d=path_data, attrib={ # 'glyph-name': name, 'unicode': unichr(char), 'horiz-adv-x': short_float_fmt(glyph.linearHoriAdvance / 65536.0) }) writer.end('font') writer.end('defs')
def get_glyphs_tex(self, prop, s, glyph_map=None, return_new_glyphs_only=False): """ convert the string *s* to vertices and codes using matplotlib's usetex mode. """ # codes are modstly borrowed from pdf backend. texmanager = self.get_texmanager() if self.tex_font_map is None: self.tex_font_map = dviread.PsfontsMap( dviread.find_tex_file('pdftex.map')) if self._adobe_standard_encoding is None: self._adobe_standard_encoding = self._get_adobe_standard_encoding() fontsize = prop.get_size_in_points() if hasattr(texmanager, "get_dvi"): dvifilelike = texmanager.get_dvi(s, self.FONT_SCALE) dvi = dviread.DviFromFileLike(dvifilelike, self.DPI) else: dvifile = texmanager.make_dvi(s, self.FONT_SCALE) dvi = dviread.Dvi(dvifile, self.DPI) with dvi: page = next(iter(dvi)) if glyph_map is None: glyph_map = dict() if return_new_glyphs_only: glyph_map_new = dict() else: glyph_map_new = glyph_map glyph_ids, xpositions, ypositions, sizes = [], [], [], [] # Gather font information and do some setup for combining # characters into strings. # oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: font_and_encoding = self._ps_fontd.get(dvifont.texname) font_bunch = self.tex_font_map[dvifont.texname] if font_and_encoding is None: font = get_font(font_bunch.filename) for charmap_name, charmap_code in [("ADOBE_CUSTOM", 1094992451), ("ADOBE_STANDARD", 1094995778)]: try: font.select_charmap(charmap_code) except (ValueError, RuntimeError): pass else: break else: charmap_name = "" warnings.warn("No supported encoding in font (%s)." % font_bunch.filename) if charmap_name == "ADOBE_STANDARD" and font_bunch.encoding: enc0 = dviread.Encoding(font_bunch.encoding) enc = dict([(i, self._adobe_standard_encoding.get(c, None)) for i, c in enumerate(enc0.encoding)]) else: enc = dict() self._ps_fontd[dvifont.texname] = font, enc else: font, enc = font_and_encoding ft2font_flag = LOAD_TARGET_LIGHT char_id = self._get_char_id_ps(font, glyph) if char_id not in glyph_map: font.clear() font.set_size(self.FONT_SCALE, self.DPI) if enc: charcode = enc.get(glyph, None) else: charcode = glyph if charcode is not None: glyph0 = font.load_char(charcode, flags=ft2font_flag) else: warnings.warn("The glyph (%d) of font (%s) cannot be " "converted with the encoding. Glyph may " "be wrong" % (glyph, font_bunch.filename)) glyph0 = font.load_char(glyph, flags=ft2font_flag) glyph_map_new[char_id] = self.glyph_to_path(font) glyph_ids.append(char_id) xpositions.append(x1) ypositions.append(y1) sizes.append(dvifont.size / self.FONT_SCALE) myrects = [] for ox, oy, h, w in page.boxes: vert1 = [(ox, oy), (ox + w, oy), (ox + w, oy + h), (ox, oy + h), (ox, oy), (0, 0)] code1 = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY] myrects.append((vert1, code1)) return (list(zip(glyph_ids, xpositions, ypositions, sizes)), glyph_map_new, myrects)
from matplotlib.path import Path from matplotlib import _png, rcParams from matplotlib.cbook import is_string_like, is_writable_file_like from matplotlib.compat import subprocess from matplotlib.compat.subprocess import check_output ############################################################################### # create a list of system fonts, all of these should work with xe/lua-latex system_fonts = [] if sys.platform.startswith('win'): from matplotlib import font_manager for f in font_manager.win32InstalledFonts(): try: system_fonts.append(font_manager.get_font(str(f)).family_name) except: pass # unknown error, skip this font else: # assuming fontconfig is installed and the command 'fc-list' exists try: # list scalable (non-bitmap) fonts fc_list = check_output(['fc-list', ':outline,scalable', 'family']) fc_list = fc_list.decode('utf8') system_fonts = [f.split(',')[0] for f in fc_list.splitlines()] system_fonts = list(set(system_fonts)) except: warnings.warn('error getting fonts from fc-list', UserWarning) def get_texcommand(): """Get chosen TeX system from rc."""
def _font_to_ps_type3(font_path, chars): """ Subset *chars* from the font at *font_path* into a Type 3 font. Parameters ---------- font_path : path-like Path to the font to be subsetted. chars : str The characters to include in the subsetted font. Returns ------- str The string representation of a Type 3 font, which can be included verbatim into a PostScript file. """ font = get_font(font_path, hinting_factor=1) glyph_ids = [font.get_char_index(c) for c in chars] preamble = """\ %!PS-Adobe-3.0 Resource-Font %%Creator: Converted from TrueType to Type 3 by Matplotlib. 10 dict begin /FontName /{font_name} def /PaintType 0 def /FontMatrix [{inv_units_per_em} 0 0 {inv_units_per_em} 0 0] def /FontBBox [{bbox}] def /FontType 3 def /Encoding [{encoding}] def /CharStrings {num_glyphs} dict dup begin /.notdef 0 def """.format(font_name=font.postscript_name, inv_units_per_em=1 / font.units_per_EM, bbox=" ".join(map(str, font.bbox)), encoding=" ".join("/{}".format(font.get_glyph_name(glyph_id)) for glyph_id in glyph_ids), num_glyphs=len(glyph_ids) + 1) postamble = """ end readonly def /BuildGlyph { exch begin CharStrings exch 2 copy known not {pop /.notdef} if true 3 1 roll get exec end } _d /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec } _d FontName currentdict end definefont pop """ entries = [] for glyph_id in glyph_ids: g = font.load_glyph(glyph_id, LOAD_NO_SCALE) v, c = font.get_path() entries.append( "/%(name)s{%(bbox)s sc\n" % { "name": font.get_glyph_name(glyph_id), "bbox": " ".join(map(str, [g.horiAdvance, 0, *g.bbox])), } + _path.convert_to_string( # Convert back to TrueType's internal units (1/64's). # (Other dimensions are already in these units.) Path(v * 64, c), None, None, False, None, 0, # No code for quad Beziers triggers auto-conversion to cubics. # Drop intermediate closepolys (relying on the outline # decomposer always explicitly moving to the closing point # first). [b"m", b"l", b"", b"c", b""], True).decode("ascii") + "ce} _d") return preamble + "\n".join(entries) + postamble
def print_figure_impl(fh): # write the PostScript headers if is_eps: print("%!PS-Adobe-3.0 EPSF-3.0", file=fh) else: print( f"%!PS-Adobe-3.0\n" f"%%DocumentPaperSizes: {papertype}\n" f"%%Pages: 1\n", end="", file=fh) if title: print("%%Title: " + title, file=fh) # get source date from SOURCE_DATE_EPOCH, if set # See https://reproducible-builds.org/specs/source-date-epoch/ source_date_epoch = os.getenv("SOURCE_DATE_EPOCH") if source_date_epoch: source_date = datetime.datetime.utcfromtimestamp( int(source_date_epoch)).strftime("%a %b %d %H:%M:%S %Y") else: source_date = time.ctime() print( f"%%Creator: {creator_str}\n" f"%%CreationDate: {source_date}\n" f"%%Orientation: {orientation.name}\n" f"%%BoundingBox: {bbox[0]} {bbox[1]} {bbox[2]} {bbox[3]}\n" f"%%EndComments\n", end="", file=fh) Ndict = len(psDefs) print("%%BeginProlog", file=fh) if not mpl.rcParams['ps.useafm']: Ndict += len(ps_renderer._character_tracker.used) print("/mpldict %d dict def" % Ndict, file=fh) print("mpldict begin", file=fh) for d in psDefs: d = d.strip() for l in d.split('\n'): print(l.strip(), file=fh) if not mpl.rcParams['ps.useafm']: for font_path, chars \ in ps_renderer._character_tracker.used.items(): if not chars: continue font = get_font(font_path) glyph_ids = [font.get_char_index(c) for c in chars] fonttype = mpl.rcParams['ps.fonttype'] # Can't use more than 255 chars from a single Type 3 font. if len(glyph_ids) > 255: fonttype = 42 # The ttf to ps (subsetting) support doesn't work for # OpenType fonts that are Postscript inside (like the STIX # fonts). This will simply turn that off to avoid errors. if is_opentype_cff_font(font_path): raise RuntimeError( "OpenType CFF fonts can not be saved using " "the internal Postscript backend at this " "time; consider using the Cairo backend") fh.flush() try: convert_ttf_to_ps(os.fsencode(font_path), fh, fonttype, glyph_ids) except RuntimeError: _log.warning("The PostScript backend does not " "currently support the selected font.") raise print("end", file=fh) print("%%EndProlog", file=fh) if not is_eps: print("%%Page: 1 1", file=fh) print("mpldict begin", file=fh) print("%s translate" % _nums_to_str(xo, yo), file=fh) if rotation: print("%d rotate" % rotation, file=fh) print("%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0), file=fh) # write the figure content = self._pswriter.getvalue() if not isinstance(content, str): content = content.decode('ascii') print(content, file=fh) # write the trailer print("end", file=fh) print("showpage", file=fh) if not is_eps: print("%%EOF", file=fh) fh.flush()
def print_figure_impl(fh): # write the PostScript headers if is_eps: print("%!PS-Adobe-3.0 EPSF-3.0", file=fh) else: print( f"%!PS-Adobe-3.0\n" f"%%DocumentPaperSizes: {papertype}\n" f"%%Pages: 1\n", end="", file=fh) print( f"{dsc_comments}\n" f"%%Orientation: {orientation.name}\n" f"{get_bbox_header(bbox)[0]}\n" f"%%EndComments\n", end="", file=fh) Ndict = len(psDefs) print("%%BeginProlog", file=fh) if not mpl.rcParams['ps.useafm']: Ndict += len(ps_renderer._character_tracker.used) print("/mpldict %d dict def" % Ndict, file=fh) print("mpldict begin", file=fh) print("\n".join(psDefs), file=fh) if not mpl.rcParams['ps.useafm']: for font_path, chars \ in ps_renderer._character_tracker.used.items(): if not chars: continue font = get_font(font_path) glyph_ids = [font.get_char_index(c) for c in chars] fonttype = mpl.rcParams['ps.fonttype'] # Can't use more than 255 chars from a single Type 3 font. if len(glyph_ids) > 255: fonttype = 42 fh.flush() if fonttype == 3: fh.write(_font_to_ps_type3(font_path, glyph_ids)) else: try: _log.debug("SUBSET %s characters: %s", font_path, ''.join(chr(c) for c in chars)) fontdata = _backend_pdf_ps.get_glyphs_subset( font_path, "".join(chr(c) for c in chars)) _log.debug("SUBSET %s %d -> %d", font_path, os.stat(font_path).st_size, fontdata.getbuffer().nbytes) # give ttconv a subsetted font # along with updated glyph_ids with TemporaryDirectory() as tmpdir: tmpfile = os.path.join(tmpdir, "tmp.ttf") font = FT2Font(fontdata) glyph_ids = [ font.get_char_index(c) for c in chars ] with open(tmpfile, 'wb') as tmp: tmp.write(fontdata.getvalue()) tmp.flush() # TODO: allow convert_ttf_to_ps # to input file objects (BytesIO) convert_ttf_to_ps( os.fsencode(tmpfile), fh, fonttype, glyph_ids, ) except RuntimeError: _log.warning( "The PostScript backend does not currently " "support the selected font.") raise print("end", file=fh) print("%%EndProlog", file=fh) if not is_eps: print("%%Page: 1 1", file=fh) print("mpldict begin", file=fh) print("%s translate" % _nums_to_str(xo, yo), file=fh) if rotation: print("%d rotate" % rotation, file=fh) print("%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0), file=fh) # write the figure print(self._pswriter.getvalue(), file=fh) # write the trailer print("end", file=fh) print("showpage", file=fh) if not is_eps: print("%%EOF", file=fh) fh.flush()
def print_figure_impl(fh): # write the PostScript headers if is_eps: print("%!PS-Adobe-3.0 EPSF-3.0", file=fh) else: print( f"%!PS-Adobe-3.0\n" f"%%DocumentPaperSizes: {papertype}\n" f"%%Pages: 1\n", end="", file=fh) print( f"{dsc_comments}\n" f"%%Orientation: {orientation.name}\n" f"{get_bbox_header(bbox)[0]}\n" f"%%EndComments\n", end="", file=fh) Ndict = len(psDefs) print("%%BeginProlog", file=fh) if not mpl.rcParams['ps.useafm']: Ndict += len(ps_renderer._character_tracker.used) print("/mpldict %d dict def" % Ndict, file=fh) print("mpldict begin", file=fh) print("\n".join(psDefs), file=fh) if not mpl.rcParams['ps.useafm']: for font_path, chars \ in ps_renderer._character_tracker.used.items(): if not chars: continue font = get_font(font_path) glyph_ids = [font.get_char_index(c) for c in chars] fonttype = mpl.rcParams['ps.fonttype'] # Can't use more than 255 chars from a single Type 3 font. if len(glyph_ids) > 255: fonttype = 42 fh.flush() if fonttype == 3: fh.write(_font_to_ps_type3(font_path, glyph_ids)) else: try: convert_ttf_to_ps(os.fsencode(font_path), fh, fonttype, glyph_ids) except RuntimeError: _log.warning( "The PostScript backend does not currently " "support the selected font.") raise print("end", file=fh) print("%%EndProlog", file=fh) if not is_eps: print("%%Page: 1 1", file=fh) print("mpldict begin", file=fh) print("%s translate" % _nums_to_str(xo, yo), file=fh) if rotation: print("%d rotate" % rotation, file=fh) print("%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0), file=fh) # write the figure print(self._pswriter.getvalue(), file=fh) # write the trailer print("end", file=fh) print("showpage", file=fh) if not is_eps: print("%%EOF", file=fh) fh.flush()
def get_glyphs_tex(self, prop, s, glyph_map=None, return_new_glyphs_only=False): """Convert the string *s* to vertices and codes using usetex mode.""" # Mostly borrowed from pdf backend. dvifile = TexManager().make_dvi(s, self.FONT_SCALE) with dviread.Dvi(dvifile, self.DPI) as dvi: page, = dvi if glyph_map is None: glyph_map = OrderedDict() if return_new_glyphs_only: glyph_map_new = OrderedDict() else: glyph_map_new = glyph_map glyph_ids, xpositions, ypositions, sizes = [], [], [], [] # Gather font information and do some setup for combining # characters into strings. for text in page.text: font = get_font(text.font_path) char_id = self._get_char_id(font, text.glyph) if char_id not in glyph_map: font.clear() font.set_size(self.FONT_SCALE, self.DPI) glyph_name_or_index = text.glyph_name_or_index if isinstance(glyph_name_or_index, str): index = font.get_name_index(glyph_name_or_index) font.load_glyph(index, flags=LOAD_TARGET_LIGHT) elif isinstance(glyph_name_or_index, int): self._select_native_charmap(font) font.load_char(glyph_name_or_index, flags=LOAD_TARGET_LIGHT) else: # Should not occur. raise TypeError(f"Glyph spec of unexpected type: " f"{glyph_name_or_index!r}") glyph_map_new[char_id] = font.get_path() glyph_ids.append(char_id) xpositions.append(text.x) ypositions.append(text.y) sizes.append(text.font_size / self.FONT_SCALE) myrects = [] for ox, oy, h, w in page.boxes: vert1 = [(ox, oy), (ox + w, oy), (ox + w, oy + h), (ox, oy + h), (ox, oy), (0, 0)] code1 = [ Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY ] myrects.append((vert1, code1)) return (list(zip(glyph_ids, xpositions, ypositions, sizes)), glyph_map_new, myrects)
def bad_idea(n): b.wait() for j in range(100): font = fm.get_font(fm.findfont("DejaVu Sans")) font.set_text(str(n), 0.0, flags=LOAD_NO_HINTING)
finally: timer.cancel() return [os.fsdecode(fname) for fname in out.split(b'\n')] zh_fonts = pd.unique(call_fc_list_zh()) print('fc-list :lang=zh \n', zh_fonts) print(mpl.matplotlib_fname()) # use command to find ttc list that supports Chinese: # fc-list :lang=zh # randomly choose one: Songti font_path = zh_fonts[2] prop = mfm.FontProperties(fname=font_path) fn = mfm.findfont(prop, fontext='ttc') f = mfm.get_font(fn) mpl.rcParams['font.family'] = f.family_name mpl.rcParams['axes.unicode_minus'] = False print(mpl.rcParams) df1 = pd.DataFrame({ u'计算机应用基础': [85, 78, 81, 95, 70, 67, 82, 72, 80, 81, 77], u'西方经济学': [93, 81, 76, 88, 66, 79, 83, 92, 78, 86, 78], u'Math': [65, 95, 51, 74, 78, 63, 91, 82, 75, 71, 55], u'英语': [76, 90, 97, 71, 70, 93, 86, 83, 78, 85, 81], }) print(df1) # df1.boxplot() # plt.show() plt.style.use('ggplot') plt.boxplot(x=df1.values, labels=df1.columns, whis=1.5, showmeans=True) plt.show()
def print_figure_impl(fh): # write the PostScript headers if is_eps: print("%!PS-Adobe-3.0 EPSF-3.0", file=fh) else: print(f"%!PS-Adobe-3.0\n" f"%%DocumentPaperSizes: {papertype}\n" f"%%Pages: 1\n", end="", file=fh) print(f"{dsc_comments}\n" f"%%Orientation: {orientation.name}\n" f"%%BoundingBox: {bbox[0]} {bbox[1]} {bbox[2]} {bbox[3]}\n" f"%%EndComments\n", end="", file=fh) Ndict = len(psDefs) print("%%BeginProlog", file=fh) if not mpl.rcParams['ps.useafm']: Ndict += len(ps_renderer._character_tracker.used) print("/mpldict %d dict def" % Ndict, file=fh) print("mpldict begin", file=fh) print("\n".join(psDefs), file=fh) if not mpl.rcParams['ps.useafm']: for font_path, chars \ in ps_renderer._character_tracker.used.items(): if not chars: continue font = get_font(font_path) glyph_ids = [font.get_char_index(c) for c in chars] fonttype = mpl.rcParams['ps.fonttype'] # Can't use more than 255 chars from a single Type 3 font. if len(glyph_ids) > 255: fonttype = 42 # The ttf to ps (subsetting) support doesn't work for # OpenType fonts that are Postscript inside (like the STIX # fonts). This will simply turn that off to avoid errors. if is_opentype_cff_font(font_path): raise RuntimeError( "OpenType CFF fonts can not be saved using " "the internal Postscript backend at this " "time; consider using the Cairo backend") fh.flush() try: convert_ttf_to_ps(os.fsencode(font_path), fh, fonttype, glyph_ids) except RuntimeError: _log.warning("The PostScript backend does not " "currently support the selected font.") raise print("end", file=fh) print("%%EndProlog", file=fh) if not is_eps: print("%%Page: 1 1", file=fh) print("mpldict begin", file=fh) print("%s translate" % _nums_to_str(xo, yo), file=fh) if rotation: print("%d rotate" % rotation, file=fh) print("%s clipbox" % _nums_to_str(width*72, height*72, 0, 0), file=fh) # write the figure print(self._pswriter.getvalue(), file=fh) # write the trailer print("end", file=fh) print("showpage", file=fh) if not is_eps: print("%%EOF", file=fh) fh.flush()
def get_glyphs_tex(self, prop, s, glyph_map=None, return_new_glyphs_only=False): """ convert the string *s* to vertices and codes using matplotlib's usetex mode. """ # codes are modstly borrowed from pdf backend. texmanager = self.get_texmanager() if self.tex_font_map is None: self.tex_font_map = dviread.PsfontsMap( dviread.find_tex_file('pdftex.map')) if self._adobe_standard_encoding is None: self._adobe_standard_encoding = self._get_adobe_standard_encoding() fontsize = prop.get_size_in_points() if hasattr(texmanager, "get_dvi"): dvifilelike = texmanager.get_dvi(s, self.FONT_SCALE) dvi = dviread.DviFromFileLike(dvifilelike, self.DPI) else: dvifile = texmanager.make_dvi(s, self.FONT_SCALE) dvi = dviread.Dvi(dvifile, self.DPI) with dvi: page = next(iter(dvi)) if glyph_map is None: glyph_map = OrderedDict() if return_new_glyphs_only: glyph_map_new = OrderedDict() else: glyph_map_new = glyph_map glyph_ids, xpositions, ypositions, sizes = [], [], [], [] # Gather font information and do some setup for combining # characters into strings. # oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: font_and_encoding = self._ps_fontd.get(dvifont.texname) font_bunch = self.tex_font_map[dvifont.texname] if font_and_encoding is None: if font_bunch.filename is None: raise ValueError(("No usable font file found for %s (%s). " "The font may lack a Type-1 version.") % (font_bunch.psname, dvifont.texname)) font = get_font(font_bunch.filename) for charmap_name, charmap_code in [ ("ADOBE_CUSTOM", 1094992451), ("ADOBE_STANDARD", 1094995778) ]: try: font.select_charmap(charmap_code) except (ValueError, RuntimeError): pass else: break else: charmap_name = "" warnings.warn("No supported encoding in font (%s)." % font_bunch.filename) if charmap_name == "ADOBE_STANDARD" and font_bunch.encoding: enc0 = dviread.Encoding(font_bunch.encoding) enc = { i: self._adobe_standard_encoding.get(c, None) for i, c in enumerate(enc0.encoding) } else: enc = {} self._ps_fontd[dvifont.texname] = font, enc else: font, enc = font_and_encoding ft2font_flag = LOAD_TARGET_LIGHT char_id = self._get_char_id_ps(font, glyph) if char_id not in glyph_map: font.clear() font.set_size(self.FONT_SCALE, self.DPI) if enc: charcode = enc.get(glyph, None) else: charcode = glyph if charcode is not None: glyph0 = font.load_char(charcode, flags=ft2font_flag) else: warnings.warn("The glyph (%d) of font (%s) cannot be " "converted with the encoding. Glyph may " "be wrong" % (glyph, font_bunch.filename)) glyph0 = font.load_char(glyph, flags=ft2font_flag) glyph_map_new[char_id] = self.glyph_to_path(font) glyph_ids.append(char_id) xpositions.append(x1) ypositions.append(y1) sizes.append(dvifont.size / self.FONT_SCALE) myrects = [] for ox, oy, h, w in page.boxes: vert1 = [(ox, oy), (ox + w, oy), (ox + w, oy + h), (ox, oy + h), (ox, oy), (0, 0)] code1 = [ Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY ] myrects.append((vert1, code1)) return (list(zip(glyph_ids, xpositions, ypositions, sizes)), glyph_map_new, myrects)