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

Commitcb204cd

Browse files
committed
Clearer implementation of charstring simulator
1 parent68fbefd commitcb204cd

File tree

1 file changed

+111
-111
lines changed

1 file changed

+111
-111
lines changed

‎lib/matplotlib/_type1font.py

Lines changed: 111 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ def subset(self, characters: Iterable[int], name_prefix: str) -> T.Self:
870870
seen_subrs= {0,1,2,3}
871871
whiletodo:
872872
glyph=todo.pop()
873-
called_glyphs,called_subrs,_,_=self._simulate(glyph, [], [])
873+
called_glyphs,called_subrs=_CharstringSimulator(self).run(glyph)
874874
todo.update(called_glyphs-done)
875875
seen_subrs.update(called_subrs)
876876
done.add(glyph)
@@ -943,116 +943,6 @@ def _charstring_tokens(data: T.Iterable[int]) -> T.Generator[int | str, None, No
943943
31:'hvcurveto'
944944
}[byte]
945945

946-
def_simulate(
947-
self,glyph_or_subr:str|int,buildchar_stack:list[float],
948-
postscript_stack:list[float]
949-
)->tuple[set[str],set[int],list[float],list[float]]:
950-
"""Run the charstring interpreter on a glyph or subroutine.
951-
952-
This does not actually execute the code but simulates it to find out
953-
which subroutines get called when executing the glyph or subroutine.
954-
955-
Parameters
956-
----------
957-
glyph_or_subr : str or int
958-
The name of the glyph or the index of the subroutine to simulate.
959-
buildchar_stack : list[float]
960-
The buildchar stack at the start of the simulation.
961-
postscript_stack : list[float]
962-
The PostScript stack at the start of the simulation.
963-
964-
Returns
965-
-------
966-
glyphs : set[str]
967-
The set of glyph names called by the glyph or subroutine.
968-
subrs : set[int]
969-
The set of subroutines called by the glyph or subroutine.
970-
buildchar_stack : list[float]
971-
The buildchar stack at the end of the simulation.
972-
postscript_stack : list[float]
973-
The PostScript stack at the end of the simulation.
974-
"""
975-
ifisinstance(glyph_or_subr,str):
976-
program=self.prop['CharStrings'][glyph_or_subr]
977-
glyphs= {glyph_or_subr}
978-
subrs=set()
979-
else:
980-
program=self.prop['Subrs'][glyph_or_subr]
981-
glyphs=set()
982-
subrs= {glyph_or_subr}
983-
foropcodeinself._charstring_tokens(program):
984-
ifopcodein ('return','endchar'):
985-
returnglyphs,subrs,buildchar_stack,postscript_stack
986-
newglyphs,newsubrs,buildchar_stack,postscript_stack= \
987-
self._step(buildchar_stack,postscript_stack,opcode)
988-
glyphs.update(newglyphs)
989-
subrs.update(newsubrs)
990-
else:
991-
font_name=self.prop.get('FontName','(unknown)')
992-
_log.info(
993-
f"Glyph or subr{glyph_or_subr} in font{font_name} does not end "
994-
"with return or endchar"
995-
)
996-
returnglyphs,subrs,buildchar_stack,postscript_stack
997-
998-
def_step(
999-
self,
1000-
buildchar_stack:list[float],
1001-
postscript_stack:list[float],
1002-
opcode:int|str,
1003-
)->tuple[set,set,list[float],list[float]]:
1004-
"""Run one step in the charstring interpreter."""
1005-
ifisinstance(opcode,int):
1006-
returnset(),set(),buildchar_stack+ [opcode],postscript_stack
1007-
elifopcodein {
1008-
'hsbw','sbw','closepath','hlineto','hmoveto','hcurveto',
1009-
'hvcurveto','rlineto','rmoveto','rrcurveto','vhcurveto',
1010-
'vlineto','vmoveto','dotsection','hstem','hstem3','vstem',
1011-
'vstem3','setcurrentpoint'
1012-
}:
1013-
returnset(),set(), [],postscript_stack
1014-
elifopcode=='seac':# Standard Encoding Accented Character
1015-
codes=buildchar_stack[3:5]
1016-
glyphs:set[str]= {_StandardEncoding[int(x)]forxincodes}
1017-
returnglyphs,set(), [],postscript_stack
1018-
elifopcode=='div':
1019-
num1,num2=buildchar_stack[-2:]
1020-
returnset(),set(),buildchar_stack[-2:]+ [num1/num2],postscript_stack
1021-
elifopcode=='callothersubr':
1022-
othersubr=buildchar_stack[-1]
1023-
n=buildchar_stack[-2]
1024-
ifnotisinstance(n,int):
1025-
_log.warning(
1026-
f"callothersubr{othersubr} with non-integer argument count in "
1027-
f"font{self.prop['FontName']}"
1028-
)
1029-
n=int(n)
1030-
args=buildchar_stack[-2-n:-2]
1031-
ifothersubr==3:# Section 8.1 in Type-1 spec
1032-
postscript_stack.append(args[0])
1033-
else:
1034-
postscript_stack.extend(args[::-1])
1035-
returnset(),set(),buildchar_stack[:-n-2],postscript_stack
1036-
elifopcode=='callsubr':
1037-
subr=buildchar_stack[-1]
1038-
ifnotisinstance(subr,int):
1039-
_log.warning(
1040-
f"callsubr with non-integer argument{subr} in font "
1041-
f"{self.prop['FontName']}"
1042-
)
1043-
subr=int(subr)
1044-
glyphs,subrs,new_bc_stack,new_ps_stack= \
1045-
self._simulate(subr,buildchar_stack[:-1],postscript_stack)
1046-
returnset(),subrs| {subr},new_bc_stack,new_ps_stack
1047-
elifopcode=='pop':
1048-
return (
1049-
set(),
1050-
set(),
1051-
buildchar_stack+ [postscript_stack[-1]],postscript_stack[:-1]
1052-
)
1053-
else:
1054-
raiseRuntimeError(f'opcode{opcode}')
1055-
1056946
def_postscript_encoding(self,encoding:dict[int,str])->str:
1057947
"""Return a PostScript encoding array for the encoding."""
1058948
return'\n'.join([
@@ -1106,6 +996,116 @@ def _subset_subrs(self, indices: set[int]) -> str:
1106996
])
1107997

