Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3daaf30

Browse files
committed
Move PostScript Type3 subsetting to pure python.
... similarly to the change for pdf, but easier because there are nobaseline images for which we need to provide bug-level backcompat :-)Drop the FontInfo metadata (which is explicitly optional in thePostScript spec) to avoid having to figure out the correct encoding(which can be quite obscure).Replace the implementation of the `_sc` command from`7 -1 roll{setcachedevice}{pop pop pop pop pop pop}ifelse` to a plain`setcachedevice` (as I cannot see any case where the "other" branch istaken).Drop the splitting of long commands using `exec` (`_e`) -- this is onlyneeded for level-1 postscript, which has a small fixed stack size; weoutput level-2 postscript (per backend_version) and I guess level-1 israrely in use nowadays anyways (probably the feature could be added backif there's really demand for it, but let's not get ahead of ourselves).Previously, some composite characters would be output in a "compressed"form (e.g., accented characters would be recorded as "draw the accent,then run the charproc for the unaccented character"). This is lost, butI'd guess outputting .ps.gz is better if compression really matters.
1 parent71de09a commit3daaf30

File tree

4 files changed

+210
-30
lines changed

4 files changed

+210
-30
lines changed

‎lib/matplotlib/backends/backend_ps.py

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
_Backend,_check_savefig_extra_args,FigureCanvasBase,FigureManagerBase,
2626
GraphicsContextBase,RendererBase)
2727
frommatplotlib.cbookimportis_writable_file_like,file_requires_unicode
28-
frommatplotlib.font_managerimportis_opentype_cff_font,get_font
29-
frommatplotlib.ft2fontimportLOAD_NO_HINTING
28+
frommatplotlib.font_managerimportget_font
29+
frommatplotlib.ft2fontimportLOAD_NO_HINTING,LOAD_NO_SCALE
3030
frommatplotlib._ttconvimportconvert_ttf_to_ps
3131
frommatplotlib.mathtextimportMathTextParser
3232
frommatplotlib._mathtext_dataimportuni2type1
@@ -134,6 +134,70 @@ def _move_path_to_path_or_stream(src, dst):
134134
shutil.move(src,dst,copy_function=shutil.copyfile)
135135

