From mimsy!haven!purdue!decwrl!adobe!greid Fri Mar 10 11:01:27 EST 1989 Article 1989 of comp.lang.postscript: Path: mimsy!haven!purdue!decwrl!adobe!greid >From: greid@adobe.com (Glenn Reid) Newsgroups: comp.lang.postscript Subject: release 10 of the Distillery Message-ID: <626@adobe.UUCP> Date: 10 Mar 89 10:21:52 GMT Sender: news@adobe.COM Reply-To: greid@adobe.COM () Organization: Adobe Systems Incorporated, Mountain View Lines: 2201 Here is another release of the PostScript Language Distillery. I know it's not terribly long after the last release, but there are some significant enhancements, and I thought it would be worthwhile. I finally took a closer look at user-defined fonts, which now seem to be working fairly well. In particular, it seems to handle the Macintosh screen bitmap fonts that get used if the native font is unavailable when the print file is genreated. The entire user-defined font is reverse-engineered to the output file as it stands, and is used exactly like the original file used it. I also fixed some rotate text bugs, rotated charpath, and a few other things. I want to emphasize that probably the two best uses of this program, currently, are to do speed comparisons of various PostScript language drivers and to convert "non-conforming" files into "conforming" files. It is not particularly well suited to carefully hand-written programs, especially not those which use looping constructs. It works (usually), but it unrolls the loops and makes the files much bigger. --------------------------- cut here ----------------------- %!PS-Adobe-2.1 %%Title: still.ps %%Creator: Glenn Reid, Adobe Systems %%CreationDate: greid Wed Jul 6 18:02:53 1988 EDIT: Thu Mar 9 23:08:53 1989 %%VMUsage: 44036 (approx) %%EndComments % Notice: Copyright 1988 1989 Adobe Systems Incorporated. All Rights Reserved. /adobe_distill 155 200 add dict def % 155 required by still.ps /adobe_still_version ((V 1.0d release 10 edit 06)) def % options: /debug true def % generate debugging messages /messages false def % generate more debugging messages (verbose!) /trace true def % print tracing messages like "page: 3" /substitutefonts true def % substitute fonts if guess_font fails.... /includeuserfonts true def % copy embedded user-defined fonts to output?; /printpages false def % do you want the pages to print? /optimize true def % optimize "show" to "widthshow", etc. /tolerance .05 def % for "essentially equal to" operations /cachedir 60 dict def % how many font dicts to cache (optimization) /includeprologue true def % output files with/without prologue % % HOW TO USE: [see section below] % % OVERVIEW: % This is a meta-utility program that "distills" any PostScript % language program into a simpler one. The resulting program % will print exactly the same page as the original, but all % unnecessary execution overhead is eliminated and the file is % clean, uniform, and fast. % % RELEASE NOTES: [recent changes and details] % First public release: 2/10/89 % Second release (numbered release 8): 2/17/89 % - reimplemented guess_font routines % - added support for color; not careful about RGB->CMYK->RGB % - added selective printing of pages during distill % Release 9: 3/2/89 % - fixed color-induced [major efficiency loss] bug % - produces %%BoundingBox and %%PageBoundingBox info (atend) % - works better (bugs fixed) on rotated (landscape) documents % - fixed horrible bug related to CTM that made it resolution- % dependent in some cases. % - included flag to omit the prologue on output if desired % - moved some of the flags to the beginning of the file % - improved prologue code to simulate CMYK color with RGB % Release 10: 3/10/89 % - fixed bug related to rotated text % - fixed rotated charpath bug mentioned in KNOWN PROBLEMS list % - fixed bug with "closepath" followed by "rmoveto" % - '=' and 'print' operators now pass data through to output % - bug fixes for and much better support of user-defined fonts % % MANY USES: % * If you archive documents in PostScript format, they can be % made compact and efficient by distilling them. % * As a development tool, you can see what your program is % really doing, and how simple and fast the driver could be. % * Distilled files can be used as an interchange format, % since arbitrary PostScript files can be converted to this % uniform representation. % * If your program can parse these files, then any arbitrary % PostScript program can be used as input after distilling. % * Many others. % % FEATURES: % * correctly distills arbitrarily complex PostScript programs % * output is universal, simple, and in default user coordinates % * handles "charpath", "image", "imagemask", "awidthshow", etc. % * correctly follows "save", "restore", "gsave", "grestore" % * re-encodes fonts automatically to match application encoding % * reduces prologue size to only about 25-30 lines % * For machine-generated code: % * output files are almost always SMALLER than original files % * output files are almost always FASTER than original files % * optimizes "show" to use "widthshow" whenever possible. % * uses save/restore at page boundaries % * observes structuring conventions and page independence % * caches font dictionaries instead of repeating "findfonts" % * output is normally VERY fast. % % HOW TO USE: % This program redefines a bunch of operators, and is invoked % with the word "distill". This file has to precede the job it is % distilling, and you have to invoke it by calling "distill". % % PRINTERS: % In general, start with this file (still.ps), add the word % "distill" at the end (to invoke the procedure), and tack % any PostScript language file onto the end. Send this to % your favorite PostScript printer with an appropriate % end-of-file indication at the end. Results will % be returned across communication channel, often to a log % file somewhere (Unix: /usr/adm/printername.log) % % INTERPRETERS: if you have an interpreter with a file system % handy, first type "(still.ps) run" to load this file, then % distill your file like this: "(prog.ps) distill". It will % write the results in "prog.psx" (appends an x to the file % name you give it). % % MACINTOSH: I have written a small Mac utility that is called % "DistillPS" (an adaptation of "SendPS") that will perform the % above PRINTER steps for you. If you are an Adobe registered % developer, you can get a copy directly from Adobe (or see % posting in USENET comp.binaries.mac group). % % BACKGROUND % The basic idea is to execute the input file completely, with all of % the painting operators redefined. When one of these operators is % called by the client program, the distillery will write the % path the output file (with all coordinates normalized to the default % userspace coordinate system). Note that it will usually take LONGER % to distill a file than it would to print it, because it executes the % whole program, and much of it in a redefined state (slower). Usually % only about 20% slower than original print time to distill. % % The routines in this file are broken down into several areas. Most % of them are concerned with writing things to the output file, % actually, although there are two other interesting areas. The first % are the graphics state procedures, which attempt to keep track of the % graphics state and, when a painting op is called, it writes out any % changes to the graphics state since the last time it was called. This % keeps each painting op from having to write gstate itself. The other % interesting procs are simply the redefinitions of the painting ops % themselves. % % KNOWN COMPATIBLE PROGRAMS % The following applications have been tested (with some version of the % driver, at least), successfully: % Lotus Manuscript % Macintosh "LaserPrep" (all documents, I think) % DEC's VaxDocument % Scribe % PageMaker % Frame Maker % Adobe Illustrator % TranScript (ditroff and enscript drivers) % % KNOWN PROBLEMS: % Clipping isn't handled correctly. % % I'm not convinced that the bounding box for images is right. % % Hand-written PostScript language programs (especially those % that take advantage of looping constructs) may get BIGGER % when you distill them, because the Distillery unrolls all loops. % It is really intended for machine-generated files, but it should % still work on programs tightly coded by hand (like Cookbook % examples). % % Use of the "put" and "putinterval" operators to overwrite % string bodies can confuse the optimization technique. If you % see strange output (wrong characters printed, especially), % try changing "/optimize true def" to "/optimize false def" % at the very beginning of this program. % % Programs that use the "transform" operator to make resolution- % rounding decisions may have the output file bound to a specific % resolution. The last ProcSet (called "hacks") redefines a few % operators to try to work around this. Output file is still % device-independent in any case, but might look different. % % Distillery relies on bug in save/restore related to string bodies % to preserve some information across save/restore. It is localized % to the "adobe_staticvar" procedure set, but may not always work. % % In order to optimize re-encoding of fonts, the distillery takes % an educated guess that the first re-encoded font it sees will % have a representative encoding vector ("stdvec"). If this % first font is not encountered before other marks are made, the encoding % vector cannot be produced in the %%BeginSetup section, and the still % is forced to repeat the vector every time a font is used. Work % is in progress on a heuristic to improve this. % % In order to avoid building up the dictionary stack during % execution, all definitions are made in one dictionary % (PROLOGUE) and it is not explicitly brought to the top of % the dictionary stack for each operation (to avoid % "dictstackoverflow" errors). Most of the identifiers have % been chosen to be reasonably unique, but there could be a % conflict if user programs use the same names. % % Sometimes generates unnecessarily verbose code in the presence % of lots of save/restores in original file. Try distilling the % output a second time to improve this (like whiskey).... % % Some of the ProcSets depend on each other in weird ways, which % is definitely wrong, since only the script should depend on % the procset definitions. Eventually this will get fixed. % % Does not always work correctly with user-defined fonts, especially % those defined by the standard TeX driver (unfortunately). In % particular, TeX bitmap fonts that are defined and have characters % added on the fly are almost impossible to deal with reliably in this % distillery approach. %%BeginProcSet: originals 0.5 % This dictionary contains the original definitions of native operators % that have been redefined by the Distillery. They are needed on % occasion to permit the original program to execute operators without % having the results distilled. The motivating factor for this is % user-defined fonts, which "draw" into the font cache, but the effects % are not wanted in the output file. % % This also serves as a list of the redbook operators that are redefined % by the distillery code. mark /show /widthshow /ashow /awidthshow /kshow /fill /eofill /stroke /clip /image /imagemask /showpage /pathbbox /save /restore /gsave /grestore /charpath /newpath /definefont /flushfile /= /print counttomark dup dict begin { dup load def } repeat /originals currentdict end def %%EndProcSet: originals 0.5 %%BeginProcSet: distill_defs 1.0 0 /setpacking where { pop currentpacking true setpacking } if /firstmtx matrix currentmatrix def /bdef { bind def } bind def /ifnotdef { %def % only does the "def" if the key has not already been defined: 1 index where { pop pop pop }{ def } ifelse } bdef /*flushfile /flushfile load ifnotdef printpages not { %if /showpage { erasepage initgraphics } bind def } if /currentcmykcolor where { pop }{ %else /currentcmykcolor { %def currentrgbcolor 3 { 1 exch sub 3 1 roll } repeat 0 } bind def } ifelse /setpacking where { pop setpacking } if %%EndProcSet %%BeginProcSet: Adobe_staticvar 1.0 0 % this procedure set implements the "magic" stuff to hide numbers % and other things where they will not be subject to save/restore /magicval { 8 string } bdef /hideval { %def % /name int : % "hideval" uses save/restore bug! exch load dup 0 (\040\040\040\040\040\040\040\040) putinterval exch (\040\040\040\040\040\040\040\040) cvs dup length 8 exch sub exch putinterval } bdef /magicbool { 5 string } bdef /hidebool { %def % /name int : % "hideval" uses save/restore bug! exch load dup 0 (\040\040\040\040\040) putinterval exch (\040\040\040\040\040) cvs 0 exch putinterval } bdef /cvnum { cvx exec } bdef % makes hidden val back into an integer /cvbool { cvx exec } bdef % makes hidden val back into a boolean /hidefontname { %def % hides a font name in a string body, for use in %%DocumentFonts scratch cvs % look to see if it is already in the docfonts string: % lots of hacks to search for (FontName\n), not just (FontName) save % cause we're using memory for temporary string adobe_distill begin 1 index length 1 add string /tmpstring exch def tmpstring dup length 1 sub (\040) 0 get put tmpstring 0 3 index putinterval pagefonts tmpstring search {pop pop pop false}{pop true} ifelse docfonts tmpstring search {pop pop pop false}{pop true}ifelse end 3 -1 roll restore % roll save object past booleans % first deal with docfonts, then with pagefonts booleans { %ifelse exch % extra boolean for page fonts dup dfontcount cvnum 1 index length add 1 add docfonts length lt { dup docfonts exch dfontcount cvnum exch putinterval length 1 add dfontcount cvnum add /dfontcount exch hideval docfonts dfontcount cvnum 1 sub (\040) putinterval }{ %else pop (% No more room for fonts in document font list\n) d= } ifelse messages { %if (document fonts: ) pr= docfonts 0 dfontcount cvnum getinterval d= flush } if exch % page font boolean still on stack, under "dup"ed string }{ } ifelse { %ifelse pfontcount cvnum 1 index length add 1 add pagefonts length lt { dup pagefonts exch pfontcount cvnum exch putinterval length 1 add pfontcount cvnum add /pfontcount exch hideval pagefonts pfontcount cvnum 1 sub (\040) putinterval }{ %else pop (% No more room for fonts in page font list\n) d= } ifelse messages { %if (page fonts: ) pr= pagefonts 0 pfontcount cvnum getinterval d= flush } if }{ pop } ifelse } bdef %%EndProcSet: Adobe_staticvar 1.0 0 %%BeginProcSet: distill 1.0 0 /setpacking where { pop currentpacking true setpacking } if /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse % some variables % magic variables depending on "hideval", not subject to save/restore /pagecount magicval def /pagecount 1 hideval /beginsetup magicbool def /beginsetup true hidebool /lastshowpage magicbool def /lastshowpage false hidebool /begunpage magicbool def /begunpage false hidebool /?distilling magicbool def /?distilling true hidebool /dfontcount magicval def /dfontcount 0 hideval /pfontcount magicval def /pfontcount 0 hideval /docfonts 40 30 mul string def % room for 40 30-byte font names /pagefonts 40 30 mul string def % room for 40 30-byte font names /LLx magicval def /LLx 10000 hideval /LLy magicval def /LLy 10000 hideval /URx magicval def /URx -10000 hideval /URy magicval def /URy -10000 hideval /docLLx magicval def /docLLx 10000 hideval /docLLy magicval def /docLLy 10000 hideval /docURx magicval def /docURx -10000 hideval /docURy magicval def /docURy -10000 hideval /optim optimize def /scratch 128 string def /fontcount 0 def /indentlevel 0 def /ANYtype null def /insideproc false def /Dfont null def /Ffont null def /Fname null def /lastshow false def /imageproc null def /imagematrix null def /imagedepth null def /imageheight null def /imagewidth null def /unames 120 dict def % for keeping track of user-defined names % a few of them go into userdict: /cvp { messages { % ifelse ( ) cvs pr= (\040) pr= }{ pop } ifelse } bdef /pr= { messages { rprint }{ pop } ifelse } bdef /d= { messages { r= }{ pop } ifelse } bdef /distill { adobe_distill begin debug{(%!PS-Adobe-2.1 debug version ) rprint adobe_still_version == }if userdict /orig_dictcount countdictstack put count 0 eq { %ifelse /OUTfile (%stdin) def /fd (%stdout) (w) file def initstill writeprologue initgstate currentfile cvx exec writetrailer }{ %else initgraphics /saveall save def /INfile exch def /OUTfile INfile length 1 add string def OUTfile 0 INfile putinterval OUTfile dup length 1 sub (x) 0 get put trace { (output file: ) rprint OUTfile == } if /outfile OUTfile (w) file def /fd /outfile load def initstill writeprologue initgstate debug { %ifelse INfile run }{ % else { INfile run } stopped { % if errordict begin $error begin (\n%%[Error: ) wout /errorname load =string cvs wout (; OffendingCommand: ) wout /command load =string cvs wout (]%%) wout writeNL (STACK:) writeop /ostack load type /arraytype eq { ostack { =string cvs writeop } forall } if fd systemdict /flushfile get exec handleerror end end } if } ifelse writetrailer fd closefile countdictstack orig_dictcount sub { end } repeat clear saveall { restore } stopped { %if trace { (couldn't restore after distill.) r= } if } if } ifelse end } bdef % the rest of them go in "adobe_distill" adobe_distill begin /setdistill { %def /?distilling exch hidebool } bdef /initstill { %def /beginsetup true hidebool /lastshowpage false hidebool /begunpage false hidebool /pagecount 1 hideval /STDvec 0 hideval /PAGEvec 0 hideval /dfontcount 0 hideval /pfontcount 0 hideval /LLx 10000 hideval /LLy 10000 hideval /URx -10000 hideval /URy -10000 hideval /docLLx 10000 hideval /docLLy 10000 hideval /docURx -10000 hideval /docURy -10000 hideval /SharedFontDirectory where { %ifelse /SharedFontDirectory get }{ /FontDirectory load } ifelse /FontDirectory exch def 0 1 pagefonts length 1 sub { pagefonts exch 0 put } for 0 1 docfonts length 1 sub { docfonts exch 0 put } for } bdef debug { %if /BB { debug { (% BBox: ) pr= LLx pr= ( ) pr= LLy pr= ( ) pr= URx pr= ( ) pr= URy pr= (\n) pr= flush (% DocBBox: ) pr= docLLx pr= ( ) pr= docLLy pr= ( ) pr= docURx pr= ( ) pr= docURy pr= () r= flush } if } bdef } if /?box { %def % X Y dup URy cvnum gt { dup /URy exch cvi hideval } if dup LLy cvnum lt { dup /LLy exch cvi hideval } if pop dup URx cvnum gt { dup /URx exch cvi hideval } if dup LLx cvnum lt { dup /LLx exch cvi hideval } if pop } bdef /doc?box { dup docURy cvnum gt { dup /docURy exch cvi hideval } if dup docLLy cvnum lt { dup /docLLy exch cvi hideval } if pop dup docURx cvnum gt { dup /docURx exch cvi hideval } if dup docLLx cvnum lt { dup /docLLx exch cvi hideval } if pop } bdef /pageBBox-docBBox { LLx cvnum LLy cvnum doc?box URx cvnum URy cvnum doc?box } bdef /writeRmove { %def 2 copy lineY sub exch lineX sub exch dup 0.0 eq { pop writenum (x) writeop }{ %ifelse 1 index 0.0 eq { writenum (y) writeop pop }{ %ifelse writepair (r) writeop } ifelse } ifelse 2 copy ?box /lineY exch store /lineX exch store } bdef /writelines { %def counttomark REPEAT_LINETO_THRESHOLD gt { % ifelse counttomark /lcount exch store lcount -2 2 { %for dup /rcount exch store -2 roll 2 copy lineY sub exch lineX sub exch 4 -2 roll 2 copy ?box /lineY exch store /lineX exch store rcount 2 roll } for lcount 2 idiv { writepair writeNL } repeat lcount 2 idiv writenum (R) writeop }{ % else counttomark -2 2 { -2 roll writeRmove } for } ifelse } bdef /writepath { /closed false store % optimize special case of just "moveto lineto stroke" mark % pathforall { counttomark 2 gt { cleartomark false exit } if thruCTM true } { counttomark 5 gt { cleartomark false exit } if thruCTM true } { cleartomark false exit } { cleartomark false exit } pathforall { %ifelse counttomark 5 ne { %ifelse % degenerate case... ischarpath counttomark 2 eq and { % just moveto 2 copy ?box writepair (m) writeop } if cleartomark }{ %else 3 -1 roll pop /?simplepath true store simplepath astore pop pop %mark } ifelse }{ %else /?simplepath false store mark { % moveto closed { (cp ) wout /closed false store } if counttomark 2 gt { %if counttomark 1 add 2 roll writelines 3 1 roll } if 2 copy thruCTM /lineY exch store /lineX exch store /closeX lineX store /closeY lineY store 2 copy ?box writeTpair (m) writeop } % moveto proc { %lineto proc thruCTM count 490 gt { writelines } if } % lineto { % curveto counttomark 6 gt { %if counttomark 1 add 6 roll writelines 7 1 roll } if 2 copy thruCTM /lineY exch store /lineX exch store 3 { %repeat 6 -2 roll 2 copy thruCTM 2 copy ?box exch writenum writenum } repeat (c) writeop 6 {pop} repeat } % curveto { % closepath counttomark 0 gt { writelines } if /closed true store /lineX closeX store /lineY closeY store } % closepath pathforall counttomark 0 gt { writelines } if pop %mark } ifelse } bdef /hashpath { %def % manufacture a [fairly] unique integer to represent a path: -1 % initial value { .5 add add 2 div add } % moveto { add sub } % lineto { add add sub add add add } % curveto { 1 add } % closepath pathforall dup 100 lt { 10 mul truncate 10 div } if } bdef /hashencoding { %def % manufacture a [fairly] unique integer for an encoding vector, % by alternately adding then subtracting the length of the name. % The alternation makes reordered lists with same names still come out % with a different hash value (the "-1 exch" and the "mul" do this) -1 exch 0 exch % initial value: 0 { % forall dup type /nametype eq { length }{ pop 1 } ifelse 2 index mul add % multiply by 1 or -1 and add exch -1 mul exch % flip 1 and -1 } forall exch pop % get rid of -1, leave hash val } bdef /STDvec magicval def /STDvec 0 hideval /PAGEvec magicval def /PAGEvec 0 hideval /enc1 null def /enc2 null def /diffencoding { %def % check the "top128" boolean to see if it's worth reencoding them /enc2 exch store /enc1 exch store % enc2 is the new one [ 32 1 127 { %for % 0 1 255 ?? dup dup enc2 exch get exch enc1 exch get 1 index eq { pop pop } if } for ] } bdef /indent { indentlevel { fd ( ) writestring } repeat } bdef /++ { dup load 1 add store } bdef /-- { dup load dup 1 ge { 1 sub } if store } bdef end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet %%BeginProcSet: distill_writetofile 1.0 0 /setpacking where { pop currentpacking true setpacking } if /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse adobe_distill begin /writetrailer { %def % : stackptr 0 ne { stackshow } if begunpage cvbool { %if lastshowpage cvbool not { %if ( /showpage {} def) writeop } if pagecount cvnum scratch cvs wout ( ENDPAGE\n) wout (%%PageTrailer) writeop (%%PageFonts: ) wout pfontcount cvnum 0 eq { writeNL }{ %else pfontcount cvnum 200 lt { %ifelse pagefonts 0 pfontcount cvnum getinterval writeop }{ %else pagefonts (\040) search not { writeop }{ %else writeop % first one without the %%+ { %loop search { (%%+ ) wout writeop }{ %else (\000) search { writeop pop pop }{ pop } ifelse exit } ifelse } loop } ifelse } ifelse 0 1 pfontcount cvnum { pagefonts exch 0 put } for /pfontcount 0 hideval } ifelse LLx 10000 eq LLy 10000 eq or URx -10000 eq URy -10000 eq or or not { (%%PageBoundingBox: ) wout LLx cvnum writenum LLy cvnum writenum URx cvnum writenum URy cvnum writenum writeNL } if pageBBox-docBBox } if (%%Trailer) writeop (end %PROLOGUE) writeop (%%Pages: ) wout pagecount cvnum writenum writeNL (%%BoundingBox: ) wout docLLx cvnum writenum docLLy cvnum writenum docURx cvnum writenum docURy cvnum writenum writeNL (%%DocumentFonts: ) wout dfontcount cvnum 0 eq { writeNL }{ %else dfontcount cvnum 200 lt { %ifelse docfonts 0 dfontcount cvnum getinterval writeop }{ %else docfonts (\040) search not { writeop }{ %else writeop % first one without the %%+ { %loop search { (%%+ ) wout writeop }{ %else (\000) search { writeop pop pop }{ pop } ifelse exit } ifelse } loop } ifelse } ifelse } ifelse (%%EOF) writeop } bdef /writecomments { %def fd (%!PS-Adobe-2.1\n) writestring fd (%%Title: ) writestring fd OUTfile writestring fd (\n) writestring fd (%%Creator: Glenn Reid and still.ps ) writestring fd adobe_still_version writestring fd (\n) writestring fd (%%BoundingBox: (atend)\n) writestring fd (%%Pages: (atend)\n) writestring includeprologue { %ifelse fd (%%DocumentProcSets: Adobe_distill 0.95\n) writestring }{ %else fd (%%DocumentNeededProcSets: Adobe_distill 0.95\n) writestring } ifelse fd (%%EndComments\n) writestring } bdef /writeprologue { %def % : writecomments includeprologue { %ifelse mark (%%BeginProcSet: Adobe_distill 0.95) (/PROLOGUE 30 40 add dict def) ( % 30 procedure entries + room for 40 cached font dictionaries) ( PROLOGUE begin) ( /clip { } def % causes problems. remove if "clip" is needed) ( /bdef { bind def } bind def /ldef { load def } bdef) ( /T { moveto show } bdef /A { moveto ashow } bdef) ( /W { moveto widthshow } bdef /AW { moveto awidthshow } bdef) ( /f /fill ldef /R { { rlineto } repeat } bdef) ( /r /rlineto ldef /L { { lineto } repeat } bdef) ( /m /moveto ldef /l { moveto lineto stroke } bdef) ( /x { 0 rlineto } bdef /y { 0 exch rlineto } bdef) ( /c /curveto ldef /cp /closepath ldef) ( /s /stroke ldef /w /setlinewidth ldef) ( /g /setgray ldef /j /setlinejoin ldef) ( /d /setdash ldef /F /setfont ldef) ( /C /setcmykcolor where { /setcmykcolor get }{ %ifelse) ( { %def) ( 1 sub 3 { 3 index add neg dup 0 lt { pop 0 } if 3 1 roll } repeat) ( setrgbcolor) ( } bind) ( } ifelse def) ( /MF { findfont exch makefont setfont } bdef) ( /DF { findfont exch scalefont setfont currentfont def } bdef) ( /BEGINPAGE { pop /pagesave save def } bdef) ( /ENDPAGE { pop pagesave restore showpage } def) ( /REMAP { %def) ( FontDirectory 2 index known { pop pop pop } { %ifelse) ( findfont dup length dict begin) ( { 1 index /FID ne {def}{pop pop} ifelse } forall) ( exch dup length 0 gt { /Encoding exch def }{ pop } ifelse) ( currentdict end definefont pop) ( } ifelse) ( } bdef) ( /RECODE { %def) ( 3 -1 roll 1 index findfont /Encoding get 256 array copy exch) ( 0 exch { %forall) ( dup type/nametype eq) ( { 3 {2 index} repeat put pop 1 add }{ exch pop }ifelse) ( } forall pop 3 1 roll REMAP) ( } bdef) ( end %PROLOGUE) (%%EndProcSet: Adobe_distill 0.95) % write all the above strings to the output file: counttomark -1 1 { %for -1 roll fd exch writestring fd (\n) writestring } for fd systemdict /flushfile get exec pop %mark }{ %else (%%IncludeProcSet: Adobe_distill 0.95\n) fd exch writestring } ifelse fd (%%EndProlog\n) writestring fd (%%BeginSetup\n) writestring fd (PROLOGUE begin\n) writestring } bdef /checksetup { %def % called from "fontstate", "graphicstate", and "definefont" beginsetup cvbool { /beginsetup false hidebool fd (\n%%EndSetup\n%%Page: 1 1\n) writestring fd (%%PageFonts: (atend)\n) writestring fd (%%PageBoundingBox: (atend)\n) writestring fd (1 BEGINPAGE\n) writestring /begunpage true hidebool /fontcount 0 store }{ %else lastshowpage cvbool { %if /lastshowpage false hidebool /fontcount 0 store writeNL (%%Page: ) wout trace { (page: ) rprint pagecount cvnum == flush } if /pagecount pagecount cvnum 1 add hideval pagecount cvnum dup writenum writenum writeNL (%%PageFonts: (atend)) writeop (%%PageBoundingBox: (atend)) writeop pagecount cvnum scratch cvs wout ( BEGINPAGE\n) wout /begunpage true hidebool % invalidate all remapped fonts, for page independence FontDirectory { %forall exch pop dup /FontInfo known { %ifelse /FontInfo get dup /pleasemap known { %ifelse begin (Glenn Reid) pleasemap cvbool not { /pleasemap true hidebool } if pop end }{ pop } ifelse }{ pop } ifelse } forall % forcegstate } if } ifelse } bdef /writenamearray { % [ /name ... ] : fd ([) writestring /indentlevel ++ fd (\n) writestring indent /CNT 1 store %| maintain CNT to count bytes. wrap lines at a reasonable %| place when writing out character names, to avoid long lines { %forall fd (/) writestring dup type /nametype eq { scratch cvs }{ pop (.notdef) } ifelse dup length 1 add CNT add /CNT exch store fd exch writestring CNT 60 ge { /CNT 1 store fd (\n) writestring indent } if } forall /indentlevel -- fd (\n) writestring indent fd (]) writestring } bdef /writediffencoding { % [ 32/name 37/etc ... ] : fd ([) writestring /indentlevel ++ fd (\n) writestring indent /CNT 1 store %| maintain CNT to count bytes. wrap lines at a reasonable %| place when writing out character names, to avoid long lines { %forall dup type /integertype eq { %ifelse fd (\040) writestring scratch cvs fd exch writestring /CNT CNT 4 add store }{ %else fd (/) writestring dup type /nametype eq { scratch cvs }{ pop (.notdef) } ifelse dup length 1 add CNT add /CNT exch store fd exch writestring } ifelse CNT 60 ge { /CNT 1 store fd (\n) writestring indent } if } forall /indentlevel -- fd (\n) writestring indent fd (]) writestring } bdef % write numbers in various formats: /thruCTM { CTM transform } bdef /dthruCTM { CTM dtransform } bdef /XthruCTM { %def dup CTM dtransform rot not { pop }{ %else 2 copy gt { pop }{ exch pop } ifelse } ifelse } bdef /*writestring { %def writestring fd *flushfile } bdef /shave { %def % eliminate significant digits beyond .001; compensate for roundoff dup type /realtype eq { %if 1000 mul truncate 1000 div } if } bdef /writenum { % def % num : dup abs 0.001 le { pop 0 } if % --> 0 dup dup cvi eq { cvi } if fd exch scratch cvs writestring _space } bdef /writeprecisenum { % def % num : fd exch scratch cvs writestring _space } bdef /writeXnum { % def % num : CTM 0 get mul writenum } bdef /writeYnum { % def % num : CTM 3 get mul writenum } bdef /writeTpair { % def % num1 num2 : thruCTM exch writenum writenum } bdef /writepair { % def % num1 num2 : exch writenum writenum } bdef /writenumarray { % [ nums ] : fd ([) writestring { writenum } forall fd (] ) writestring } bdef % write out names and strings: /rprint /print load def /r= /= load def /print { fd exch writestring } bind def /= { scratch cvs fd exch writestring writeNL } bind def /writeNL { fd (\n) writestring } bdef /_space { fd (\040) writestring } bdef /wout { % def % (string) : fd exch writestring } bdef /writestr { % def % (string) : fd exch writestring _space } bdef /writeop { %def % (string) : fd exch writestring writeNL } bdef /writePSstring { % def % (string) : fd (\() writestring dup length 75 gt exch wordfix fd (\) ) writestring { writeNL } if % if length > 75 bytes } bdef /writename { % def % name : scratch cvs fd exch writestring _space } bdef /writeRname { % def % name : (/) wout scratch cvs wout (R ) wout } bdef /checkusernames { %def % array : { % forall dup type /nametype ne { pop }{ %ifelse dup systemdict exch known { pop }{ % ifelse dup xcheck not { pop }{ %ifelse dup unames exch known { pop }{ %ifelse dup where not { %ifelse dup unames exch true put pop % assume it's taken care of }{ %else pop dup load dup type /arraytype eq 1 index type /packedarraytype eq or { checkusernames }{ pop } ifelse indent (userdict /) wout dup writename dup unames exch true put load writeANY (put) writeop indent } ifelse } ifelse } ifelse } ifelse } ifelse } forall } bdef /arrayusernames { %def dup type /arraytype eq 1 index type /packedarraytype eq or { %ifelse dup checkusernames { arrayusernames } forall }{ pop } ifelse } bdef /writeproc { %def ({) writestr insideproc exch /insideproc true store dup type /arraytype eq 1 index type /packedarraytype eq or { % ifelse dup length 20 lt { %ifelse { writeANY } forall }{ %else writeNL /indentlevel ++ indent { writeANY writeNL indent } forall /indentlevel -- writeNL indent } ifelse }{ %else writename } ifelse /insideproc exch store (} ) writestr } bdef /typedict 12 dict def typedict begin /stringtype { dup 0 get 0 eq 1 index dup length 1 sub get 0 eq or { (<) wout fd exch writehexstring (> ) wout }{ writePSstring } ifelse } bdef /arraytype { %def % dup checkusernames dup xcheck { %ifelse writeproc }{ %else /CNT 1 store dup length 20 lt { %ifelse ([ ) wout { writeANY } forall (] ) wout }{ %else ([) writeop /indentlevel ++ { indent writeANY writeNL } forall /indentlevel -- indent (] ) wout } ifelse } ifelse } bdef /packedarraytype /arraytype load def /dicttype { %def % safety: 1 add (needed for User Fonts) dup maxlength 1 add writenum (dict begin) writeop indent { %forall exch writeANY writeANY (def ) writeop indent } forall (currentdict end ) wout } bdef /integertype { writenum } def /realtype { writenum } def /nulltype { pop (null ) wout } def /operatortype { %def insideproc { %ifelse writename }{ %else (/) wout writename (load) writestr } ifelse } bdef /nametype { %def dup xcheck not { (/) wout dup unames exch true put } if writename } bdef end % typedict /writeANY { %def dup type dup typedict exch known { %ifelse typedict exch get exec }{ %else pop writename } ifelse } bdef % The following writes an escaped string that may contain special chars. % It regenerates the (\035string) notation. /wordfix { %def % (string) : (\() search { %ifelse rparenfix (\\\() wout pop wordfix }{ rparenfix } ifelse } bdef /rparenfix { %def (\)) search { %ifelse binaryfix (\\\)) wout pop rparenfix }{ binaryfix } ifelse } bdef /str1 1 string def /longstr 1028 string def /writetomark { %def counttomark -1 0 { %for longstr exch exch put } for } bdef /binaryfix { %def dup false exch { %forall dup 128 gt 1 index 32 lt or { %ifelse str1 exch 0 exch put pop true exit }{ pop } ifelse } forall { %ifelse % depending on whether num>128 was found str1 search { quotefix % string previous to num>128 (\\) wout % the backslash % write suspicious char as octal 0 get 8 scratch cvrs % padding with leading 0 as needed dup length 3 exch sub { (0) wout } repeat wout binaryfix % recurse on rest of string }{ (ERROR: search lied in "binaryfix".) r= flush stop } ifelse }{ quotefix } ifelse } bdef /quotefix { %def (\\) search { %ifelse wout (\\\\) wout pop quotefix }{ wout } ifelse } bdef end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet %%BeginProcSet: distill_graphicstate 1.0 0 % we don't want packed arrays for all these matrices; set packing later /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse adobe_distill begin % define a bunch of state variables, then use "store" subsequently % to write into them (to avoid currentdict problems). /mtx matrix def /tmpmtx matrix def /fontmtx matrix def /curfontmtx matrix def /CTM matrix currentmatrix def /normalCTM tmpmtx currentmatrix matrix invertmatrix def /compareCTM matrix currentmatrix def /newCTM matrix def /mtx1 0 def /mtx2 0 def /$normalize { dup tmpmtx copy normalCTM 3 -1 roll concatmatrix } bind def /rot false def /gray currentgray def currentcmykcolor /colK exch def /colY exch def /colM exch def /colC exch def /linewidth currentlinewidth def /linecap currentlinecap def /linejoin currentlinejoin def /miterlimit currentmiterlimit def /screenang null def /screenfreq null def /screenproc null def /closed false def currentdash /dashoff exch def /dasharray exch def /pointX -1 def /pointY -1 def /initfontscale { 1 0 0 1 0 0 $fontscale astore pop } bind def /$fontscale matrix def /0a 0 def /0b 0 def /X1 0 def /X2 0 def /origfontname null def /currfontdict null def /definefontname null def /tempfontname /Courier def % /defaultfontname substitutefonts { /Courier }{ /Unknown } ifelse def /defaultfontname { /FontType where { %ifelse pop FontType 3 eq { FontInfo /realname get }{ substitutefonts { /Courier }{ /Unknown } ifelse } ifelse }{ %else substitutefonts { /Courier }{ /Unknown } ifelse } ifelse } def /ischarpath false def /currpath newpath hashpath def /pathstr () def /pathbool false def /pathX 0 def /pathY 0 def /lineX 0 def /lineY 0 def /closeX 0 def /closeY 0 def /lcount 0 def /rcount 0 def /REPEAT_LINETO_THRESHOLD 20 def % point at which repeat loop is used /currX -1 def /currY -1 def /diffX 0 def /gstates 0 def /charpathgstate 0 def /CNT 0 def /showX null def /showY null def /currfont currentfont def /cliphash newpath hashpath def /?simplepath false def /simplepath [ 0 0 0 0 ] def /setpacking where { pop currentpacking true setpacking } if /matrixeq { %def % compares two matrices /mtx2 exch store /mtx1 exch store 0 1 5 { %for dup mtx1 exch get exch mtx2 exch get eq } for 5 { and } repeat } bdef % procedure definitions for state machinery --------------- /initgstate { %def gsave initgraphics /CTM mtx currentmatrix $normalize store tmpmtx currentmatrix compareCTM matrixeq not { .345 dup 0 dtransform pop 0 idtransform pop ne dup /rot exch store not optimize and /optim exch store } if compareCTM currentmatrix pop /gray currentgray store currentcmykcolor /colK exch store /colY exch store /colM exch store /colC exch store /linewidth currentlinewidth XthruCTM store /linecap currentlinecap store /linejoin currentlinejoin store /miterlimit currentmiterlimit store currentdash /dashoff exch store /dasharray exch store /origfontname /InvalidFont store /definefontname /InvalidFont store initfontscale /currfontdict currentfont store currentscreen /screenproc exch store /screenang exch store /screenfreq exch store /cliphash clippath hashpath store % Wed Dec 28 12:41:07 1988 grestore } bdef % initgstate /forcegstate { %def % after save & restore, you may have to explicitly "undo" anything % that was done within the saved context. Since save & restore % affect all our state variables, we dump anything that is different % from the default graphics state: /CTM [1.01 0 1.01 0 .5 .5] store /compareCTM [1.01 0 1.01 0 .5 .5] store initfontscale /currfontdict null store /gray null store /colC null store % checkgstate % fontstate } bdef % initgstate /checkgstate { %def graphicstate fontstate } def %checkgstate /checkCTM { %def tmpmtx currentmatrix compareCTM matrixeq not { % /CTM mtx currentmatrix $normalize store CTM currentmatrix $normalize pop compareCTM currentmatrix $normalize pop .345 dup 0 dtransform pop 0 idtransform pop ne dup /rot exch store not optimize and /optim exch store } if } bdef /generalstate { %def stackptr 0 ne { stackshow } if /lastshow false store checkCTM } bdef % generalstate /colorstate { %def mark currentcmykcolor colC colM colY colK 4 { %repeat dup 5 index ne 10 1 roll 8 1 roll } repeat cleartomark or or or { currentcmykcolor /colK exch store /colY exch store /colM exch store /colC exch store colC 0 eq colM 0 eq colY 0 eq and and not { %ifelse % COLOR colC writenum colM writenum colY writenum colK writenum (C) writeop }{ %else % GRAY 1 colK sub shave writenum (g) writeop } ifelse } if } bdef % colorstate /registerfont { %def dup cachedir exch 20 dict put % allow 20 point sizes cachedir exch get % ptsize dict exch fontcount put } bdef /addfontsize { %def cachedir exch get exch fontcount put } bdef /fontstate { %def currentfont null eq not { %if currentfont dup /ScaleMatrix known not { pop }{ %ifelse begin % determine if anything has changed: tmpmtx currentmatrix compareCTM matrixeq not currfontdict currentfont ne or ScaleMatrix CTM tmpmtx concatmatrix $fontscale matrixeq not or { %if % get and set new font names /origfontname /FontInfo where { %ifelse pop FontInfo /realname known { FontInfo /realname get }{ % ifelse /FontName where { pop FontName }{ defaultfontname } ifelse } ifelse }{ %else /FontName where { pop FontName }{ defaultfontname } ifelse } ifelse store /definefontname /FontName where { pop FontName }{ defaultfontname } ifelse FontDirectory { %forall currentdict eq { exch pop exit } { pop } ifelse } forall store origfontname hidefontname % check for font reencoding: % The current font is the one required in the distilled % program. If it is a reeconded font, we must generate % a call to "REMAP", but at the same time let's mark it % so we don't generate too may "REMAP" calls. checksetup generalstate colorstate % worry about reencoding: /FontInfo where { %ifelse pop FontInfo /pleasemap known { %ifelse FontInfo /pleasemap get cvbool }{ %else false % evidently has not been reencoded... } ifelse % leaves a boolean }{ false } ifelse { % if remapping has not been done yet: Encoding hashencoding origfontname findfont /Encoding get hashencoding ne { %ifelse Encoding hashencoding STDvec cvnum eq { %ifelse (stdvec) writestr origfontname writeRname origfontname (/) wout writename ( REMAP) writeop }{ %else Encoding hashencoding PAGEvec cvnum eq { (pagevec) writestr origfontname writeRname origfontname (/) wout writename ( REMAP) writeop }{ %else origfontname findfont /Encoding get Encoding diffencoding writediffencoding origfontname writeRname origfontname (/) wout writename ( RECODE) writeop } ifelse } ifelse /FontInfo where { %if pop FontInfo /pleasemap known { %if FontInfo begin /pleasemap false hidebool end } if } if } if } if % /pleasemap % check font scale change: % This stuff is absolutely horrible.... ScaleMatrix CTM $fontscale concatmatrix aload pop % Xscale 0a 0b Yscale 0 0 pop pop 3 1 roll % X Y 0b 0a % if 0a and 0b are really both 0 ... % and X Y are equal and positive, then you can use % "scalefont", else you have to use "makefont" /0a exch store /0b exch store /X1 exch store /X2 exch store X1 X2 % leave on stack 0a 0b eq 0b 0 eq and % make sure 0's are 0 X1 X2 EQ and % X1 and X2 are equal X1 dup abs eq X2 dup abs eq and % and positive and { %ifelse pop dup dup round EQ { round } if % if you find it in the "font dict cache".... cachedir definefontname known { %ifelse cachedir definefontname get dup 2 index known { exch get (F) wout writenum (F) writeop }{ %else pop /fontcount ++ dup definefontname addfontsize (/F) wout fontcount writenum %+ cvnum writenum writenum origfontname /FontInfo where { %ifelse pop FontInfo /pleasemap known { %ifelse FontInfo /pleasemap get cvbool }{ false } ifelse % leaves a boolean }{ false } ifelse Encoding hashencoding origfontname findfont /Encoding get hashencoding ne and { %ifelse writeRname }{ (/) wout writename } ifelse (DF) writeop } ifelse }{ %else if you DON'T find the name in the cache /fontcount ++ dup definefontname registerfont (/F) wout fontcount writenum writenum origfontname /FontInfo where { %ifelse pop FontInfo /pleasemap known { %ifelse FontInfo /pleasemap get cvbool not }{ false } ifelse % leaves a boolean }{ false } ifelse Encoding hashencoding origfontname findfont /Encoding get hashencoding ne and { %ifelse writeRname }{ (/) wout writename } ifelse (DF) writeop } ifelse }{ %else % need either "makefont" or rotated coordinate system pop pop $fontscale aload pop curfontmtx astore dup 4 ScaleMatrix 4 get put dup 5 ScaleMatrix 5 get put % no translate writenumarray origfontname /FontInfo where { pop FontInfo /pleasemap known }{ false } ifelse { %ifelse writeRname }{ (/) wout writename } ifelse (MF) writeop } ifelse /currfontdict currentfont store } if % anything has changed end } ifelse beginsetup cvbool not { generalstate colorstate } if } if } bdef %fontstate /graphicstate { %def checksetup generalstate colorstate linewidth currentlinewidth XthruCTM ne { /linewidth currentlinewidth XthruCTM store linewidth shave writenum (w) writeop } if linecap currentlinecap ne { /linecap currentlinecap store linecap writenum (setlinecap) writeop } if linejoin currentlinejoin ne { /linejoin currentlinejoin store linejoin writenum (j) writeop } if miterlimit currentmiterlimit ne { /miterlimit currentmiterlimit store miterlimit shave writenum (setmiterlimit) writeop } if currentdash dashoff ne exch dasharray ne or { currentdash /dashoff exch store /dasharray exch store fd ([) writestring dasharray { XthruCTM writenum } forall fd (] ) writestring dashoff XthruCTM writenum (d) writeop } if gsave % don't clip to degenerate paths of any kind: newpath clippath hashpath cliphash ne { %if mark { pathbbox } stopped not { exch 4 -1 roll sub abs 1 gt 3 1 roll sub abs 1 gt and { % if writepath (clip newpath) writeop /cliphash hashpath store } if } if cleartomark } if grestore currentscreen /screenproc load ne exch screenang ne or exch screenfreq ne or { %if currentscreen /screenproc exch store /screenang exch store /screenfreq exch store screenfreq writenum screenang writenum writeNL /screenproc load dup type /arraytype eq 1 index type /packedarraytype eq or { %ifelse checkusernames }{ pop } ifelse /screenproc load writeproc (setscreen) writeop } if } bdef %graphicstate end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet %%BeginProcSet: distill_optimize 1.0 0 /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse adobe_distill begin % These procedures implement an optimization scheme for recognizing % sequences of "show" operations that could be optimized into calls % to "widthshow" (or just "show" with a longer string body). In % order to accomplish this, we have implemented a stack to store % string bodies until they are flushed by a font change, a change % in Y coordinate, or an inter-string space that is inconsistent. % When comparing coordinates for equality, anything with the given % tolerance is accepted as being equal (to combat roundoff error). /tolerance .05 ifnotdef /EQ { sub abs tolerance le } bdef /stack 250 array def /stackptr 0 def /setpacking where { pop currentpacking true setpacking } if /push { %def stackptr 0 eq { % if currentpoint thruCTM /showY exch store /showX exch store } if /stackptr stackptr 1 add store stackptr 249 ge { (STACK OVERFLOW!) r= flush exit } if stack stackptr 3 -1 roll put } bdef /pull { %def stack stackptr get /stackptr stackptr dup 0 gt { 1 sub } if store } bdef /*save systemdict /save get def /save { % def stackshow % in case there's anything pending.... *save } bdef /*restore systemdict /restore get def /restore { % def % after save & restore, you may have to explicitly "undo" anything % that was done within the saved context. Since save & restore % affect all distillery state variables, we dump anything different % from the default graphics state: stackshow % in case there's anything pending.... currentlinecap % 5 currentlinewidth % 4 currentgray % 3 currentmiterlimit % 2 currentlinejoin % 1 6 -1 roll *restore setlinejoin % 1 setmiterlimit % 2 setgray % 3 setlinewidth % 4 setlinecap % 5 forcegstate % checkgstate %graphicstate } bdef /stackshow { %def stackptr 0 ne { %if messages { (stackshow: ) d= 1 1 stackptr { ( ) pr= stack exch get == } for } if % currfont /FontType known { % currfont /FontType get 3 eq { % ?distilling false setdistill % } if % } if stackptr 1 eq { %ifelse %- if there is only one string, use "show": pull writePSstring showX showY writepair (T) writeop }{ %else %- otherwise, build single string (with \b to use W): diffX 0 EQ not { % if gsave % figure out widthshow value currfont setfont diffX (\b) stringwidth CTM dtransform pop sub grestore writenum (0) writestr (\b) 0 get writenum (\\b) % padding character }{ % else () % empty padding character } ifelse (\() wout 1 1 stackptr 1 sub { % for stack exch get wordfix dup wout } for pop % padding character pull wordfix (\)) wout writeNL showX showY writepair %- if diffX is 0, don't use "widthshow": diffX 0 EQ { (T) }{ (W) } ifelse writeop } ifelse /stackptr 0 store % currfont /FontType known { % currfont /FontType get 3 eq { setdistill } if % } if } if } bdef /setcurrpoint { %def currentpoint thruCTM /currY exch store /currX exch store } bdef % setcurrpoint end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet %%BeginProcSet: distill_paintops 1.0 0 /setpacking where { pop currentpacking true setpacking } if /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse adobe_distill begin % text operators /sameYcoords { %def % this is pulled out of the "show" proc for readability; it is % not used anywhere else currentfont currfont ne { %ifelse stackshow fontstate push }{ %else currentpoint thruCTM pop currX sub dup diffX EQ { %ifelse pop % dup'ed value push }{ %else diffX -1 eq { %ifelse /diffX exch store push }{ % else pop stackshow fontstate /diffX -1 store push } ifelse } ifelse } ifelse } bdef /*stringwidth /stringwidth load def /stringwidth { %def false setdistill *stringwidth true setdistill } bdef /show { %def checkCTM currentpoint thruCTM ?box optim { %ifelse dup length 0 eq { pop } { %ifelse dup % save string for use at the end lastshow not { %ifelse stackshow fontstate /currfont currentfont store push /diffX -1 store }{ % else % don't optimize if matrix is different... tmpmtx currentmatrix compareCTM matrixeq currentpoint thruCTM exch pop currY eq and { %ifelse Y = Y sameYcoords }{ %else currY ne stackshow % flush the pending show stack fontstate push % the string (and set showX, showY) /diffX -1 store } ifelse /currfont currentfont store } ifelse %lastshow currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill show true setdistill }{ show } ifelse }{ false setdistill show true setdistill } ifelse setcurrpoint /lastshow true store } ifelse % if length is not 0 }{ % else dup length 0 eq { pop } { %ifelse fontstate dup writePSstring currentpoint writeTpair (T) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill show true setdistill }{ show } ifelse }{ false setdistill show true setdistill } ifelse } ifelse % if operand is not null string } ifelse currentpoint thruCTM ?box } bdef /widthshow { %def checkCTM currentpoint thruCTM ?box optim { %ifelse dup length 0 eq { 4{pop}repeat } { %ifelse 4 copy pop pop 1 index EQ exch 0.0 EQ and { % ifelse fontstate 4 1 roll pop pop pop show % make sure it's not "bound" }{ %else fontstate 4 copy 4 2 roll dthruCTM writepair %exch writeXnum writeYnum exch writenum writePSstring currentpoint writeTpair (W) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill widthshow true setdistill }{ widthshow } ifelse }{ false setdistill widthshow true setdistill } ifelse } ifelse } ifelse }{ %else % Cx Cy char (string) widthshow dup length 0 eq { 4{pop}repeat } { %ifelse fontstate 4 copy % 4 -2 roll exch writeXnum writeYnum exch writenum 4 -2 roll dthruCTM writepair exch writenum writePSstring currentpoint writeTpair (W) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill widthshow true setdistill }{ widthshow } ifelse }{ false setdistill widthshow true setdistill } ifelse } ifelse } ifelse currentpoint thruCTM ?box } bdef /ashow { %bdef checkCTM currentpoint thruCTM ?box optim { %ifelse dup length 0 eq { pop pop pop } { %ifelse 3 copy pop 1 index EQ exch 0.0 EQ and { % ifelse fontstate 3 1 roll pop pop show % make sure it's not "bound" }{ %else fontstate 3 copy 3 1 roll dthruCTM writepair writePSstring currentpoint writeTpair (A) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill ashow true setdistill }{ ashow } ifelse }{ false setdistill ashow true setdistill } ifelse } ifelse } ifelse }{ %else dup length 0 eq { pop pop pop } { %ifelse fontstate 3 copy 3 1 roll dthruCTM writepair % exch writeXnum writeYnum writePSstring currentpoint writeTpair (A) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill ashow true setdistill }{ ashow } ifelse }{ false setdistill ashow true setdistill } ifelse } ifelse } ifelse currentpoint thruCTM ?box } bdef /awidthshow { %def % Cx Cy 32 Ax Ay (string) awidthshow checkCTM currentpoint thruCTM ?box optim { %def dup length 0 eq { 6{pop}repeat } { %ifelse fontstate 6 copy 6 1 roll 1 index EQ exch 0.0 EQ and { %ifelse 4 1 roll 1 index eq exch 0.0 eq and { %leaves 32 (str) 8 1 roll 7 { pop } repeat show % make sure it's not "bound" }{ %else pop pop 3 1 roll pop pop widthshow % make sure it's not "bound" } ifelse }{ %else pop pop pop pop 6 copy 6 -3 roll pop 1 index EQ exch 0.0 EQ and { % ifelse 9 3 roll 6 { pop } repeat ashow % make sure it's not "bound" }{ %else pop pop pop 6 copy 6 -2 roll dthruCTM writepair 4 -1 roll writenum 3 1 roll dthruCTM writepair writePSstring currentpoint writeTpair (AW) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill awidthshow true setdistill }{ awidthshow } ifelse }{ false setdistill awidthshow true setdistill } ifelse } ifelse } ifelse } ifelse }{ %else dup length 0 eq { 6{pop}repeat } { %ifelse fontstate 6 copy % 6 -2 roll exch writeXnum writeYnum % 4 -1 roll writenum 3 -1 roll writeXnum exch writeYnum 6 -2 roll dthruCTM writepair 4 -1 roll writenum 3 1 roll dthruCTM writepair writePSstring currentpoint writeTpair (AW) writeop currentfont /FontType known { currentfont /FontType get 3 eq { false setdistill awidthshow true setdistill }{ awidthshow } ifelse }{ false setdistill awidthshow true setdistill } ifelse } ifelse } ifelse currentpoint thruCTM ?box } bdef /kshow { %def (%AAAAAH: kshow) writeop kshow } bdef % graphics operators /fillguts { %def (starting fill) d= generalstate graphicstate writepath ischarpath { % if pathstr length 0 gt { pathX writenum pathY writenum (m) writeop pathstr writePSstring (false charpath) writeop } if gstates 0 le { /ischarpath false store /closed false store } if } if } bdef /fill { %def ?distilling cvbool { %if fillguts ?simplepath { simplepath aload pop 4 2 roll writepair (moveto) writeop writepair (lineto) writeop /?simplepath false store } if (f) writeop } if fill } bdef /eofill { %def ?distilling cvbool { %if fillguts ?simplepath { %ifelse simplepath aload pop 4 2 roll writepair (moveto) writeop writepair (lineto) writeop /?simplepath false store } if (eofill) writeop } if eofill } bdef /stroke { %def ?distilling cvbool { %if fillguts ?simplepath { %ifelse generalstate graphicstate simplepath aload pop writepair writepair (l) writeop /?simplepath false store }{ % else closed { (cp ) wout } if (s) writeop } ifelse } if stroke } bdef /clip { %def ?distilling cvbool { %if /lastshow false store } if clip } bdef /eoclip /clip load def /imageguts { % def graphicstate /imageproc exch store /imagematrix exch store /imagedepth exch store /imageheight exch store /imagewidth exch store % set up the call to "image" in the output file: (/imagesave save def) writeop CTM writenumarray (concat) writeop 0 0 thruCTM ?box imagewidth imagedepth dup type /booleantype eq { pop 1 } if div imageheight imagematrix itransform thruCTM ?box (/imagebuff) writestr imagedepth dup type /booleantype eq { pop 1 } if imagewidth mul dup dup 8 idiv 8 mul eq {8 idiv}{8 idiv 1 add} ifelse writenum ( string def) writeop % invoke "image" with correct args in output file: imagewidth writenum imageheight writenum imagedepth ( ) cvs writestr imagematrix writenumarray } bdef /image { %def % width height depth matrix { proc } : ?distilling cvbool { %ifelse imageguts ({ currentfile imagebuff readhexstring pop } image) writeop imagewidth imageheight imagedepth imagematrix { imageproc dup fd exch writehexstring writeNL } image (imagesave restore) writeop }{ image } ifelse } bdef /imagemask { % def % width height depth matrix { proc } : ?distilling cvbool { %ifelse imageguts ({ currentfile imagebuff readhexstring pop } imagemask) writeop imagewidth imageheight imagedepth imagematrix { imageproc dup fd exch writehexstring writeNL } imagemask (imagesave restore) writeop }{ imagemask } ifelse } bdef % don't actually print the pages... Fri Feb 17 13:13:10 1989 % /*showpage systemdict /showpage get def /*showpage where { pop }{ %ifelse /*showpage /showpage load def } ifelse /showpage { %def stackshow pagecount cvnum scratch cvs wout ( ENDPAGE\n) wout /lastshowpage true hidebool /begunpage false hidebool /PAGEvec 0 hideval *showpage (%%PageTrailer) writeop (%%PageFonts: ) wout pfontcount cvnum 0 eq { writeNL }{ %else pfontcount cvnum 200 lt { %ifelse pagefonts 0 pfontcount cvnum getinterval writeop }{ %else pagefonts (\040) search not { writeop }{ %else writeop % first one without the %%+ { %loop search { (%%+ ) wout writeop }{ %else (\000) search { writeop pop pop }{ pop } ifelse exit } ifelse } loop } ifelse } ifelse } ifelse 0 1 pfontcount cvnum { pagefonts exch 0 put } for /pfontcount 0 hideval LLx 10000 eq LLy 10000 eq or URx -10000 eq URy -10000 eq or or not { (%%PageBoundingBox: ) wout LLx cvnum writenum LLy cvnum writenum URx cvnum writenum URy cvnum writenum writeNL pageBBox-docBBox } if /LLx 10000 hideval /LLy 10000 hideval /URx -10000 hideval /URy -10000 hideval % checksetup } bdef /*pathbbox systemdict /pathbbox get def /pathbbox { %def ?distilling cvbool { %if ischarpath { %ifelse gsave { currentpoint } stopped { 0 0 } if systemdict /moveto get exec pathstr false charpath flattenpath *pathbbox grestore }{ %else *pathbbox } ifelse } if } bdef /gsave { % def ?distilling cvbool { /gstates gstates 1 add store } if gsave } bdef /grestore { % def ?distilling cvbool { %if gstates 0 gt { %if /gstates gstates 1 sub store gstates charpathgstate lt { /ischarpath false store } if } if } if grestore } bdef /charpath { %def % need to make sure that when "stroke" or "fill" comes along % that the "charpath" elements are in the right place in the path... %- writepath ?distilling cvbool { %if checkgstate /ischarpath true store /charpathgstate gstates store /pathbool exch store /pathstr exch store { currentpoint } stopped { 0 0 } if thruCTM /pathY exch store /pathX exch store pathstr stringwidth rmoveto } if } bdef /newpath { %def ?distilling cvbool { gstates 0 le { /ischarpath false store } if } if newpath } bdef end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet: distill_paintops 1.0 %%BeginProcSet: distill_guessfont 1.0 /setpacking where { pop currentpacking true setpacking } if /adobe_distill dup where { pop pop }{ 165 200 add dict def } ifelse adobe_distill begin /*definefont systemdict /definefont get def /definefont { %def % make a dictionary into which to put things % put the ORIGINAL name of the font into that dictionary % put the original FID in that dictionary, for easy comparison dup /FontType known { dup /FontType get 3 eq { %ifelse dup begin includeuserfonts { %if (%%BeginFont: ) wout 1 index writename writeNL currentdict maxlength writenum (dict begin) writeop save /indentlevel ++ unames /Encoding true put currentdict { %forall exch dup /Encoding eq { %ifelse indent (/) wout writename writenamearray ( def) writeop indent }{ %else % dup unames exch true put ( /) wout writename writeANY (def) writeop indent } ifelse } forall currentdict { pop unames exch true put } forall currentdict { exch pop arrayusernames } forall restore indent (currentdict end\n) wout 1 index writeANY (exch definefont pop) writeop (%%EndFont: ) wout 1 index writename writeNL } if currentdict /FontInfo known not currentdict dup length 2 add exch maxlength ge and { %if % make slightly bigger version of current dictionary pop currentdict end dup maxlength 1 add dict begin { def } forall currentdict } if /FontInfo 5 dict def FontInfo begin /realname 2 index def /pleasemap magicbool def /pleasemap false hidebool end end false }{ true } ifelse }{ true } ifelse % previous code leaves either true or false on stack { %if /Dfont exch store % This might be the first time we've ever seen a new % encoding. If so, let's guess that we'll see lots % more of the vector, and give it the name "stdvec". Dfont begin %gcr FontType 1 eq STDvec cvnum 0 eq and STDvec cvnum 0 eq Encoding StandardEncoding ne and { %if /STDvec Encoding hashencoding hideval fd (/stdvec\n) *writestring STDvec StandardEncoding hashencoding eq { %ifelse fd (StandardEncoding ) *writestring }{ %else Encoding writenamearray } ifelse fd (def\n) *writestring checksetup }{ %else %gcr FontType 1 eq STDvec cvnum 0 eq and STDvec cvnum 0 eq Encoding StandardEncoding ne and { %if /PAGEvec Encoding hashencoding hideval fd (/pagevec\n) *writestring PAGEvec StandardEncoding hashencoding eq { %ifelse fd (StandardEncoding ) *writestring }{ %else Encoding writenamearray } ifelse fd (def\n) *writestring checksetup } if } ifelse end % try to find the "real" font in FontDirectory from which this % font was derived, assuming it was reencoded.... /tempfontname /Courier store /tempfontname /UnKnownFont store FontDirectory { %forall /Ffont exch store /Fname exch store % if the font was already touched, ignore it: Ffont /FontInfo known { %ifelse Ffont /FontInfo get /realname known not }{ true } ifelse % leaves boolean { % if % if UniqueID's match, grab it! Dfont /UniqueID known Ffont /UniqueID known and { Dfont /UniqueID get Ffont /UniqueID get eq { /tempfontname Fname store exit } if } if } if % /realname is not there } forall tempfontname /UnKnownFont eq { %if Dfont begin FontDirectory { %forall /Ffont exch store /Fname exch store % if CharStrings match, then compare FontMatrix. If % FontMatrix matches or the *second* elements match, % (it might be oblique), then grab it. Dfont /FontType known { FontType 1 eq { Dfont/CharStrings known Ffont/CharStrings known and { Dfont/CharStrings get Ffont/CharStrings get eq { Dfont/FontMatrix known Ffont/FontMatrix known and { Dfont/FontMatrix get Ffont/FontMatrix get 2 copy eq 3 1 roll 2 get exch 2 get eq or { /tempfontname Fname store exit } if } if } if } if } if } if } forall end } if tempfontname /UnKnownFont eq { %if FontDirectory { %forall /Ffont exch store /Fname exch store % if everything matches but some keys, grab it true % start with "true" on stack Dfont { %forall exch dup /Encoding eq 1 index /FID eq or { %ifelse pop pop }{ % else dup Ffont exch known { Ffont exch get ne { pop false exit } if }{ pop pop } ifelse } ifelse } forall % use either "true" that was there, or "false" from loop { %if /tempfontname Fname store exit } if } forall } if tempfontname /UnKnownFont eq { Dfont /Encoding get StandardEncoding eq substitutefonts or { %ifelse % If there is no comparable fontdict already there, and % if this is of FontType 1 and has StandardEncoding, % we guess that this is a downloadable font, and ignore it Dfont /FontName known { /tempfontname Dfont /FontName get store }{ /tempfontname /Courier store } ifelse (%substituting ) wout tempfontname writename writeNL messages { (substituting: ) pr= tempfontname == } if Dfont % needed by *definefont below... }{ %else (ERROR: Couldn't find original fontdict to match: ) print Dfont /FontName get == flush (Fonts in FontDirectory include:) r= FontDirectory { pop (\040) print == } forall flush stop } ifelse } if Dfont dup begin /FontInfo 5 dict def FontInfo begin /realname tempfontname def /pleasemap magicbool def /pleasemap tempfontname findfont /Encoding get StandardEncoding eq hidebool end end } if *definefont } bdef end %adobe_distill /setpacking where { pop setpacking } if %%EndProcSet: distill_guessfont 1.0 %%BeginProcSet: hacks 0.5 % defeat the "transform round exch round exch itransform" trick: /round { } bdef /transform { dup type /arraytype eq { pop } if } bdef /itransform { dup type /arraytype eq { pop } if } bdef % redefine control-D: (\004) { (\n%%EOF) writeop } bdef %%EndProcSet: hacks 0.5