% Copyright (C) 1991, 1992, 1993 Aladdin Enterprises. All rights reserved. % % This file is part of Ghostscript. % % Ghostscript is distributed in the hope that it will be useful, but % WITHOUT ANY WARRANTY. No author or distributor accepts responsibility % to anyone for the consequences of using it or for whether it serves any % particular purpose or works at all, unless he says so in writing. Refer % to the Ghostscript General Public License for full details. % % Everyone is granted permission to copy, modify and redistribute % Ghostscript, but only under the conditions described in the Ghostscript % General Public License. A copy of this license is supposed to have been % given to you along with Ghostscript so you can know your rights and % responsibilities. It should be in a file named COPYING. Among other % things, the copyright notice and this notice must be preserved on all % copies. % Extract the ASCII text from a PostScript file. Nothing is displayed. % Instead, ASCII information is written to stdout. 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 () % indicate font height and width of a space % % S () % display a string % % P % end of page % % is an integer expressed in tenths of a point % is an integer in tenths of a point. % and are integer coordinates, in tenths of a point, with origin % at lower left. % and are strings represented with the standard % PostScript escape conventions. % The idea is similar to Glenn Reid's `distillery', only a lot more % simple-minded, and less robust. % 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 -dNOBIND -dWRITESYSTEMDICT ps2ascii.ps % Thanks to J Greely for improvements % to this code. /QUIET true def systemdict wcheck { systemdict } { userdict } ifelse begin /SIMPLE dup where { pop true } { false } ifelse def % Disable the display operators. /eofill { newpath } odef /erasepage { } odef /fill { newpath } odef /stroke { newpath } odef % The image operators must read the input, but do nothing. /colorimage { gsave nulldevice //colorimage grestore } odef /image { gsave nulldevice //image grestore } odef /imagemask { gsave nulldevice //imagemask grestore } odef % Redefine the end-of-page operators. /copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } odef /showpage { copypage erasepage initgraphics } odef % 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.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 /.show.scale exch def 0.1 dup scale .show.ident.matrix currentmatrix grestore } bind def /.coord { transform .show.ident itransform exch round cvi exch round cvi } odef /.dcoord { % Transforming distances is trickier, because % the coordinate system might be rotated. .show.ident pop exch 0 dtransform % dup 0 ne { dup mul exch dup mul add sqrt } { pop abs } ifelse dup mul exch dup mul add sqrt .show.scale div round cvi exch 0 exch dtransform % exch dup 0 ne { dup mul exch dup mul add sqrt } { pop abs } ifelse dup mul exch dup mul add sqrt .show.scale div round cvi } odef % Define a way to store and retrieve integers that survives save/restore. /.i.string ( ) def /.iget { cvi } bind def /.iput { exch //.i.string exch copy cvs pop } bind def /.inew { //.i.string length string dup 3 -1 roll .iput } bind def /.show.x 0 .inew def /.show.y 0 .inew def /.show.height 1000 .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 % 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 //.stdout exch write==only //.show.=string //=string copy pop } odef /.showfont %(following comments are from J Greely) %old code - This didn't work right for me with all fonts. % % { 0 currentfont /FontBBox get dup 3 get exch 1 get sub % currentfont /FontMatrix get dtransform dtransform % exch abs exch abs max round % (F ) //print //.stdout exch write==only (\n) //print % } odef % %unfortunately, my way bombs on one of my test files in %--%show_continue--(?!). It's from dvi2ps, which molests %the fonts in some way. --jgreely { gsave % If we can't get the height and width of the font from % the FontBBox, we just measure some characters. currentfont /FontBBox .knownget not { {0 0 0 0} } if aload pop exch 4 -1 roll sub 3 1 roll exch sub 2 copy max 0 ne { currentfont /FontMatrix get dtransform } { % Unfortunately, charpath is broken in some versions, % so we use stringwidth and fudge. (X) stringwidth pop dup 1.3 mul } ifelse .dcoord exch currentfont /FontName .knownget not { () } if dup type /nametype eq { //.show.string cvs } if grestore % Stack: height width fontname SIMPLE { pop pop //.show.height exch .iput } { (F ) //print 3 { 2 index .show==only ( ) //print 3 -1 roll } repeat pop pop pop (\n) //print } 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 % 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 (>>) /guilsingleft (<) /guilsingright (>) /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 % 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 % { dup length 1 ge { dup dup length 1 sub get dup 45 eq % hyphen { 1 index length 1 gt { 1 index dup length 2 sub get } { //.show.last 0 get } ifelse currentfont /Encoding get exch get //.letter.chars exch known { % Remove the hyphen exch dup length 1 sub 0 exch getinterval exch } { pop 0 } ifelse } if //.show.last 0 3 -1 roll put } if { dup currentfont /Encoding get exch get dup //.char.map exch .knownget { //.stdout exch writestring pop pop } { currentfont /Encoding dup StandardEncoding eq exch ISOLatin1Encoding eq or { % Untranslated character in standard encoding pop //.stdout exch write } { % Character in non-standard encoding, substitute pop pop //.stdout (*) writestring } ifelse } ifelse } forall } odef /.showstring { currentpoint .coord 3 -1 roll dup stringwidth 1 index 0 rmoveto .dcoord pop % Stack: x y string width SIMPLE { 2 index //.show.y .iget ne { % Try to figure out whether we have a line break % or a paragraph break. 2 index //.show.y .iget sub abs //.show.height .iget 1.3 mul ge 2 index length 0 gt { 2 index 0 get currentfont /Encoding get exch get //.break.chars exch known { pop true } if } if { (\n\n) % Paragraph } { ( ) % Line } ifelse //print //.show.y 3 index .iput //.show.x 4 index .iput } { % If the word processor split a hyphenated word within % the same line, put out the hyphen now. //.show.last 0 get 45 eq { (-) //print } if } ifelse 3 index //.show.x .iget 10 add gt { ( ) //print } if 4 1 roll .show.write pop add //.show.x exch .iput } { (S ) //print 4 -1 roll .show==only ( ) //print 3 -1 roll .show==only ( ) //print exch .show==only ( ) //print .show==only (\n) //print } ifelse } odef /show { .showfont .showstring } odef % Redefine the other string display operators in terms of `show'. /.show1.string ( ) def /.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef /ashow { .showfont { .show1 2 copy rmoveto } forall pop pop } odef /awidthshow { .showfont { dup .show1 4 index eq { 4 index 4 index rmoveto } if 2 copy rmoveto } forall pop pop pop pop pop } odef /widthshow { .showfont //.show1.string 0 4 -1 roll put { //.show1.string search not { exit } if .showstring .showstring 2 index 2 index rmoveto } loop .showstring pop pop } odef /kshow { .showfont { .show1 dup exec } forall pop } odef % Redirect the printing operators. /.stdout (_temp_.out) (w) file def /.stderr (_temp_.err) (w) file def /print { //.stdout exch writestring } odef end % Bind the operators we just defined, and all the others if we didn't % do it before. Also reenable 'bind' for future files. .bindoperators NOBIND currentdict systemdict ne and { systemdict begin .bindoperators end } if NOBIND { /bind /.bind load def } if % Make systemdict read-only if it wasn't already. systemdict wcheck { systemdict readonly pop } if