136136

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+
forglyph_idinglyph_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+
forglyph_idinglyph_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+
returnpreamble+"\n".join(entries)+postamble
199+
200+
137201
classRendererPS(_backend_pdf_ps.RendererPDFPSBase):
138202
"""
139203
The renderer handles all the drawing primitives using a graphics
@@ -932,22 +996,18 @@ def print_figure_impl(fh):
932996
# Can't use more than 255 chars from a single Type 3 font.
933997
iflen(glyph_ids)>255:
934998
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-
ifis_opentype_cff_font(font_path):
939-
raiseRuntimeError(
940-
"OpenType CFF fonts can not be saved using "
941-
"the internal Postscript backend at this "
942-
"time; consider using the Cairo backend")
943999
fh.flush()
944-
try:
945-
convert_ttf_to_ps(os.fsencode(font_path),
946-
fh,fonttype,glyph_ids)
947-
exceptRuntimeError:
948-
_log.warning("The PostScript backend does not "
949-
"currently support the selected font.")
950-
raise
1000+
iffonttype==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+
exceptRuntimeError:
1007+
_log.warning(
1008+
"The PostScript backend does not currently "
1009+
"support the selected font.")
1010+
raise
9511011
print("end",file=fh)
9521012
print("%%EndProlog",file=fh)
9531013

@@ -1333,30 +1393,36 @@ def pstoeps(tmpfile, bbox=None, rotated=False):
13331393
# The usage comments use the notation of the operator summary
13341394
# in the PostScript Language reference manual.
13351395
psDefs= [
1396+
# name proc *d* -
1397+
"/d { bind def } bind def",
13361398
# x y *m* -
1337-
"/m { moveto }bind def",
1399+
"/m { moveto }d",
13381400
# x y *l* -
1339-
"/l { lineto }bind def",
1401+
"/l { lineto }d",
13401402
# x y *r* -
1341-
"/r { rlineto }bind def",
1403+
"/r { rlineto }d",
13421404
# 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",
13461410
# w h x y *box* -
13471411
"""/box {
13481412
m
13491413
1 index 0 r
13501414
0 exch r
13511415
neg 0 r
13521416
cl
1353-
}bind def""",
1417+
}d""",
13541418
# w h x y *clipbox* -
13551419
"""/clipbox {
13561420
box
13571421
clip
13581422
newpath
1359-
} bind def""",
1423+
} d""",
1424+
# wx wy llx lly urx ury *setcachedevice* -
1425+
"/sc { setcachedevice } d",
13601426
]
13611427

13621428

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
/mpldict11dictdef
7+
mpldictbegin
8+
/d {binddef }binddef
9+
/m {moveto }d
10+
/l {lineto }d
11+
/r {rlineto }d
12+
/c {curveto }d
13+
/cl {closepath }d
14+
/ce {closepatheofill }d
15+
/box {
16+
m
17+
1index0r
18+
0exchr
19+
neg0r
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+
10dictbegin
31+
/FontName/DejaVuSansdef
32+
/PaintType0def
33+
/FontMatrix [0.00048828125000.0004882812500]def
34+
/FontBBox [-2090-94836732524]def
35+
/FontType3def
36+
/Encoding [/I/J/slash]def
37+
/CharStrings4dictdupbegin
38+
/.notdef0def
39+
/I{604020104031493sc
40+
2011493m
41+
4031493l
42+
4030l
43+
2010l
44+
2011493l
45+
46+
ce}d
47+
/J{6040-106-4104031493sc
48+
2011493m
49+
4031493l
50+
403104l
51+
403-76369-207300-288c
52+
232-369122-410-29-410c
53+
-106-410l
54+
-106-240l
55+
-43-240l
56+
46-240109-215146-165c
57+
183-115201-25201104c
58+
2011493l
59+
60+
ce}d
61+
/slash{69000-1906901493sc
62+
5201493m
63+
6901493l
64+
170-190l
65+
0-190l
66+
5201493l
67+
68+
ce}d
69+
endreadonlydef
70+
71+
/BuildGlyph {
72+
exchbegin
73+
CharStringsexch
74+
2copyknownnot {pop/.notdef}if
75+
true31rollgetexec
76+
end
77+
}d
78+
79+
/BuildChar {
80+
1index/Encodinggetexchget
81+
1index/BuildGlyphgetexec
82+
}d
83+
84+
FontNamecurrentdictenddefinefontpop
85+
end
86+
%%EndProlog
87+
mpldictbegin
88+
18180translate
89+
57643200clipbox
90+
gsave
91+
00m
92+
5760l
93+
576432l
94+
0432l
95+
cl
96+
1.000setgray
97+
fill
98+
grestore
99+
0.000setgray
100+
/DejaVuSansfindfont
101+
12.000scalefont
102+
setfont
103+
gsave
104+
288.000000216.000000translate
105+
0.000000rotate
106+
0.0000000m/Iglyphshow
107+
3.5390620m/slashglyphshow
108+
7.5820310m/Jglyphshow
109+
grestore
110+
111+
end
112+
showpage

‎lib/matplotlib/tests/test_backend_ps.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,8 @@ def test_partial_usetex(caplog):
133133
plt.savefig(io.BytesIO(),format="ps")
134134
assertcaplog.recordsandall("as if usetex=False"inrecord.getMessage()
135135
forrecordincaplog.records)
136+
137+
138+
@image_comparison(["type3.eps"])
139+
deftest_type3_font():
140+
plt.figtext(.5,.5,"I/J")

‎lib/matplotlib/tests/test_font_manager.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,8 @@ def test_find_ttc():
120120

121121
fig,ax=plt.subplots()
122122
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-
withpytest.raises(RuntimeError):
127-
fig.savefig(BytesIO(),format="ps")
123+
forfmtin ["raw","svg","pdf","ps"]:
124+
fig.savefig(BytesIO(),format=fmt)
128125

129126

130127
deftest_find_invalid(tmpdir):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp