diff options
Diffstat (limited to 'Master/tlpkg/tlgs/lib/ps2ascii.ps')
-rw-r--r--[-rwxr-xr-x] | Master/tlpkg/tlgs/lib/ps2ascii.ps | 3048 |
1 files changed, 1524 insertions, 1524 deletions
diff --git a/Master/tlpkg/tlgs/lib/ps2ascii.ps b/Master/tlpkg/tlgs/lib/ps2ascii.ps index 8a8c1ff755b..a88c7d535e6 100755..100644 --- a/Master/tlpkg/tlgs/lib/ps2ascii.ps +++ b/Master/tlpkg/tlgs/lib/ps2ascii.ps @@ -1,1524 +1,1524 @@ -% Copyright (C) 1991, 1995, 1996, 1998, 1999 Aladdin Enterprises. All rights reserved.
-%
-% This software is provided AS-IS with no warranty, either express or
-% implied.
-%
-% This software is distributed under license and may not be copied,
-% modified or distributed except as expressly authorized under the terms
-% of the license contained in the file LICENSE in this distribution.
-%
-% For more information about licensing, please refer to
-% http://www.ghostscript.com/licensing/. For information on
-% commercial licensing, go to http://www.artifex.com/licensing/ or
-% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
-% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
-
-% $Id: ps2ascii.ps 6300 2005-12-28 19:56:24Z giles $
-% Extract the ASCII text from a PostScript file. Nothing is displayed.
-% Instead, ASCII information is written to stdout. The idea is similar to
-% Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
-
-% If SIMPLE is defined, just the text is written, with a guess at line
-% breaks and word spacing. If SIMPLE is not defined, lines are written
-% to stdout as follows:
-%
-% F <height> <width> (<fontname>)
-% Indicate the font height and the width of a space.
-%
-% P
-% Indicate the end of the page.
-%
-% S <x> <y> (<string>) <width>
-% Display a string.
-%
-% <width> and <height> are integer dimensions in units of 1/720".
-% <x> and <y> are integer coordinates, in units of 1/720", with the origin
-% at the lower left.
-% <string> and <fontname> are strings represented with the standard
-% PostScript escape conventions.
-
-% If COMPLEX is defined, the following additional types of lines are
-% written to stdout.
-%
-% C <r> <g> <b>
-% Indicate the current color.
-%
-% I <x> <y> <width> <height>
-% Note the presence of an image.
-%
-% R <x> <y> <width> <height>
-% Fill a rectangle.
-%
-% <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
-%
-% Note that future versions of this program (in COMPLEX mode) may add
-% other output elements, so programs parsing the output should be
-% prepared to ignore elements that they do not recognize.
-
-% Note that this code will only work in all cases if systemdict is writable
-% and if `binding' the definitions of operators defined as procedures
-% is deferred. For this reason, it is normally invoked with
-% gs -q -dNODISPLAY -dDELAYBIND -dWRITESYSTEMDICT ps2ascii.ps
-
-% Thanks to:
-% J Greely <jgreely@cis.ohio-state.edu> for improvements to this code;
-% Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements;
-% David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below.
-
-%% Additional modifications by David M. Jones
-%% (dmjones@theory.lcs.mit.edu), December 23, 1997
-%%
-%% (a) Rewrote forall loop at the end of .show.write. This fixes a
-%% stack leakage problem, but the changes are more significant
-%% than that.
-%%
-%% .char.map includes the names of all characters in the
-%% StandardEncoding, ISOLatin1Encoding, OT1Encoding and
-%% T1Encoding vectors. Thus, if the Encoding vector for the
-%% current font contains a name that is not in .char.map, it's
-%% redundant to check if the Encoding vector is equal to one of
-%% the known vectors. Previous versions of ps2ascii would give
-%% up at this point, and substitute an asterisk (*) for the
-%% character. I've taken the liberty of instead using the
-%% OT1Encoding vector to translate the character, on the grounds
-%% that in the cases I'm most interested in, a font without a
-%% useful Encoding vector was most likely created by a DVI to PS
-%% converter such as dvips or DVILASER (and OT1Encoding is
-%% largely compatible with StandardEncoding anyway). [Note that
-%% this does not make my earlier changes to support dvips (see
-%% fix (a) under my 1996 changes) completely obsolete, since
-%% there's additional useful information I can extract in that
-%% case.]
-%%
-%% Overall, this should provide better support for some documents
-%% (e.g, DVILASER documents will no longer be translated into a
-%% series of *'s) without breaking any other documents any worse
-%% than they already were broken.
-%%
-%% (b) Fixed two bugs in dvips.df-tail: (1) changed "dup 127" to "dup
-%% 128" to fix fencepost error, and (2) gave each font it's own
-%% FontName rather than having all fonts share the same name.
-%%
-%% (c) Added one further refinement to the heuristic for detecting
-%% paragraph breaks: do not ever start a new paragraph after a
-%% line ending in a hyphen.
-%%
-%% (d) Added a bunch of missing letters from the T1Encoding,
-%% OT1Encoding and ISOLatin1Encoding vectors to .letter.chars to
-%% improve hyphen-elimination algorithm. This still won't help
-%% if there's no useful Encoding vector.
-%%
-%% NOTE: A better solution to the problem of missing Encoding vectors
-%% might be to redefine definefont to check whether the Encoding
-%% vector is sensible and, if not, replace it by a default. This
-%% would alleviate the need for constant tests in the .show.write
-%% loop, as well as automatically solving the problem noted in fix
-%% (d) above, and the similar problem with .break.chars. This should
-%% be investigated. Also, the hyphen-elimination algorithm really
-%% needs to be looked at carefully and rethought.
-
-%%* Modifications to ps2ascii.ps by David M. Jones
-%%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996
-
-%%* Modifications:
-%%*
-%%* (a) added code to give better support for dvips files by providing
-%%* FontBBox's, FontName's and Encoding vectors for downloaded
-%%* bitmap fonts. This is done by using dvips's start-hook to
-%%* overwrite the df-tail and D procedures that dvips uses to
-%%* define its Type 3 bitmap fonts. Thus, this change should
-%%* provide better support for dvips-generated PS files without
-%%* affecting the handling of other documents.
-%%*
-%%* (b) Fixed two bugs that could potentially affect any PS file, not
-%%* just those created by dvips: (1) added missing "get" operator
-%%* in .show.write and (2) fixed bug that caused a hyphen at the
-%%* end of a line to be replaced by a space rather than begin
-%%* deleted. Note that the first bug was a source of stack
-%%* leakage, causing ps2ascii to run out of operand stack space
-%%* occasionally.
-%%*
-%%* Search for "%%* BF" to find these modifications.
-%%*
-%%* (c) Improved the heuristic for determining whether a line break
-%%* has occurred and whether a line break represents a paragraph
-%%* break. Previously, any change in the vertical position caused
-%%* a line break; now a line break is only registered if the
-%%* change is larger than the height of the current font. This
-%%* means that superscripts, subscripts, and such things as
-%%* shifted accents generated by TeX won't cause line breaks.
-%%* Paragraph-recognition is now done by comparing the indentation
-%%* of the new line to the indentation of the previous line and by
-%%* comparing the vertical distance between the new line and the
-%%* previous line to the vertical distance between the previous
-%%* line and its predecessor.
-%%*
-%%* (d) Added a hook for renaming the files where stdout and stderr
-%%* go.
-%%*
-%%* In general, my additions or changes to the code are described in
-%%* comments beginning with "%%*". However, there are numerous other
-%%* places where I have either re-formatted code or added comments to
-%%* the code while I was trying to understand it. These are usually
-%%* not specially marked.
-%%*
-
-/QUIET true def
-systemdict wcheck { systemdict } { userdict } ifelse begin
-/.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
-/COMPLEX dup where { pop true } { false } ifelse def
-/SIMPLE dup where { pop true } { false } ifelse def
-/setglobal where
- { pop currentglobal /setglobal load true setglobal }
- { { } }
-ifelse
-
-% Define a way to store and retrieve integers that survives save/restore.
-/.i.string0 (0 ) def
-/.i.string .i.string0 length string def
-/.iget { cvi } bind def
-/.iput { exch //.i.string exch copy cvs pop } bind def
-/.inew { //.i.string0 dup length string copy } bind def
-
-% We only want to redefine operators if they are defined already.
-
-/codef { 1 index where { pop def } { pop pop } ifelse } def
-
-% Redefine the end-of-page operators.
-
-/erasepage { } codef
-/copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
-/showpage { copypage erasepage initgraphics } codef
-
-% Redefine the fill operators to detect rectangles.
-
-/.orderrect % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
- { % Ensure llx <= urx, lly <= ury.
- 1 index 4 index lt { 4 2 roll } if
- dup 3 index lt { 3 1 roll exch } if
- exch 3 index sub exch 2 index sub
- } odef
-/.fillcomplex
- { % Do a first pass to see if the path is all rectangles in
- % the output coordinate system. We don't worry about overlapping
- % rectangles that might be partially not filled.
- % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
- mark true mark
- % Add a final moveto so we pick up any trailing unclosed subpath.
- 0 0 itransform moveto
- { .coord counttomark 2 gt
- { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop } ifelse }
- if
- }
- { .coord }
- { cleartomark not mark exit }
- { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
- pathforall cleartomark
- { .showcolor counttomark 4 idiv
- { counttomark -4 roll .orderrect
- (R ) //print .show==4
- }
- repeat pop
- }
- { cleartomark
- }
- ifelse
- } odef
-/.fillcheckrect
- { % Check whether the current subpath is a rectangle.
- % If it is, add it to the list of rectangles being accumulated;
- % if not exit the .fillcomplex loop.
- % The subpath has not been closed.
- % Stack: as in .fillcomplex, + newx newy
- counttomark 10 eq { 9 index 9 index 4 2 roll } if
- counttomark 12 ne { cleartomark not mark exit } if
- 12 2 roll
- % Check for the two possible forms of rectangles:
- % x0 y0 x0 y1 x1 y1 x1 y0 x0 y0
- % x0 y0 x1 y0 x1 y1 x0 y1 x0 y0
- 9 index 2 index eq 9 index 2 index eq and
- 10 index 9 index eq
- { % Check for first form.
- 7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
- }
- { % Check for second form.
- 9 index 8 index eq and
- 8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
- }
- ifelse not { cleartomark not mark exit } if
- % We have a rectangle.
- pop pop pop pop 4 2 roll pop pop 8 4 roll
- } odef
-/eofill { COMPLEX { .fillcomplex } if newpath } codef
-/fill { COMPLEX { .fillcomplex } if newpath } codef
-/rectfill { gsave newpath .rectappend fill grestore } codef
-/ueofill { gsave newpath uappend eofill grestore } codef
-/ufill { gsave newpath uappend fill grestore } codef
-
-% Redefine the stroke operators to detect rectangles.
-
-/rectstroke
- { gsave newpath
- dup type dup /arraytype eq exch /packedarraytype eq or
- { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
- { .rectappend }
- ifelse stroke grestore
- } codef
-/.strokeline % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
- % Note: fromx and fromy are in output coordinates;
- % tox and toy are in user coordinates.
- { .coord 2 copy 6 2 roll .orderrect
- % Add in the line width. Assume square or round caps.
- currentlinewidth 2 div dup .dcoord add abs 1 .max 5 1 roll
- 4 index add 4 1 roll 4 index add 4 1 roll
- 4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
- (R ) //print .show==4
- } odef
-/.strokecomplex
- { % Do a first pass to see if the path is all horizontal and vertical
- % lines in the output coordinate system.
- % Stack: true mark origx origy curx cury
- true mark null null null null
- { .coord 6 2 roll pop pop pop pop 2 copy }
- { .coord 1 index 4 index eq 1 index 4 index eq or
- { 4 2 roll pop pop }
- { cleartomark not mark exit }
- ifelse
- }
- { cleartomark not mark exit }
- { counttomark -2 roll 2 copy counttomark 2 roll
- 1 index 4 index eq 1 index 4 index eq or
- { pop pop 2 copy }
- { cleartomark not mark exit }
- ifelse
- }
- pathforall cleartomark
- 0 currentlinewidth .dcoord 0 eq exch 0 eq or and
- % Do the second pass to write out the rectangles.
- % Stack: origx origy curx cury
- { .showcolor null null null null
- { 6 2 roll pop pop pop pop 2 copy .coord }
- { .strokeline }
- { }
- { 3 index 3 index .strokeline }
- pathforall pop pop pop pop
- }
- if
- } odef
-/stroke { COMPLEX { .strokecomplex } if newpath } codef
-/ustroke
- { gsave newpath
- dup length 6 eq { exch uappend concat } { uappend } ifelse
- stroke grestore
- } codef
-
-% The image operators must read the input and note the dimensions.
-% Eventually we should redefine these to detect 1-bit-high all-black images,
-% since this is how dvips does underlining (!).
-
-/.noteimagerect % <width> <height> <matrix> .noteimagerect -
- { COMPLEX
- { gsave setmatrix itransform 0 0 itransform
- grestore .coord 4 2 roll .coord .orderrect
- (I ) //print .show==4
- }
- { pop pop pop
- }
- ifelse
- } odef
-/colorimage where
- { pop /colorimage
- { 1 index
- { dup 6 add index 1 index 6 add index 2 index 5 add index }
- { 6 index 6 index 5 index }
- ifelse .noteimagerect gsave nulldevice //colorimage grestore
- } codef
- } if
-/.noteimage % Arguments as for image[mask]
- { dup type /dicttype eq
- { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
- { 4 index 4 index 3 index }
- ifelse .noteimagerect
- } odef
-/image { .noteimage gsave nulldevice //image grestore } codef
-/imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
-
-% Output the current color if necessary.
-/.color.r .inew def
- .color.r -1 .iput % make sure we write the color at the beginning
-/.color.g .inew def
-/.color.b .inew def
-/.showcolor
- { COMPLEX
- { currentrgbcolor
- 1000 mul round cvi
- 3 1 roll 1000 mul round cvi
- exch 1000 mul round cvi
- % Stack: b g r
- dup //.color.r .iget eq
- 2 index //.color.g .iget eq and
- 3 index //.color.b .iget eq and
- { pop pop pop
- }
- { (C ) //print
- dup //.color.r exch .iput .show==only
- ( ) //print dup //.color.g exch .iput .show==only
- ( ) //print dup //.color.b exch .iput .show==only
- (\n) //print
- }
- ifelse
- }
- if
- } bind def
-
-% Redefine `show'.
-
-% Set things up so our output will be in tenths of a point, with origin at
-% lower left. This isolates us from the peculiarities of individual devices.
-
-/.show.ident.matrix matrix def
-/.show.ident { % - .show.ident <scale> <matrix>
-% //.show.ident.matrix defaultmatrix
-% % Assume the original transformation is well-behaved.
-% 0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
-% 0.1 dup 3 -1 roll scale
- gsave initmatrix
- % Assume the original transformation is well-behaved...
- 0.1 0 dtransform abs exch abs .max
- 0.1 dup scale .show.ident.matrix currentmatrix
- % ... but undo any rotation into landscape orientation.
- dup 0 get 0 eq {
- 1 get dup abs div 90 mul rotate
- .show.ident.matrix currentmatrix
- } if
- grestore
-} bind def
-
-/.coord { % <x> <y> .coord <x'> <y'>
- transform .show.ident exch pop itransform
- exch round cvi exch round cvi
-} odef
-
-/.dcoord { % <dx> <dy> .coord <dx'> <dy'>
- % Transforming distances is trickier, because
- % the coordinate system might be rotated.
- .show.ident pop 3 1 roll
- exch 0 dtransform
- dup mul exch dup mul add sqrt
- 2 index div round cvi
- exch 0 exch dtransform
- dup mul exch dup mul add sqrt
- 3 -1 roll div round cvi
-} odef
-
-% Remember the current X, Y, and height.
-/.show.x .inew def
-/.show.y .inew def
-/.show.height .inew def
-
-% Remember the last character of the previous string; if it was a
-% hyphen preceded by a letter, we didn't output the hyphen.
-
-/.show.last (\000) def
-
-% Remember the current font.
-/.font.name 130 string def
-/.font.name.length .inew def
-/.font.height .inew def
-/.font.width .inew def
-
-%%* Also remember indentation of current line and previous vertical
-%%* skip
-
-/.show.indent .inew def
-/.show.dy .inew def
-
-% We have to redirect stdout somehow....
-
-/.show.stdout { (%stdout) (w) file } bind def
-
-% Make sure writing will work even if a program uses =string.
-/.show.string =string length string def
-/.show.=string =string length string def
-/.show==only
- { //=string //.show.=string copy pop
- dup type /stringtype eq
- { dup length //.show.string length le
- { dup rcheck { //.show.string copy } if
- } if
- } if
- .show.stdout exch write==only
- //.show.=string //=string copy pop
- } odef
-/.show==4
- { 4 -1 roll .show==only ( ) //print
- 3 -1 roll .show==only ( ) //print
- exch .show==only ( ) //print
- .show==only (\n) //print
- } odef
-
-/.showwidth % Same as stringwidth, but disable COMPLEX so that
- % we don't try to detect rectangles during BuildChar.
- { COMPLEX
- { /COMPLEX false def stringwidth /COMPLEX true def }
- { stringwidth }
- ifelse
- } odef
-
-/.showfont % <string> .showfont <string>
- { gsave
- % Try getting the height and width of the font from the FontBBox.
- currentfont /FontBBox .knownget not { {0 0 0 0} } if
- aload pop % llx lly urx ury
- exch 4 -1 roll % lly ury urx llx
- sub % lly ury dx
- 3 1 roll exch % dx ury lly
- sub % dx dy
- 2 copy .max 0 ne
- { currentfont /FontMatrix get dtransform
- }
- { pop pop
- % Fonts produced by dvips, among other applications, have
- % BuildChar procedures that bomb out when given unexpected
- % characters, and there is no way to determine whether a given
- % character will do this. So for Type 1 fonts, we measure a
- % typical character ('X'); for others, we punt.
- currentfont /FontType get 1 eq
- { (X) .showwidth pop dup 1.3 mul
- }
- { % No safe way to get the character size. Punt.
- 0 0
- }
- ifelse
- }
- ifelse .dcoord exch
- currentfont /FontName .knownget not { () } if
- dup type /stringtype ne { //.show.string cvs } if
- grestore
- % Stack: height width fontname
- SIMPLE
- { pop pop //.show.height exch .iput }
- { 2 index //.font.height .iget eq
- 2 index //.font.width .iget eq and
- 1 index //.font.name 0 //.font.name.length .iget getinterval eq and
- { pop pop pop
- }
- { (F ) //print
- 3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
- exch dup //.font.width exch .iput .show==only ( ) //print
- dup length //.font.name.length exch .iput
- //.font.name cvs .show==only (\n) //print
- }
- ifelse
- }
- ifelse
- } odef
-
-% Define the letters -- characters which, if they occur followed by a hyphen
-% at the end of a line, cause the hyphen and line break to be ignored.
-/.letter.chars 100 dict def
-mark
- 65 1 90 { dup 32 add } for
- counttomark
- { StandardEncoding exch get .letter.chars exch dup put }
- repeat
-pop
-
-%%* Add the rest of the letters from the [O]T1Encoding and
-%%* ISOLatin1Encoding vectors
-
-mark
- /AE
- /Aacute
- /Abreve
- /Acircumflex
- /Adieresis
- /Agrave
- /Aogonek
- /Aring
- /Atilde
- /Cacute
- /Ccaron
- /Ccedilla
- /Dcaron
- /Eacute
- /Ecaron
- /Ecircumflex
- /Edieresis
- /Egrave
- /Eng
- /Eogonek
- /Eth
- /Gbreve
- /Germandbls
- /IJ
- /Iacute
- /Icircumflex
- /Idieresis
- /Idot
- /Igrave
- /Lacute
- /Lcaron
- /Lslash
- /Nacute
- /Ncaron
- /Ntilde
- /OE
- /Oacute
- /Ocircumflex
- /Odieresis
- /Ograve
- /Ohungarumlaut
- /Oslash
- /Otilde
- /Racute
- /Rcaron
- /Sacute
- /Scaron
- /Scedilla
- /Tcaron
- /Tcedilla
- /Thorn
- /Uacute
- /Ucircumflex
- /Udieresis
- /Ugrave
- /Uhungarumlaut
- /Uring
- /Yacute
- /Ydieresis
- /Zacute
- /Zcaron
- /Zdot
- /aacute
- /abreve
- /acircumflex
- /adieresis
- /ae
- /agrave
- /aogonek
- /aring
- /atilde
- /cacute
- /ccaron
- /ccedilla
- /dbar
- /dcaron
- /dotlessi
- /dotlessj
- /eacute
- /ecaron
- /ecircumflex
- /edieresis
- /egrave
- /eng
- /eogonek
- /eth
- /exclamdown
- /ff
- /ffi
- /ffl
- /fi
- /fl
- /gbreve
- /germandbls
- /iacute
- /icircumflex
- /idieresis
- /igrave
- /ij
- /lacute
- /lcaron
- /lslash
- /nacute
- /ncaron
- /ntilde
- /oacute
- /ocircumflex
- /odieresis
- /oe
- /ograve
- /ohungarumlaut
- /oslash
- /otilde
- /questiondown
- /racute
- /rcaron
- /sacute
- /scaron
- /scedilla
- /section
- /sterling
- /tcaron
- /tcedilla
- /thorn
- /uacute
- /ucircumflex
- /udieresis
- /ugrave
- /uhungarumlaut
- /uring
- /yacute
- /ydieresis
- /zacute
- /zcaron
- /zdot
-counttomark
- { .letter.chars exch dup put }
-repeat
-pop
-
-% Define a set of characters which, if they occur at the start of a line,
-% are taken as indicating a paragraph break.
-/.break.chars 50 dict def
-mark
- /bullet /dagger /daggerdbl /periodcentered /section
- counttomark
- { .break.chars exch dup put }
- repeat
-pop
-
-% Define character translation to ASCII.
-% We have to do this for the entire character set.
-
-/.char.map 500 dict def
-
-/.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
-
-% Encode the printable ASCII characters.
-
-mark 32 1 126
- { 1 string dup 0 4 -1 roll put
- dup 0 get StandardEncoding exch get exch
- }
-for .chars.def
-
- % Encode accents.
-mark
- /acute (')
- /caron (^)
- /cedilla (,)
- /circumflex (^)
- /dieresis (")
- /grave (`)
- /ring (*)
- /tilde (~)
-.chars.def
-
- % Encode the ISO accented characters.
-mark 192 1 255
- { ISOLatin1Encoding exch get =string cvs
- dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
- .char.map 2 index known .char.map 2 index known and
- { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
- .char.map 3 1 roll put
- }
- { pop pop pop
- }
- ifelse
- }
-for .chars.def
-
-% Encode the remaining standard and ISO alphabetic characters.
-
-mark
- /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
- /ae (ae) /eth (dh)
- /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
- /germandbls (ss) /oe (oe) /thorn (th)
-.chars.def
-
-% Encode the other standard and ISO characters.
-
-mark
- /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
- /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
- /dotlessi (i)
- /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
- /florin (f) /fraction (/)
- /guillemotleft (<<) /guillemotright (>>)
- /guilsinglleft (<) /guilsinglright (>) /hungarumlaut ("") /logicalnot (~)
- /macron (_) /minus (-) /mu (u) /multiply (*)
- /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
- /ordfeminine (-a) /ordmasculine (-o)
- /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
- /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
- /quotesinglbase (,) /quotesingle (') /registered ((R))
- /section ($) /sterling (#)
- /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
- /yen (Y)
-.chars.def
-
-% Encode a few common Symbol characters.
-
-mark
- /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
- /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
- /trademarksans ((TM)) /trademarkserif ((TM))
-.chars.def
-
-%%* Add a few characters from StandardEncoding and ISOLatin1Encoding
-%%* that were missing.
-
-mark
- /cent (c)
- /guilsinglleft (<)
- /guilsinglright (>)
- /breve (*)
- /Lslash (L/)
- /lslash (l/)
-.chars.def
-
-%%* Define the OT1Encoding and T1Encoding vectors for use with dvips
-%%* files. Unfortunately, there's no way of telling what font is
-%%* really being used within a dvips document, so we can't provide an
-%%* appropriate encoding for each individual font. Instead, we'll
-%%* just provide support for the two most popular text encodings, the
-%%* OT1 and T1 encodings, and just accept the fact that any font not
-%%* using one of those encodings will be rendered as gibberish.
-%%*
-%%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1
-%%* (aka the Cork encoding) is the 8-bit encoding used by the DC
-%%* fonts, a preliminary version of the proposed Extended Computer
-%%* Modern fonts. Unfortunately, T1 is not a strict extension of OT1;
-%%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134,
-%%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same
-%%* vector for both.
-%%*
-%%* Of course, we also can't reliably tell the difference between an
-%%* OT1-encoded font and a T1-encoded font based on the information in
-%%* a dvips-created PostScript file. As a best-guess solution, we'll
-%%* use the T1 encoding if the font contains any characters in
-%%* positions above 8#177 and the OT1 encoding if it doesn't.
-
-/T1Encoding 256 array def
-
-/OT1Encoding 256 array def
-
-%%* T1Encoding shares a lot with StandardEncoding, so let's start
-%%* there.
-
-StandardEncoding T1Encoding copy pop
-
-/OT1.encode {
- counttomark
- 2 idiv
- { OT1Encoding 3 1 roll put }
- repeat
- cleartomark
-} def
-
-/T1.encode {
- counttomark
- 2 idiv
- { T1Encoding 3 1 roll put }
- repeat
- cleartomark
-} def
-
-mark
- 8#000 /grave
- 8#001 /acute
- 8#002 /circumflex
- 8#003 /tilde
- 8#004 /dieresis
- 8#005 /hungarumlaut
- 8#006 /ring
- 8#007 /caron
-
- 8#010 /breve
- 8#011 /macron
- 8#012 /dotaccent
- 8#013 /cedilla
- 8#014 /ogonek
- 8#015 /quotesinglbase
- 8#016 /guilsinglleft
- 8#017 /guilsinglright
-
- 8#020 /quotedblleft
- 8#021 /quotedblright
- 8#022 /quotedblbase
- 8#023 /guillemotleft
- 8#024 /guillemotright
- 8#025 /endash
- 8#026 /emdash
- 8#027 /cwm
-
- 8#030 /perthousandzero
- 8#031 /dotlessi
- 8#032 /dotlessj
- 8#033 /ff
- 8#034 /fi
- 8#035 /fl
- 8#036 /ffi
- 8#037 /ffl
-
-%% 8#040 through 8#176 follow StandardEncoding
-
- 8#177 /hyphen
-T1.encode
-
-mark
- 8#200 /Abreve
- 8#201 /Aogonek
- 8#202 /Cacute
- 8#203 /Ccaron
- 8#204 /Dcaron
- 8#205 /Ecaron
- 8#206 /Eogonek
- 8#207 /Gbreve
- 8#210 /Lacute
- 8#211 /Lcaron
- 8#212 /Lslash
- 8#213 /Nacute
- 8#214 /Ncaron
- 8#215 /Eng
- 8#216 /Ohungarumlaut
- 8#217 /Racute
- 8#220 /Rcaron
- 8#221 /Sacute
- 8#222 /Scaron
- 8#223 /Scedilla
- 8#224 /Tcaron
- 8#225 /Tcedilla
- 8#226 /Uhungarumlaut
- 8#227 /Uring
- 8#230 /Ydieresis
- 8#231 /Zacute
- 8#232 /Zcaron
- 8#233 /Zdot
- 8#234 /IJ
- 8#235 /Idot
- 8#236 /dbar
- 8#237 /section
- 8#240 /abreve
- 8#241 /aogonek
- 8#242 /cacute
- 8#243 /ccaron
- 8#244 /dcaron
- 8#245 /ecaron
- 8#246 /eogonek
- 8#247 /gbreve
- 8#250 /lacute
- 8#251 /lcaron
- 8#252 /lslash
- 8#253 /nacute
- 8#254 /ncaron
- 8#255 /eng
- 8#256 /ohungarumlaut
- 8#257 /racute
- 8#260 /rcaron
- 8#261 /sacute
- 8#262 /scaron
- 8#263 /scedilla
- 8#264 /tcaron
- 8#265 /tcedilla
- 8#266 /uhungarumlaut
- 8#267 /uring
- 8#270 /ydieresis
- 8#271 /zacute
- 8#272 /zcaron
- 8#273 /zdot
- 8#274 /ij
- 8#275 /exclamdown
- 8#276 /questiondown
- 8#277 /sterling
-
- 8#300 /Agrave
- 8#301 /Aacute
- 8#302 /Acircumflex
- 8#303 /Atilde
- 8#304 /Adieresis
- 8#305 /Aring
- 8#306 /AE
- 8#307 /Ccedilla
- 8#310 /Egrave
- 8#311 /Eacute
- 8#312 /Ecircumflex
- 8#313 /Edieresis
- 8#314 /Igrave
- 8#315 /Iacute
- 8#316 /Icircumflex
- 8#317 /Idieresis
- 8#320 /Eth
- 8#321 /Ntilde
- 8#322 /Ograve
- 8#323 /Oacute
- 8#324 /Ocircumflex
- 8#325 /Otilde
- 8#326 /Odieresis
- 8#327 /OE
- 8#330 /Oslash
- 8#331 /Ugrave
- 8#332 /Uacute
- 8#333 /Ucircumflex
- 8#334 /Udieresis
- 8#335 /Yacute
- 8#336 /Thorn
- 8#337 /Germandbls
-
- 8#340 /agrave
- 8#341 /aacute
- 8#342 /acircumflex
- 8#343 /atilde
- 8#344 /adieresis
- 8#345 /aring
- 8#346 /ae
- 8#347 /ccedilla
- 8#350 /egrave
- 8#351 /eacute
- 8#352 /ecircumflex
- 8#353 /edieresis
- 8#354 /igrave
- 8#355 /iacute
- 8#356 /icircumflex
- 8#357 /idieresis
- 8#360 /eth
- 8#361 /ntilde
- 8#362 /ograve
- 8#363 /oacute
- 8#364 /ocircumflex
- 8#365 /otilde
- 8#366 /odieresis
- 8#367 /oe
- 8#370 /oslash
- 8#371 /ugrave
- 8#372 /uacute
- 8#373 /ucircumflex
- 8#374 /udieresis
- 8#375 /yacute
- 8#376 /thorn
- 8#377 /germandbls
-
-T1.encode
-
-%%* Now copy OT1Encoding into T1Encoding and make a few changes.
-
-T1Encoding OT1Encoding copy pop
-
-mark
- 8#000 /Gamma
- 8#001 /Delta
- 8#002 /Theta
- 8#003 /Lambda
- 8#004 /Xi
- 8#005 /Pi
- 8#006 /Sigma
- 8#007 /Upsilon
-
- 8#010 /Phi
- 8#011 /Psi
- 8#012 /Omega
- 8#013 /ff
- 8#014 /fi
- 8#015 /fl
- 8#016 /ffi
- 8#017 /ffl
-
- 8#020 /dotlessi
- 8#021 /dotlessj
- 8#022 /grave
- 8#023 /acute
- 8#024 /caron
- 8#025 /breve
- 8#026 /macron
- 8#027 /ring
-
- 8#030 /cedilla
- 8#031 /germandbls
- 8#032 /ae
- 8#033 /oe
- 8#034 /oslash
- 8#035 /AE
- 8#036 /OE
- 8#037 /Oslash
-
- 8#040 /polishslash
-
- 8#042 /quotedblright
-
- 8#074 /exclamdown
- 8#076 /questiondown
-
- 8#134 /quotedblleft
- 8#137 /dotaccent
-
- 8#173 /endash
- 8#174 /emdash
- 8#175 /hungarumlaut
- 8#177 /dieresis
-OT1.encode
-
-%%* And add a few characters from the OT1Encoding
-
-mark
- /Gamma (\\Gamma )
- /Delta (\\Delta )
- /Theta (\\Theta )
- /Lambda (\\Lambda )
- /Xi (\\Xi )
- /Pi (\\Pi )
- /Sigma (\\Sigma )
- /Upsilon (\\Upsilon )
-
- /Phi (\\Phi )
- /Psi (\\Psi )
- /Omega (\\Omega )
-
- /dotlessj (j)
- /ff (ff)
-
- /cwm ()
-
- /perthousandzero (0)
-
- /polishslash ()
-
- /Abreve (A*)
- /Aogonek (A,)
- /Cacute (C')
- /Ccaron (C^)
- /Dcaron (D^)
- /Ecaron (E^)
- /Eogonek (E,)
- /Gbreve (G*)
- /Lacute (L')
- /Lcaron (L^)
- /Nacute (N')
- /Ncaron (N^)
- /Eng (NG)
- /Ohungarumlaut (O"")
- /Racute (R')
- /Rcaron (R^)
- /Sacute (S')
- /Scaron (S^)
- /Scedilla (S,)
- /Tcaron (T^)
- /Tcedilla (T,)
- /Uhungarumlaut (U"")
- /Uring (U*)
- /Ydieresis (Y")
- /Zacute (Z')
- /Zcaron (Z^)
- /Zdot (Z.)
- /IJ (IJ)
- /Idot (I.)
- /dbar (d-)
- /abreve (a*)
- /aogonek (a,)
- /cacute (c')
- /ccaron (c^)
- /dcaron (d^)
- /ecaron (e^)
- /eogonek (e,)
- /gbreve (g*)
- /lacute (l')
- /lcaron (l^)
- /nacute (n')
- /ncaron (n^)
- /eng (ng)
- /ohungarumlaut (o"")
- /racute (r')
- /rcaron (r^)
- /sacute (s')
- /scaron (s^)
- /scedilla (s,)
- /tcaron (t^)
- /tcedilla (t,)
- /uhungarumlaut (u"")
- /uring (u*)
- /zacute (z')
- /zcaron (z^)
- /zdot (z.)
- /ij (ij)
- /Germandbls (SS)
-.chars.def
-
-%%* We extend the df-tail command to stick in an Encoding vector (see
-%%* above for a discussion of the T1 and OT1 encodings), put in a
-%%* FontName (which will just be dvips's name for the font, i.e., Fa,
-%%* Fb, etc.) and give each font a separate FontBBox instead of
-%%* letting them all share a single one.
-
-/dvips.df-tail % id numcc maxcc df-tail
- {
- /nn 9 dict N
- nn begin
- %%
- %% Choose an encoding based on the highest position occupied.
- %%
- dup 128 gt { T1Encoding } { OT1Encoding } ifelse
- /Encoding X
- /FontType 3 N
- %%
- %% It's ok for all the fonts to share a FontMatrix, but they
- %% need to have separate FontBBoxes
- %%
- /FontMatrix fntrx N
- /FontBBox [0 0 0 0] N
- string /base X
- array /BitMaps X
- %%
- %% And let's throw in a FontName for good measure
- %%
- dup ( ) cvs
- %%
- %% Make sure each font gets it own private FontName. -- dmj,
- %% 12/23/97
- %%
- dup length string copy
- /FontName X
- /BuildChar {CharBuilder} N
- end
- dup { /foo setfont }
- 2 array copy cvx N
- load
- 0 nn put
- /ctr 0 N
- [
-} def
-
-%%* This is functionally equivalent to dvips's /D procedure, but it
-%%* also calculates the Font Bounding Box while defining the
-%%* characters.
-
-/dvips.D % char-data ch D - : define character bitmap in current font
-{
- /cc X % char-data
- dup type /stringtype ne {]} if % char-data
-
- /ch-xoff where
- { pop }
- { dup /Cd exch def
- /ch-width { Cw } def
- /ch-height { Ch } def
- /ch-xoff { Cx } def
- /ch-yoff { Cy } def
- /ch-dx { Cdx } def
- } ifelse
- /ch-data X
- nn /base get cc ctr put % (adds ctr to cc'th position of BASE)
- nn /BitMaps get
- ctr
- ch-data % BitMaps ctr char-data
- sf 1 ne {
- dup dup length 1 sub dup 2 index S get sf div put
- } if
- put % puts char-data into BitMaps at index ctr
- /ctr ctr 1 add N
-%%
-%% Make sure the Font Bounding Box encloses the Bounding Box of the
-%% current character
-%%
- nn /FontBBox get % BB
-
- dup % calculate new llx
- dup 0 get
- ch-xoff
- .min
- 0 exch put
-
- dup % calculate new lly
- dup 1 get
- ch-yoff ch-height sub
- .min
- 1 exch put
-
- dup % calculate new urx
- dup 2 get
- ch-dx ch-width add
- .max
- 2 exch put
-
- dup 3 get % calculate new ury
- ch-yoff
- .max
- 3 exch put
-
-} def
-
-%%* Define start-hook to replace df-tail and D by our versions.
-%%* Unfortunately, the user can redefine start-hook and thus bypass
-%%* these changes, but I don't see an obvious way around that.
-
-userdict /start-hook {
- TeXDict /df-tail /dvips.df-tail load bind put
- TeXDict /D /dvips.D load bind put
-} put
-
-%%* Introduce a symbolic constant for hyphens. (Need to make
-%%* allowance for hyphen being in different place?)
-
-/.hyphen 45 def
-
-% Write out a string. If it ends in a letter and a hyphen,
-% don't write the hyphen, and set .show.last to a hyphen;
-% otherwise, set .show.last to the character (or \000 if it was a hyphen).
-/.show.write % <string>
- {
- dup length 1 ge
- { dup dup length 1 sub get % string last_char
- dup .hyphen eq % string last_char hyphen?
- { % string last_char
- 1 index length 1 gt
- { 1 index dup length 2 sub get }
- { //.show.last 0 get }
- ifelse % string last_char prev-char
- currentfont /Encoding get exch get % look up prev-char
- //.letter.chars exch known % is it a letter?
- { % Remove the hyphen % string last_char
- exch % last_char string
- dup length 1 sub % last_char string len-1
- 0 exch getinterval % last_char string-1
- exch % string-1 last_char
- }
- { pop 0 } % string 0
- ifelse
- }
- if
- //.show.last 0 3 -1 roll put % store last_char
- % in .show.last
- % If .show.last ==
- % hyphen, then
- % last char of
- % previous string
- % was a hyphen
- }
- if % string
- currentfont /FontType get 0 ne
- {
- { % begin forall % c
- dup % c c
- currentfont /Encoding get % c c vec
- exch get % c name
- dup //.char.map exch known % c name bool
- { exch pop }
- { pop OT1Encoding exch get }
- ifelse % name
- //.char.map exch get % translation
- .show.stdout exch writestring
- }
- forall
- }
- { (\0) dup 0 get 0 eq
- { 0 1 put
- (%stderr) (w) file dup
- (*** Warning: composite font characters dumped without decoding.\n) writestring
- closefile
- }
- { pop
- }
- ifelse
- .show.stdout exch writestring
- }
- ifelse
-} odef
-
-/.showstring1 { % string
- currentpoint .coord % string x y
- 3 -1 roll dup .showwidth % x y string dx dy
- 1 index % x y string dx dy dx
- 0 rmoveto % x y string dx dy
- .dcoord pop % x y string width
- SIMPLE
- { % x y string width
- 2 index % x y string width y
- //.show.y .iget % x y string width y old.y
- %%*
- %%* Replaced test "has y changed" by "has y changed by more
- %%* than the current font height" so that subscripts and
- %%* superscripts won't cause line/paragraph breaks
- %%*
- sub abs dup % x y string width dy dy
- //.show.height .iget
- gt
- { % x y string width dy
-
- %%* Vertical position has changed by more than the font
- %%* height, so we now try to figure out whether we've
- %%* started a new paragraph or merely a new line, using a
- %%* variety of heuristics.
-
- %%* If any of the following is true, we start a new
- %%* paragraph:
-
- %%* (a) the current vertical shift is more than 1.1 times
- %%* the previous vertical shift, where 1.1 is an
- %%* arbitrarily chosen factor that could probably be
- %%* refined.
-
- dup % x y string width dy dy
- //.show.dy .iget 1.1 mul
- gt
- exch
-
- %%* Save the new vertical shift
-
- //.show.dy exch .iput
-
- %%* (b) The vertical shift is more than 1.3 times the
- %%* "size" of the current font. I've removed this
- %%* test since it's not really very useful.
-
-%%* //.show.dy .iget
-%%* //.show.height .iget 1.4 mul
-%%* gt % x y string width bool
-%%* .show.height .iget 0 gt and % only perform test if font
-%%* % height is nonzero
-%%* or
-
- %%* (c) the first character of the new line is one of the
- %%* .break.chars
-
- 2 index length % x y string width newpar? len
- 0 gt % x y string width newpar? len>0?
- {
- 2 index 0 get % x y string width newpar? s
- currentfont /Encoding get
- exch get % x y string width newpar? s_enc
- //.break.chars exch known { pop true } if
- }
- if % x y string width newpar?
-
- %%* (d) The indentation of the new line is greater than
- %%* the indentation of the previous line.
-
- 4 index
- //.show.indent .iget
- gt
- or
-
- %%* HOWEVER, if the line ends in a hyphen, we do NOT begin
- %%* a new paragraph (cf. comment at end of BF2). --dmj,
- %%* 12/23/97
-
- //.show.last 0 get .hyphen ne
- and
-
- % newpar?
- { (\n\n) } % Paragraph
- { % Line
- %%*
- %%* BF2: If last character on a line is
- %%* a hyphen, we omit the hyphen and
- %%* run the lines together. Of
- %%* course, this will fail if a word
- %%* with an explicit hyphen (e.g.,
- %%* X-ray) is split across two lines.
- %%* Oh, well. (What should we do
- %%* about a hyphen that ends a
- %%* "paragraph"? Perhaps that should
- %%* inhibit a paragraph break.)
- %%*
- //.show.last 0 get .hyphen eq
- { () }
- { ( ) }
- ifelse % x y string width char
- }
- ifelse
- //print
-
- //.show.y 3 index .iput % x y string width
- //.show.x 4 index .iput % x y string width
- //.show.indent 4 index .iput
- }
- { % x y string width dy
- % If the word processor split a hyphenated word within
- % the same line, put out the hyphen now.
- pop
- //.show.last 0 get .hyphen eq { (-) //print } if
- }
- ifelse
- %%*
- %%* If have moved more than 1 point to
- %%* the right, interpret it as a
- %%* space? This need to be looked at
- %%* more closely.
- %%*
- 3 index % x y string width x
- //.show.x .iget 10 add gt % x y string width bool
- { ( ) //print }
- if
- % x y string width
- 4 1 roll % width x y string
- .show.write pop % width x
- add //.show.x exch .iput % <empty>
- }
- { (S ) //print .show==4 }
- ifelse
-} odef
-
-/.showstring
- { dup () eq { pop } { .showstring1 } ifelse
- } bind def
-
-% Redefine all the string display operators.
-
-/show {
- .showfont
- .showcolor
- .showstring
-} codef
-
-% We define all the other operators in terms of .show1.
-
-/.show1.string ( ) def
-/.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
-/ashow
- { .showfont .showcolor
- { .show1 2 copy rmoveto } forall
- pop pop
- } codef
-/awidthshow
- { .showfont .showcolor
- { dup .show1 4 index eq { 4 index 4 index rmoveto } if
- 2 copy rmoveto
- }
- forall
- pop pop pop pop pop
- } codef
-/widthshow
- { .showfont .showcolor
- //.show1.string 0 4 -1 roll put
- { //.show1.string search not { exit } if
- .showstring .showstring
- 2 index 2 index rmoveto
- } loop
- .showstring pop pop
- } codef
-/kshow
- { .showfont .showcolor
- %**************** Should construct a closure, in case the procedure
- %**************** affects the o-stack.
- { .show1 dup exec } forall pop
- } codef
-
-% We don't really do the right thing with the Level 2 show operators,
-% but we do something semi-reasonable.
-/xshow { pop show } codef
-/yshow { pop show } codef
-/xyshow { pop show } codef
-/glyphshow
- { currentfont /Encoding .knownget not { {} } if
- 0 1 2 index length 1 sub
- { % Stack: glyph encoding index
- 2 copy get 3 index eq { exch pop exch pop null exit } if
- pop
- }
- for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
- } codef
-
-end
-
-% Bind the operators we just defined, and all the others if we didn't
-% do it before.
-
-DELAYBIND { .bindnow } if
-
-% Make systemdict read-only if it wasn't already.
-
-systemdict wcheck { systemdict readonly pop } if
-
-% Restore the current local/global VM mode.
-
-exec
+% Copyright (C) 1991, 1995, 1996, 1998, 1999 Aladdin Enterprises. All rights reserved. +% +% This software is provided AS-IS with no warranty, either express or +% implied. +% +% This software is distributed under license and may not be copied, +% modified or distributed except as expressly authorized under the terms +% of the license contained in the file LICENSE in this distribution. +% +% For more information about licensing, please refer to +% http://www.ghostscript.com/licensing/. For information on +% commercial licensing, go to http://www.artifex.com/licensing/ or +% contact Artifex Software, Inc., 101 Lucas Valley Road #110, +% San Rafael, CA 94903, U.S.A., +1(415)492-9861. + +% $Id: ps2ascii.ps 10152 2009-10-08 01:53:10Z alexcher $ +% Extract the ASCII text from a PostScript file. Nothing is displayed. +% Instead, ASCII information is written to stdout. The idea is similar to +% Glenn Reid's `distillery', only a lot more simple-minded, and less robust. + +% If SIMPLE is defined, just the text is written, with a guess at line +% breaks and word spacing. If SIMPLE is not defined, lines are written +% to stdout as follows: +% +% F <height> <width> (<fontname>) +% Indicate the font height and the width of a space. +% +% P +% Indicate the end of the page. +% +% S <x> <y> (<string>) <width> +% Display a string. +% +% <width> and <height> are integer dimensions in units of 1/720". +% <x> and <y> are integer coordinates, in units of 1/720", with the origin +% at the lower left. +% <string> and <fontname> are strings represented with the standard +% PostScript escape conventions. + +% If COMPLEX is defined, the following additional types of lines are +% written to stdout. +% +% C <r> <g> <b> +% Indicate the current color. +% +% I <x> <y> <width> <height> +% Note the presence of an image. +% +% R <x> <y> <width> <height> +% Fill a rectangle. +% +% <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000. +% +% Note that future versions of this program (in COMPLEX mode) may add +% other output elements, so programs parsing the output should be +% prepared to ignore elements that they do not recognize. + +% Note that this code will only work in all cases if systemdict is writable +% and if `binding' the definitions of operators defined as procedures +% is deferred. For this reason, it is normally invoked with +% gs -q -dNODISPLAY -dDELAYBIND -dWRITESYSTEMDICT ps2ascii.ps + +% Thanks to: +% J Greely <jgreely@cis.ohio-state.edu> for improvements to this code; +% Jerry Whelan <jerryw@abode.ccd.bnl.gov> for motivating other improvements; +% David M. Jones <dmjones@theory.lcs.mit.edu> for improvements noted below. + +%% Additional modifications by David M. Jones +%% (dmjones@theory.lcs.mit.edu), December 23, 1997 +%% +%% (a) Rewrote forall loop at the end of .show.write. This fixes a +%% stack leakage problem, but the changes are more significant +%% than that. +%% +%% .char.map includes the names of all characters in the +%% StandardEncoding, ISOLatin1Encoding, OT1Encoding and +%% T1Encoding vectors. Thus, if the Encoding vector for the +%% current font contains a name that is not in .char.map, it's +%% redundant to check if the Encoding vector is equal to one of +%% the known vectors. Previous versions of ps2ascii would give +%% up at this point, and substitute an asterisk (*) for the +%% character. I've taken the liberty of instead using the +%% OT1Encoding vector to translate the character, on the grounds +%% that in the cases I'm most interested in, a font without a +%% useful Encoding vector was most likely created by a DVI to PS +%% converter such as dvips or DVILASER (and OT1Encoding is +%% largely compatible with StandardEncoding anyway). [Note that +%% this does not make my earlier changes to support dvips (see +%% fix (a) under my 1996 changes) completely obsolete, since +%% there's additional useful information I can extract in that +%% case.] +%% +%% Overall, this should provide better support for some documents +%% (e.g, DVILASER documents will no longer be translated into a +%% series of *'s) without breaking any other documents any worse +%% than they already were broken. +%% +%% (b) Fixed two bugs in dvips.df-tail: (1) changed "dup 127" to "dup +%% 128" to fix fencepost error, and (2) gave each font it's own +%% FontName rather than having all fonts share the same name. +%% +%% (c) Added one further refinement to the heuristic for detecting +%% paragraph breaks: do not ever start a new paragraph after a +%% line ending in a hyphen. +%% +%% (d) Added a bunch of missing letters from the T1Encoding, +%% OT1Encoding and ISOLatin1Encoding vectors to .letter.chars to +%% improve hyphen-elimination algorithm. This still won't help +%% if there's no useful Encoding vector. +%% +%% NOTE: A better solution to the problem of missing Encoding vectors +%% might be to redefine definefont to check whether the Encoding +%% vector is sensible and, if not, replace it by a default. This +%% would alleviate the need for constant tests in the .show.write +%% loop, as well as automatically solving the problem noted in fix +%% (d) above, and the similar problem with .break.chars. This should +%% be investigated. Also, the hyphen-elimination algorithm really +%% needs to be looked at carefully and rethought. + +%%* Modifications to ps2ascii.ps by David M. Jones +%%* (dmjones@theory.lcs.mit.edu), June 25-July 8, 1996 + +%%* Modifications: +%%* +%%* (a) added code to give better support for dvips files by providing +%%* FontBBox's, FontName's and Encoding vectors for downloaded +%%* bitmap fonts. This is done by using dvips's start-hook to +%%* overwrite the df-tail and D procedures that dvips uses to +%%* define its Type 3 bitmap fonts. Thus, this change should +%%* provide better support for dvips-generated PS files without +%%* affecting the handling of other documents. +%%* +%%* (b) Fixed two bugs that could potentially affect any PS file, not +%%* just those created by dvips: (1) added missing "get" operator +%%* in .show.write and (2) fixed bug that caused a hyphen at the +%%* end of a line to be replaced by a space rather than begin +%%* deleted. Note that the first bug was a source of stack +%%* leakage, causing ps2ascii to run out of operand stack space +%%* occasionally. +%%* +%%* Search for "%%* BF" to find these modifications. +%%* +%%* (c) Improved the heuristic for determining whether a line break +%%* has occurred and whether a line break represents a paragraph +%%* break. Previously, any change in the vertical position caused +%%* a line break; now a line break is only registered if the +%%* change is larger than the height of the current font. This +%%* means that superscripts, subscripts, and such things as +%%* shifted accents generated by TeX won't cause line breaks. +%%* Paragraph-recognition is now done by comparing the indentation +%%* of the new line to the indentation of the previous line and by +%%* comparing the vertical distance between the new line and the +%%* previous line to the vertical distance between the previous +%%* line and its predecessor. +%%* +%%* (d) Added a hook for renaming the files where stdout and stderr +%%* go. +%%* +%%* In general, my additions or changes to the code are described in +%%* comments beginning with "%%*". However, there are numerous other +%%* places where I have either re-formatted code or added comments to +%%* the code while I was trying to understand it. These are usually +%%* not specially marked. +%%* + +/QUIET true def +systemdict wcheck { systemdict } { userdict } ifelse begin +/.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse +/COMPLEX dup where { pop true } { false } ifelse def +/SIMPLE dup where { pop true } { false } ifelse def +/setglobal where + { pop currentglobal /setglobal load true setglobal } + { { } } +ifelse + +% Define a way to store and retrieve integers that survives save/restore. +/.i.string0 (0 ) def +/.i.string .i.string0 length string def +/.iget { cvi } bind def +/.iput { exch //.i.string exch copy cvs pop } bind def +/.inew { //.i.string0 dup length string copy } bind def + +% We only want to redefine operators if they are defined already. + +/codef { 1 index where { pop def } { pop pop } ifelse } def + +% Redefine the end-of-page operators. + +/erasepage { } codef +/copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef +/showpage { copypage erasepage initgraphics } codef + +% Redefine the fill operators to detect rectangles. + +/.orderrect % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h> + { % Ensure llx <= urx, lly <= ury. + 1 index 4 index lt { 4 2 roll } if + dup 3 index lt { 3 1 roll exch } if + exch 3 index sub exch 2 index sub + } odef +/.fillcomplex + { % Do a first pass to see if the path is all rectangles in + % the output coordinate system. We don't worry about overlapping + % rectangles that might be partially not filled. + % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ... + mark true mark + % Add a final moveto so we pick up any trailing unclosed subpath. + 0 0 itransform moveto + { .coord counttomark 2 gt + { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop } ifelse } + if + } + { .coord } + { cleartomark not mark exit } + { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect } + pathforall cleartomark + { .showcolor counttomark 4 idiv + { counttomark -4 roll .orderrect + (R ) //print .show==4 + } + repeat pop + } + { cleartomark + } + ifelse + } odef +/.fillcheckrect + { % Check whether the current subpath is a rectangle. + % If it is, add it to the list of rectangles being accumulated; + % if not exit the .fillcomplex loop. + % The subpath has not been closed. + % Stack: as in .fillcomplex, + newx newy + counttomark 10 eq { 9 index 9 index 4 2 roll } if + counttomark 12 ne { cleartomark not mark exit } if + 12 2 roll + % Check for the two possible forms of rectangles: + % x0 y0 x0 y1 x1 y1 x1 y0 x0 y0 + % x0 y0 x1 y0 x1 y1 x0 y1 x0 y0 + 9 index 2 index eq 9 index 2 index eq and + 10 index 9 index eq + { % Check for first form. + 7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and + } + { % Check for second form. + 9 index 8 index eq and + 8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and + } + ifelse not { cleartomark not mark exit } if + % We have a rectangle. + pop pop pop pop 4 2 roll pop pop 8 4 roll + } odef +/eofill { COMPLEX { .fillcomplex } if newpath } codef +/fill { COMPLEX { .fillcomplex } if newpath } codef +/rectfill { gsave newpath .rectappend fill grestore } codef +/ueofill { gsave newpath uappend eofill grestore } codef +/ufill { gsave newpath uappend fill grestore } codef + +% Redefine the stroke operators to detect rectangles. + +/rectstroke + { gsave newpath + dup type dup /arraytype eq exch /packedarraytype eq or + { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse } + { .rectappend } + ifelse stroke grestore + } codef +/.strokeline % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy> + % Note: fromx and fromy are in output coordinates; + % tox and toy are in user coordinates. + { .coord 2 copy 6 2 roll .orderrect + % Add in the line width. Assume square or round caps. + currentlinewidth 2 div dup .dcoord add abs 1 .max 5 1 roll + 4 index add 4 1 roll 4 index add 4 1 roll + 4 index sub 4 1 roll 5 -1 roll sub 4 1 roll + (R ) //print .show==4 + } odef +/.strokecomplex + { % Do a first pass to see if the path is all horizontal and vertical + % lines in the output coordinate system. + % Stack: true mark origx origy curx cury + true mark null null null null + { .coord 6 2 roll pop pop pop pop 2 copy } + { .coord 1 index 4 index eq 1 index 4 index eq or + { 4 2 roll pop pop } + { cleartomark not mark exit } + ifelse + } + { cleartomark not mark exit } + { counttomark -2 roll 2 copy counttomark 2 roll + 1 index 4 index eq 1 index 4 index eq or + { pop pop 2 copy } + { cleartomark not mark exit } + ifelse + } + pathforall cleartomark + 0 currentlinewidth .dcoord 0 eq exch 0 eq or and + % Do the second pass to write out the rectangles. + % Stack: origx origy curx cury + { .showcolor null null null null + { 6 2 roll pop pop pop pop 2 copy .coord } + { .strokeline } + { } + { 3 index 3 index .strokeline } + pathforall pop pop pop pop + } + if + } odef +/stroke { COMPLEX { .strokecomplex } if newpath } codef +/ustroke + { gsave newpath + dup length 6 eq { exch uappend concat } { uappend } ifelse + stroke grestore + } codef + +% The image operators must read the input and note the dimensions. +% Eventually we should redefine these to detect 1-bit-high all-black images, +% since this is how dvips does underlining (!). + +/.noteimagerect % <width> <height> <matrix> .noteimagerect - + { COMPLEX + { gsave setmatrix itransform 0 0 itransform + grestore .coord 4 2 roll .coord .orderrect + (I ) //print .show==4 + } + { pop pop pop + } + ifelse + } odef +/colorimage where + { pop /colorimage + { 1 index + { dup 6 add index 1 index 6 add index 2 index 5 add index } + { 6 index 6 index 5 index } + ifelse .noteimagerect gsave nulldevice //colorimage grestore + } codef + } if +/.noteimage % Arguments as for image[mask] + { dup type /dicttype eq + { dup /Width get 1 index /Height get 2 index /ImageMatrix get } + { 4 index 4 index 3 index } + ifelse .noteimagerect + } odef +/image { .noteimage gsave nulldevice //image grestore } codef +/imagemask { .noteimage gsave nulldevice //imagemask grestore } codef + +% Output the current color if necessary. +/.color.r .inew def + .color.r -1 .iput % make sure we write the color at the beginning +/.color.g .inew def +/.color.b .inew def +/.showcolor + { COMPLEX + { currentrgbcolor + 1000 mul round cvi + 3 1 roll 1000 mul round cvi + exch 1000 mul round cvi + % Stack: b g r + dup //.color.r .iget eq + 2 index //.color.g .iget eq and + 3 index //.color.b .iget eq and + { pop pop pop + } + { (C ) //print + dup //.color.r exch .iput .show==only + ( ) //print dup //.color.g exch .iput .show==only + ( ) //print dup //.color.b exch .iput .show==only + (\n) //print + } + ifelse + } + if + } bind def + +% Redefine `show'. + +% Set things up so our output will be in tenths of a point, with origin at +% lower left. This isolates us from the peculiarities of individual devices. + +/.show.ident.matrix matrix def +/.show.ident { % - .show.ident <scale> <matrix> +% //.show.ident.matrix defaultmatrix +% % Assume the original transformation is well-behaved. +% 0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def +% 0.1 dup 3 -1 roll scale + gsave initmatrix + % Assume the original transformation is well-behaved... + 0.1 0 dtransform abs exch abs .max + 0.1 dup scale .show.ident.matrix currentmatrix + % ... but undo any rotation into landscape orientation. + dup 0 get 0 eq { + 1 get dup abs div 90 mul rotate + .show.ident.matrix currentmatrix + } if + grestore +} bind def + +/.coord { % <x> <y> .coord <x'> <y'> + transform .show.ident exch pop itransform + exch round cvi exch round cvi +} odef + +/.dcoord { % <dx> <dy> .coord <dx'> <dy'> + % Transforming distances is trickier, because + % the coordinate system might be rotated. + .show.ident pop 3 1 roll + exch 0 dtransform + dup mul exch dup mul add sqrt + 2 index div round cvi + exch 0 exch dtransform + dup mul exch dup mul add sqrt + 3 -1 roll div round cvi +} odef + +% Remember the current X, Y, and height. +/.show.x .inew def +/.show.y .inew def +/.show.height .inew def + +% Remember the last character of the previous string; if it was a +% hyphen preceded by a letter, we didn't output the hyphen. + +/.show.last (\000) def + +% Remember the current font. +/.font.name 130 string def +/.font.name.length .inew def +/.font.height .inew def +/.font.width .inew def + +%%* Also remember indentation of current line and previous vertical +%%* skip + +/.show.indent .inew def +/.show.dy .inew def + +% We have to redirect stdout somehow.... + +/.show.stdout { (%stdout) (w) file } bind def + +% Make sure writing will work even if a program uses =string. +/.show.string =string length string def +/.show.=string =string length string def +/.show==only + { //=string //.show.=string copy pop + dup type /stringtype eq + { dup length //.show.string length le + { dup rcheck { //.show.string copy } if + } if + } if + .show.stdout exch write==only + //.show.=string //=string copy pop + } odef +/.show==4 + { 4 -1 roll .show==only ( ) //print + 3 -1 roll .show==only ( ) //print + exch .show==only ( ) //print + .show==only (\n) //print + } odef + +/.showwidth % Same as stringwidth, but disable COMPLEX so that + % we don't try to detect rectangles during BuildChar. + { COMPLEX + { /COMPLEX false def stringwidth /COMPLEX true def } + { stringwidth } + ifelse + } odef + +/.showfont % <string> .showfont <string> + { gsave + % Try getting the height and width of the font from the FontBBox. + currentfont /FontBBox .knownget not { {0 0 0 0} } if + aload pop % llx lly urx ury + exch 4 -1 roll % lly ury urx llx + sub % lly ury dx + 3 1 roll exch % dx ury lly + sub % dx dy + 2 copy .max 0 ne + { currentfont /FontMatrix get dtransform + } + { pop pop + % Fonts produced by dvips, among other applications, have + % BuildChar procedures that bomb out when given unexpected + % characters, and there is no way to determine whether a given + % character will do this. So for Type 1 fonts, we measure a + % typical character ('X'); for others, we punt. + currentfont /FontType get 1 eq + { (X) .showwidth pop dup 1.3 mul + } + { % No safe way to get the character size. Punt. + 0 0 + } + ifelse + } + ifelse .dcoord exch + currentfont /FontName .knownget not { () } if + dup type /stringtype ne { //.show.string cvs } if + grestore + % Stack: height width fontname + SIMPLE + { pop pop //.show.height exch .iput } + { 2 index //.font.height .iget eq + 2 index //.font.width .iget eq and + 1 index //.font.name 0 //.font.name.length .iget getinterval eq and + { pop pop pop + } + { (F ) //print + 3 -1 roll dup //.font.height exch .iput .show==only ( ) //print + exch dup //.font.width exch .iput .show==only ( ) //print + dup length //.font.name.length exch .iput + //.font.name cvs .show==only (\n) //print + } + ifelse + } + ifelse + } odef + +% Define the letters -- characters which, if they occur followed by a hyphen +% at the end of a line, cause the hyphen and line break to be ignored. +/.letter.chars 100 dict def +mark + 65 1 90 { dup 32 add } for + counttomark + { StandardEncoding exch get .letter.chars exch dup put } + repeat +pop + +%%* Add the rest of the letters from the [O]T1Encoding and +%%* ISOLatin1Encoding vectors + +mark + /AE + /Aacute + /Abreve + /Acircumflex + /Adieresis + /Agrave + /Aogonek + /Aring + /Atilde + /Cacute + /Ccaron + /Ccedilla + /Dcaron + /Eacute + /Ecaron + /Ecircumflex + /Edieresis + /Egrave + /Eng + /Eogonek + /Eth + /Gbreve + /Germandbls + /IJ + /Iacute + /Icircumflex + /Idieresis + /Idot + /Igrave + /Lacute + /Lcaron + /Lslash + /Nacute + /Ncaron + /Ntilde + /OE + /Oacute + /Ocircumflex + /Odieresis + /Ograve + /Ohungarumlaut + /Oslash + /Otilde + /Racute + /Rcaron + /Sacute + /Scaron + /Scedilla + /Tcaron + /Tcedilla + /Thorn + /Uacute + /Ucircumflex + /Udieresis + /Ugrave + /Uhungarumlaut + /Uring + /Yacute + /Ydieresis + /Zacute + /Zcaron + /Zdot + /aacute + /abreve + /acircumflex + /adieresis + /ae + /agrave + /aogonek + /aring + /atilde + /cacute + /ccaron + /ccedilla + /dbar + /dcaron + /dotlessi + /dotlessj + /eacute + /ecaron + /ecircumflex + /edieresis + /egrave + /eng + /eogonek + /eth + /exclamdown + /ff + /ffi + /ffl + /fi + /fl + /gbreve + /germandbls + /iacute + /icircumflex + /idieresis + /igrave + /ij + /lacute + /lcaron + /lslash + /nacute + /ncaron + /ntilde + /oacute + /ocircumflex + /odieresis + /oe + /ograve + /ohungarumlaut + /oslash + /otilde + /questiondown + /racute + /rcaron + /sacute + /scaron + /scedilla + /section + /sterling + /tcaron + /tcedilla + /thorn + /uacute + /ucircumflex + /udieresis + /ugrave + /uhungarumlaut + /uring + /yacute + /ydieresis + /zacute + /zcaron + /zdot +counttomark + { .letter.chars exch dup put } +repeat +pop + +% Define a set of characters which, if they occur at the start of a line, +% are taken as indicating a paragraph break. +/.break.chars 50 dict def +mark + /bullet /dagger /daggerdbl /periodcentered /section + counttomark + { .break.chars exch dup put } + repeat +pop + +% Define character translation to ASCII. +% We have to do this for the entire character set. + +/.char.map 500 dict def + +/.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def + +% Encode the printable ASCII characters. + +mark 32 1 126 + { 1 string dup 0 4 -1 roll put + dup 0 get StandardEncoding exch get exch + } +for .chars.def + + % Encode accents. +mark + /acute (') + /caron (^) + /cedilla (,) + /circumflex (^) + /dieresis (") + /grave (`) + /ring (*) + /tilde (~) +.chars.def + + % Encode the ISO accented characters. +mark 192 1 255 + { ISOLatin1Encoding exch get =string cvs + dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval + .char.map 2 index known .char.map 2 index known and + { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings + .char.map 3 1 roll put + } + { pop pop pop + } + ifelse + } +for .chars.def + +% Encode the remaining standard and ISO alphabetic characters. + +mark + /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th) + /ae (ae) /eth (dh) + /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl) + /germandbls (ss) /oe (oe) /thorn (th) +.chars.def + +% Encode the other standard and ISO characters. + +mark + /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#) + /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.) + /dotlessi (i) + /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!) + /florin (f) /fraction (/) + /guillemotleft (<<) /guillemotright (>>) + /guilsinglleft (<) /guilsinglright (>) /hungarumlaut ("") /logicalnot (~) + /macron (_) /minus (-) /mu (u) /multiply (*) + /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1) + /ordfeminine (-a) /ordmasculine (-o) + /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-) + /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (") + /quotesinglbase (,) /quotesingle (') /registered ((R)) + /section ($) /sterling (#) + /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2) + /yen (Y) +.chars.def + +% Encode a few common Symbol characters. + +mark + /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C)) + /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R)) + /trademarksans ((TM)) /trademarkserif ((TM)) +.chars.def + +%%* Add a few characters from StandardEncoding and ISOLatin1Encoding +%%* that were missing. + +mark + /cent (c) + /guilsinglleft (<) + /guilsinglright (>) + /breve (*) + /Lslash (L/) + /lslash (l/) +.chars.def + +%%* Define the OT1Encoding and T1Encoding vectors for use with dvips +%%* files. Unfortunately, there's no way of telling what font is +%%* really being used within a dvips document, so we can't provide an +%%* appropriate encoding for each individual font. Instead, we'll +%%* just provide support for the two most popular text encodings, the +%%* OT1 and T1 encodings, and just accept the fact that any font not +%%* using one of those encodings will be rendered as gibberish. +%%* +%%* OT1 is Knuth's 7-bit encoding for the CMR text fonts, while T1 +%%* (aka the Cork encoding) is the 8-bit encoding used by the DC +%%* fonts, a preliminary version of the proposed Extended Computer +%%* Modern fonts. Unfortunately, T1 is not a strict extension of OT1; +%%* they differ in positions 8#000 through 8#040, 8#074, 8#076, 8#134, +%%* 8#137, 8#173, 8#174, 8#175 and 8#177, so we can't use the same +%%* vector for both. +%%* +%%* Of course, we also can't reliably tell the difference between an +%%* OT1-encoded font and a T1-encoded font based on the information in +%%* a dvips-created PostScript file. As a best-guess solution, we'll +%%* use the T1 encoding if the font contains any characters in +%%* positions above 8#177 and the OT1 encoding if it doesn't. + +/T1Encoding 256 array def + +/OT1Encoding 256 array def + +%%* T1Encoding shares a lot with StandardEncoding, so let's start +%%* there. + +StandardEncoding T1Encoding copy pop + +/OT1.encode { + counttomark + 2 idiv + { OT1Encoding 3 1 roll put } + repeat + cleartomark +} def + +/T1.encode { + counttomark + 2 idiv + { T1Encoding 3 1 roll put } + repeat + cleartomark +} def + +mark + 8#000 /grave + 8#001 /acute + 8#002 /circumflex + 8#003 /tilde + 8#004 /dieresis + 8#005 /hungarumlaut + 8#006 /ring + 8#007 /caron + + 8#010 /breve + 8#011 /macron + 8#012 /dotaccent + 8#013 /cedilla + 8#014 /ogonek + 8#015 /quotesinglbase + 8#016 /guilsinglleft + 8#017 /guilsinglright + + 8#020 /quotedblleft + 8#021 /quotedblright + 8#022 /quotedblbase + 8#023 /guillemotleft + 8#024 /guillemotright + 8#025 /endash + 8#026 /emdash + 8#027 /cwm + + 8#030 /perthousandzero + 8#031 /dotlessi + 8#032 /dotlessj + 8#033 /ff + 8#034 /fi + 8#035 /fl + 8#036 /ffi + 8#037 /ffl + +%% 8#040 through 8#176 follow StandardEncoding + + 8#177 /hyphen +T1.encode + +mark + 8#200 /Abreve + 8#201 /Aogonek + 8#202 /Cacute + 8#203 /Ccaron + 8#204 /Dcaron + 8#205 /Ecaron + 8#206 /Eogonek + 8#207 /Gbreve + 8#210 /Lacute + 8#211 /Lcaron + 8#212 /Lslash + 8#213 /Nacute + 8#214 /Ncaron + 8#215 /Eng + 8#216 /Ohungarumlaut + 8#217 /Racute + 8#220 /Rcaron + 8#221 /Sacute + 8#222 /Scaron + 8#223 /Scedilla + 8#224 /Tcaron + 8#225 /Tcedilla + 8#226 /Uhungarumlaut + 8#227 /Uring + 8#230 /Ydieresis + 8#231 /Zacute + 8#232 /Zcaron + 8#233 /Zdot + 8#234 /IJ + 8#235 /Idot + 8#236 /dbar + 8#237 /section + 8#240 /abreve + 8#241 /aogonek + 8#242 /cacute + 8#243 /ccaron + 8#244 /dcaron + 8#245 /ecaron + 8#246 /eogonek + 8#247 /gbreve + 8#250 /lacute + 8#251 /lcaron + 8#252 /lslash + 8#253 /nacute + 8#254 /ncaron + 8#255 /eng + 8#256 /ohungarumlaut + 8#257 /racute + 8#260 /rcaron + 8#261 /sacute + 8#262 /scaron + 8#263 /scedilla + 8#264 /tcaron + 8#265 /tcedilla + 8#266 /uhungarumlaut + 8#267 /uring + 8#270 /ydieresis + 8#271 /zacute + 8#272 /zcaron + 8#273 /zdot + 8#274 /ij + 8#275 /exclamdown + 8#276 /questiondown + 8#277 /sterling + + 8#300 /Agrave + 8#301 /Aacute + 8#302 /Acircumflex + 8#303 /Atilde + 8#304 /Adieresis + 8#305 /Aring + 8#306 /AE + 8#307 /Ccedilla + 8#310 /Egrave + 8#311 /Eacute + 8#312 /Ecircumflex + 8#313 /Edieresis + 8#314 /Igrave + 8#315 /Iacute + 8#316 /Icircumflex + 8#317 /Idieresis + 8#320 /Eth + 8#321 /Ntilde + 8#322 /Ograve + 8#323 /Oacute + 8#324 /Ocircumflex + 8#325 /Otilde + 8#326 /Odieresis + 8#327 /OE + 8#330 /Oslash + 8#331 /Ugrave + 8#332 /Uacute + 8#333 /Ucircumflex + 8#334 /Udieresis + 8#335 /Yacute + 8#336 /Thorn + 8#337 /Germandbls + + 8#340 /agrave + 8#341 /aacute + 8#342 /acircumflex + 8#343 /atilde + 8#344 /adieresis + 8#345 /aring + 8#346 /ae + 8#347 /ccedilla + 8#350 /egrave + 8#351 /eacute + 8#352 /ecircumflex + 8#353 /edieresis + 8#354 /igrave + 8#355 /iacute + 8#356 /icircumflex + 8#357 /idieresis + 8#360 /eth + 8#361 /ntilde + 8#362 /ograve + 8#363 /oacute + 8#364 /ocircumflex + 8#365 /otilde + 8#366 /odieresis + 8#367 /oe + 8#370 /oslash + 8#371 /ugrave + 8#372 /uacute + 8#373 /ucircumflex + 8#374 /udieresis + 8#375 /yacute + 8#376 /thorn + 8#377 /germandbls + +T1.encode + +%%* Now copy OT1Encoding into T1Encoding and make a few changes. + +T1Encoding OT1Encoding copy pop + +mark + 8#000 /Gamma + 8#001 /Delta + 8#002 /Theta + 8#003 /Lambda + 8#004 /Xi + 8#005 /Pi + 8#006 /Sigma + 8#007 /Upsilon + + 8#010 /Phi + 8#011 /Psi + 8#012 /Omega + 8#013 /ff + 8#014 /fi + 8#015 /fl + 8#016 /ffi + 8#017 /ffl + + 8#020 /dotlessi + 8#021 /dotlessj + 8#022 /grave + 8#023 /acute + 8#024 /caron + 8#025 /breve + 8#026 /macron + 8#027 /ring + + 8#030 /cedilla + 8#031 /germandbls + 8#032 /ae + 8#033 /oe + 8#034 /oslash + 8#035 /AE + 8#036 /OE + 8#037 /Oslash + + 8#040 /polishslash + + 8#042 /quotedblright + + 8#074 /exclamdown + 8#076 /questiondown + + 8#134 /quotedblleft + 8#137 /dotaccent + + 8#173 /endash + 8#174 /emdash + 8#175 /hungarumlaut + 8#177 /dieresis +OT1.encode + +%%* And add a few characters from the OT1Encoding + +mark + /Gamma (\\Gamma ) + /Delta (\\Delta ) + /Theta (\\Theta ) + /Lambda (\\Lambda ) + /Xi (\\Xi ) + /Pi (\\Pi ) + /Sigma (\\Sigma ) + /Upsilon (\\Upsilon ) + + /Phi (\\Phi ) + /Psi (\\Psi ) + /Omega (\\Omega ) + + /dotlessj (j) + /ff (ff) + + /cwm () + + /perthousandzero (0) + + /polishslash () + + /Abreve (A*) + /Aogonek (A,) + /Cacute (C') + /Ccaron (C^) + /Dcaron (D^) + /Ecaron (E^) + /Eogonek (E,) + /Gbreve (G*) + /Lacute (L') + /Lcaron (L^) + /Nacute (N') + /Ncaron (N^) + /Eng (NG) + /Ohungarumlaut (O"") + /Racute (R') + /Rcaron (R^) + /Sacute (S') + /Scaron (S^) + /Scedilla (S,) + /Tcaron (T^) + /Tcedilla (T,) + /Uhungarumlaut (U"") + /Uring (U*) + /Ydieresis (Y") + /Zacute (Z') + /Zcaron (Z^) + /Zdot (Z.) + /IJ (IJ) + /Idot (I.) + /dbar (d-) + /abreve (a*) + /aogonek (a,) + /cacute (c') + /ccaron (c^) + /dcaron (d^) + /ecaron (e^) + /eogonek (e,) + /gbreve (g*) + /lacute (l') + /lcaron (l^) + /nacute (n') + /ncaron (n^) + /eng (ng) + /ohungarumlaut (o"") + /racute (r') + /rcaron (r^) + /sacute (s') + /scaron (s^) + /scedilla (s,) + /tcaron (t^) + /tcedilla (t,) + /uhungarumlaut (u"") + /uring (u*) + /zacute (z') + /zcaron (z^) + /zdot (z.) + /ij (ij) + /Germandbls (SS) +.chars.def + +%%* We extend the df-tail command to stick in an Encoding vector (see +%%* above for a discussion of the T1 and OT1 encodings), put in a +%%* FontName (which will just be dvips's name for the font, i.e., Fa, +%%* Fb, etc.) and give each font a separate FontBBox instead of +%%* letting them all share a single one. + +/dvips.df-tail % id numcc maxcc df-tail + { + /nn 9 dict N + nn begin + %% + %% Choose an encoding based on the highest position occupied. + %% + dup 128 gt { T1Encoding } { OT1Encoding } ifelse + /Encoding X + /FontType 3 N + %% + %% It's ok for all the fonts to share a FontMatrix, but they + %% need to have separate FontBBoxes + %% + /FontMatrix fntrx N + /FontBBox [0 0 0 0] N + string /base X + array /BitMaps X + %% + %% And let's throw in a FontName for good measure + %% + dup ( ) cvs + %% + %% Make sure each font gets it own private FontName. -- dmj, + %% 12/23/97 + %% + dup length string copy + /FontName X + /BuildChar {CharBuilder} N + end + dup { /foo setfont } + 2 array copy cvx N + load + 0 nn put + /ctr 0 N + [ +} def + +%%* This is functionally equivalent to dvips's /D procedure, but it +%%* also calculates the Font Bounding Box while defining the +%%* characters. + +/dvips.D % char-data ch D - : define character bitmap in current font +{ + /cc X % char-data + dup type /stringtype ne {]} if % char-data + + /ch-xoff where + { pop } + { dup /Cd exch def + /ch-width { Cw } def + /ch-height { Ch } def + /ch-xoff { Cx } def + /ch-yoff { Cy } def + /ch-dx { Cdx } def + } ifelse + /ch-data X + nn /base get cc ctr put % (adds ctr to cc'th position of BASE) + nn /BitMaps get + ctr + ch-data % BitMaps ctr char-data + sf 1 ne { + dup dup length 1 sub dup 2 index S get sf div put + } if + put % puts char-data into BitMaps at index ctr + /ctr ctr 1 add N +%% +%% Make sure the Font Bounding Box encloses the Bounding Box of the +%% current character +%% + nn /FontBBox get % BB + + dup % calculate new llx + dup 0 get + ch-xoff + .min + 0 exch put + + dup % calculate new lly + dup 1 get + ch-yoff ch-height sub + .min + 1 exch put + + dup % calculate new urx + dup 2 get + ch-dx ch-width add + .max + 2 exch put + + dup 3 get % calculate new ury + ch-yoff + .max + 3 exch put + +} def + +%%* Define start-hook to replace df-tail and D by our versions. +%%* Unfortunately, the user can redefine start-hook and thus bypass +%%* these changes, but I don't see an obvious way around that. + +userdict /start-hook { + TeXDict /df-tail /dvips.df-tail load bind put + TeXDict /D /dvips.D load bind put +} put + +%%* Introduce a symbolic constant for hyphens. (Need to make +%%* allowance for hyphen being in different place?) + +/.hyphen 45 def + +% Write out a string. If it ends in a letter and a hyphen, +% don't write the hyphen, and set .show.last to a hyphen; +% otherwise, set .show.last to the character (or \000 if it was a hyphen). +/.show.write % <string> + { + dup length 1 ge + { dup dup length 1 sub get % string last_char + dup .hyphen eq % string last_char hyphen? + { % string last_char + 1 index length 1 gt + { 1 index dup length 2 sub get } + { //.show.last 0 get } + ifelse % string last_char prev-char + currentfont /Encoding get exch get % look up prev-char + //.letter.chars exch known % is it a letter? + { % Remove the hyphen % string last_char + exch % last_char string + dup length 1 sub % last_char string len-1 + 0 exch getinterval % last_char string-1 + exch % string-1 last_char + } + { pop 0 } % string 0 + ifelse + } + if + //.show.last 0 3 -1 roll put % store last_char + % in .show.last + % If .show.last == + % hyphen, then + % last char of + % previous string + % was a hyphen + } + if % string + currentfont /FontType get 0 ne + { + { % begin forall % c + dup % c c + currentfont /Encoding get % c c vec + exch get % c name + dup //.char.map exch known % c name bool + { exch pop } + { pop OT1Encoding exch get } + ifelse % name + //.char.map exch get % translation + .show.stdout exch writestring + } + forall + } + { (\0) dup 0 get 0 eq + { 0 1 put + (%stderr) (w) file dup + (*** Warning: composite font characters dumped without decoding.\n) writestring + closefile + } + { pop + } + ifelse + .show.stdout exch writestring + } + ifelse +} odef + +/.showstring1 { % string + currentpoint .coord % string x y + 3 -1 roll dup .showwidth % x y string dx dy + 1 index % x y string dx dy dx + 0 rmoveto % x y string dx dy + .dcoord pop % x y string width + SIMPLE + { % x y string width + 2 index % x y string width y + //.show.y .iget % x y string width y old.y + %%* + %%* Replaced test "has y changed" by "has y changed by more + %%* than the current font height" so that subscripts and + %%* superscripts won't cause line/paragraph breaks + %%* + sub abs dup % x y string width dy dy + //.show.height .iget + gt + { % x y string width dy + + %%* Vertical position has changed by more than the font + %%* height, so we now try to figure out whether we've + %%* started a new paragraph or merely a new line, using a + %%* variety of heuristics. + + %%* If any of the following is true, we start a new + %%* paragraph: + + %%* (a) the current vertical shift is more than 1.1 times + %%* the previous vertical shift, where 1.1 is an + %%* arbitrarily chosen factor that could probably be + %%* refined. + + dup % x y string width dy dy + //.show.dy .iget 1.1 mul + gt + exch + + %%* Save the new vertical shift + + //.show.dy exch .iput + + %%* (b) The vertical shift is more than 1.3 times the + %%* "size" of the current font. I've removed this + %%* test since it's not really very useful. + +%%* //.show.dy .iget +%%* //.show.height .iget 1.4 mul +%%* gt % x y string width bool +%%* .show.height .iget 0 gt and % only perform test if font +%%* % height is nonzero +%%* or + + %%* (c) the first character of the new line is one of the + %%* .break.chars + + 2 index length % x y string width newpar? len + 0 gt % x y string width newpar? len>0? + { + 2 index 0 get % x y string width newpar? s + currentfont /Encoding get + exch get % x y string width newpar? s_enc + //.break.chars exch known { pop true } if + } + if % x y string width newpar? + + %%* (d) The indentation of the new line is greater than + %%* the indentation of the previous line. + + 4 index + //.show.indent .iget + gt + or + + %%* HOWEVER, if the line ends in a hyphen, we do NOT begin + %%* a new paragraph (cf. comment at end of BF2). --dmj, + %%* 12/23/97 + + //.show.last 0 get .hyphen ne + and + + % newpar? + { (\n\n) } % Paragraph + { % Line + %%* + %%* BF2: If last character on a line is + %%* a hyphen, we omit the hyphen and + %%* run the lines together. Of + %%* course, this will fail if a word + %%* with an explicit hyphen (e.g., + %%* X-ray) is split across two lines. + %%* Oh, well. (What should we do + %%* about a hyphen that ends a + %%* "paragraph"? Perhaps that should + %%* inhibit a paragraph break.) + %%* + //.show.last 0 get .hyphen eq + { () } + { (\n) } + ifelse % x y string width char + } + ifelse + //print + + //.show.y 3 index .iput % x y string width + //.show.x 4 index .iput % x y string width + //.show.indent 4 index .iput + } + { % x y string width dy + % If the word processor split a hyphenated word within + % the same line, put out the hyphen now. + pop + //.show.last 0 get .hyphen eq { (-) //print } if + } + ifelse + %%* + %%* If have moved more than 1 point to + %%* the right, interpret it as a + %%* space? This need to be looked at + %%* more closely. + %%* + 3 index % x y string width x + //.show.x .iget 10 add gt % x y string width bool + { ( ) //print } + if + % x y string width + 4 1 roll % width x y string + .show.write pop % width x + add //.show.x exch .iput % <empty> + } + { (S ) //print .show==4 } + ifelse +} odef + +/.showstring + { dup () eq { pop } { .showstring1 } ifelse + } bind def + +% Redefine all the string display operators. + +/show { + .showfont + .showcolor + .showstring +} codef + +% We define all the other operators in terms of .show1. + +/.show1.string ( ) def +/.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef +/ashow + { .showfont .showcolor + { .show1 2 copy rmoveto } forall + pop pop + } codef +/awidthshow + { .showfont .showcolor + { dup .show1 4 index eq { 4 index 4 index rmoveto } if + 2 copy rmoveto + } + forall + pop pop pop pop pop + } codef +/widthshow + { .showfont .showcolor + //.show1.string 0 4 -1 roll put + { //.show1.string search not { exit } if + .showstring .showstring + 2 index 2 index rmoveto + } loop + .showstring pop pop + } codef +/kshow + { .showfont .showcolor + %**************** Should construct a closure, in case the procedure + %**************** affects the o-stack. + { .show1 dup exec } forall pop + } codef + +% We don't really do the right thing with the Level 2 show operators, +% but we do something semi-reasonable. +/xshow { pop show } codef +/yshow { pop show } codef +/xyshow { pop show } codef +/glyphshow + { currentfont /Encoding .knownget not { {} } if + 0 1 2 index length 1 sub + { % Stack: glyph encoding index + 2 copy get 3 index eq { exch pop exch pop null exit } if + pop + } + for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse + } codef + +end + +% Bind the operators we just defined, and all the others if we didn't +% do it before. + +DELAYBIND { .bindnow } if + +% Make systemdict read-only if it wasn't already. + +systemdict wcheck { systemdict readonly pop } if + +% Restore the current local/global VM mode. + +exec |