1108998

999+
class_CharstringSimulator:
1000+
__slots__= ('font','buildchar_stack','postscript_stack','glyphs','subrs')
1001+
font:Type1Font
1002+
buildchar_stack:list[float]
1003+
postscript_stack:list[float]
1004+
glyphs:set[str]
1005+
subrs:set[int]
1006+
1007+
def__init__(self,font:Type1Font):
1008+
self.font=font
1009+
self.buildchar_stack= []
1010+
self.postscript_stack= []
1011+
self.glyphs=set()
1012+
self.subrs=set()
1013+
1014+
defrun(self,glyph_or_subr:str|int)->tuple[set[str],set[int]]:
1015+
"""Run the charstring interpreter on a glyph or subroutine.
1016+
1017+
This does not actually execute the code but simulates it to find out
1018+
which subroutines get called when executing the glyph or subroutine.
1019+
1020+
Parameters
1021+
----------
1022+
glyph_or_subr : str or int
1023+
The name of the glyph or the index of the subroutine to simulate.
1024+
1025+
Returns
1026+
-------
1027+
glyphs : set[str]
1028+
The set of glyph names called by the glyph or subroutine.
1029+
subrs : set[int]
1030+
The set of subroutines called by the glyph or subroutine.
1031+
"""
1032+
ifisinstance(glyph_or_subr,str):
1033+
program=self.font.prop['CharStrings'][glyph_or_subr]
1034+
self.glyphs.add(glyph_or_subr)
1035+
else:
1036+
program=self.font.prop['Subrs'][glyph_or_subr]
1037+
self.subrs.add(glyph_or_subr)
1038+
foropcodeinself.font._charstring_tokens(program):
1039+
ifopcodein ('return','endchar'):
1040+
returnself.glyphs,self.subrs
1041+
self._step(opcode)
1042+
else:
1043+
font_name=self.font.prop.get('FontName','(unknown)')
1044+
_log.info(
1045+
f"Glyph or subr{glyph_or_subr} in font{font_name} does not end "
1046+
"with return or endchar"
1047+
)
1048+
returnself.glyphs,self.subrs
1049+
1050+
def_step(self,opcode:int|str)->None:
1051+
"""Run one step in the charstring interpreter."""
1052+
matchopcode:
1053+
case _ifisinstance(opcode,int):
1054+
self.buildchar_stack.append(opcode)
1055+
case (
1056+
'hsbw'|'sbw'|'closepath'|'hlineto'|'hmoveto'|'hcurveto'|
1057+
'hvcurveto'|'rlineto'|'rmoveto'|'rrcurveto'|'vhcurveto'|
1058+
'vlineto'|'vmoveto'|'dotsection'|'hstem'|'hstem3'|
1059+
'vstem'|'vstem3'|'setcurrentpoint'
1060+
):
1061+
self.buildchar_stack.clear()
1062+
case'seac':# Standard Encoding Accented Character
1063+
codes=self.buildchar_stack[3:5]
1064+
self.glyphs.update(_StandardEncoding[int(x)]forxincodes)
1065+
self.buildchar_stack.clear()
1066+
case'div':
1067+
num1,num2=self.buildchar_stack[-2:]
1068+
ifnum2==0:
1069+
_log.warning(
1070+
f"Division by zero in font{self.font.prop['FontName']}"
1071+
)
1072+
self.buildchar_stack[-2:]= [0]
1073+
else:
1074+
self.buildchar_stack[-2:]= [num1/num2]
1075+
case'callothersubr':
1076+
n,othersubr=self.buildchar_stack[-2:]
1077+
ifnotisinstance(n,int):
1078+
_log.warning(
1079+
f"callothersubr{othersubr} with non-integer argument "
1080+
f"count in font{self.font.prop['FontName']}"
1081+
)
1082+
n=int(n)
1083+
args=self.buildchar_stack[-2-n:-2]
1084+
ifothersubr==3:
1085+
self.postscript_stack.append(args[0])
1086+
else:
1087+
self.postscript_stack.extend(args[::-1])
1088+
self.buildchar_stack[-2-n:]= []
1089+
case'callsubr':
1090+
subr=self.buildchar_stack.pop()
1091+
ifnotisinstance(subr,int):
1092+
_log.warning(
1093+
f"callsubr with non-integer argument{subr} in font "
1094+
f"{self.font.prop['FontName']}"
1095+
)
1096+
subr=int(subr)
1097+
self.run(subr)
1098+
case'pop':
1099+
ifnotself.postscript_stack:
1100+
_log.warning(
1101+
f"pop with empty stack in font{self.font.prop['FontName']}"
1102+
)
1103+
self.postscript_stack.append(0)
1104+
self.buildchar_stack.append(self.postscript_stack.pop())
1105+
case _:
1106+
raiseRuntimeError(f'opcode{opcode}')
1107+
1108+
11091109
_StandardEncoding= {
11101110
**{ord(letter):letterforletterinstring.ascii_letters},
11111111
0:'.notdef',

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp