summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRay Johnston <ray.johnston@artifex.com>2020-04-23 18:23:17 -0700
committerRay Johnston <ray.johnston@artifex.com>2020-04-24 08:36:51 -0700
commit7c96228899ea05b40cdb31dc5a4c3f61aa0d39e6 (patch)
treef861535b53c95df618e28a2d7d3bb6c9b26d9ba1 /lib
parent01b1eb1ef43952026ed8bf8728744522abfbfc19 (diff)
downloadghostpdl-7c96228899ea05b40cdb31dc5a4c3f61aa0d39e6.tar.gz
Fix Bug 702014: ps2epsi problems (regression?).
The ps2epsi and ps2epsi.ps were quite a mess, and relied on non-standard operators only available with -dNOSAFER since we made SAFER the default. Even running ps2epsi with -dNOSAFER (by export GS_OPTIONS=-dNOSAFER) had problems -- it could not even convert examples/colorcir.ps to EPSI (throwing an error about colorcirsave). Both of the aforementioned files are replaced with this commit, and the ps2epsi.bat and ps2epsi.cmd are updated to use the new ps2epsi.ps file Also, input files with multiple pages were never correct since the preview was derived only from the first page. The ps2epsi.ps checks if the file is already an EPSF, then don't use eps2write on the input, but warn if the %%Pages comment indicates that there is more than a single page. Note that -dNOOUTERSAVE is needed in the invocation so that if we use eps2write, the 'restore' will close the device and write the tempfile with the EPSF. Then ps2epsi.ps reads the input file, capturing the BBox, stops after %%EndComments, removes any existing preview, constructs a new preview using the 'bit' device with appropriate parameters, writes the preview in the EPSI Preview format (using writehexstring) and then copies the remainder of the EPSF file to the output. The ps2epsi.ps has some checking for valid invocation, since someone may try to use it without the scripts. Since all of the actual conversion is done by the ps2epsi.ps, this change makes windows and linux produce equivalent files.
Diffstat (limited to 'lib')
-rwxr-xr-xlib/ps2epsi103
-rwxr-xr-xlib/ps2epsi.bat26
-rwxr-xr-xlib/ps2epsi.cmd26
-rw-r--r--lib/ps2epsi.ps383
4 files changed, 178 insertions, 360 deletions
diff --git a/lib/ps2epsi b/lib/ps2epsi
index d992180f4..7590cb5a7 100755
--- a/lib/ps2epsi
+++ b/lib/ps2epsi
@@ -1,30 +1,22 @@
#!/bin/sh
+# Revised in 2020 to use the eps2write device (within ps2epsi.ps)
+
# This definition is changed on install to match the
-# executable name set in the makefile
+# executable name set in the makefile, but we check a couple of other
+# places (bin/ sibling to $LIBDIR and 'gs' on the $PATH)
GS_EXECUTABLE=gs
-gs="`dirname \"$0\"`/$GS_EXECUTABLE"
+LIBDIR=`dirname $0`
+gs="$LIBDIR/$GS_EXECUTABLE"
if test ! -x "$gs"; then
- gs="$GS_EXECUTABLE"
-fi
-GS_EXECUTABLE="$gs"
-
-# try to create a temporary file securely
-if test -z "$TMPDIR"; then
- TMPDIR=/tmp
-fi
-if which mktemp >/dev/null 2>/dev/null; then
- tmpfile="`mktemp $TMPDIR/ps2epsi.XXXXXX`"
-else
- tmpdir=$TMPDIR/ps2epsi.$$
- (umask 077 && mkdir "$tmpdir")
- if test ! -d "$tmpdir"; then
- echo "failed: could not create temporary file"
- exit 1
+ # Might be executing lib/ps2epsi with bin/ as sibling to lib/
+ gs="$LIBDIR/../bin/$GS_EXECUTABLE"
+ if test ! -x "$gs"; then
+ # Fallback to using any 'gs' on the path
+ gs="$GS_EXECUTABLE"
fi
- tmpfile="$tmpdir"/ps2epsi$$
fi
-trap "rm -rf \"$tmpfile\"" 0 1 2 3 7 13 15
+GS_EXECUTABLE="$gs"
export outfile
@@ -35,8 +27,7 @@ fi
infile=$1;
-if [ $# -eq 1 ]
-then
+if [ $# -eq 1 ]; then
case "${infile}" in
*.ps) base=`basename "${infile}" .ps` ;;
*.cps) base=`basename "${infile}" .cps` ;;
@@ -49,70 +40,8 @@ else
outfile=$2
fi
-"$GS_EXECUTABLE" -q -dBATCH -dNOPAUSE -P- -sDEVICE=bbox -sOutputFile=/dev/null "${infile}" 2>${outfile}
-
-ls -l "${infile}" |
-awk 'F==1 {
- cd="%%CreationDate: " $6 " " $7 " " $8;
- t="%%Title: " $9;
- f="%%For:" U " " $3;
- c="%%Creator: Ghostscript ps2epsi from " $9;
- next;
- }
- /^%!/ {next;}
- /^%%Title:/ {t=$0; next;}
- /^%%Creator:/ {c=$0; next;}
- /^%%CreationDate:/ {cd=$0; next;}
- /^%%For:/ {f=$0; next;}
- !/^%/ {
- print "/ps2edict 30 dict def";
- print "ps2edict begin";
- print "/epsititle (" t "\\n) def";
- print "/epsicreator (" c "\\n) def";
- print "/epsicrdt (" cd "\\n) def";
- print "/epsifor (" f "\\n) def";
- exit(0);
- }
- ' U="$USERNAME$LOGNAME" F=1 - F=2 "${infile}" >"$tmpfile"
-
-ls -l "${outfile}" |
-awk 'F==1 {
- b="%%BoundingBox: 0 0 0 0\\n";
- }
- /^%%BoundingBox:/ {b=$0; next;}
- /^%%HiResBoundingBox:/ {
- hb=$0;
- print "ps2edict where {pop} {/ps2edict 30 dict def} ifelse";
- print "ps2edict begin";
- print "/BBoxString (" b "\\n) def";
- print "/HiresBBoxString (" hb "\\n) def";
- print "end";
- exit(0);
- }
- ' F=1 - F=2 "${outfile}" >>"$tmpfile"
-
-"$GS_EXECUTABLE" -q -dNOPAUSE -P- -r72 -sDEVICE=bit -sOutputFile=/dev/null "$tmpfile" ps2epsi.ps "$tmpfile" <"${infile}" 1>&2
-rm -f "$tmpfile"
-rm -rf "$tmpdir"
-
-(
-cat << BEGINEPS
-save countdictstack mark newpath /showpage {} def /setpagedevice /pop load def
-%%EndProlog
-%%Page 1 1
-BEGINEPS
-
-cat "${infile}" |
-LC_ALL=C \
-sed -e '/^%%BeginPreview:/,/^%%EndPreview[^!-\~]*$/d' -e '/^%!PS-Adobe/d'\
- -e '/^%%[A-Za-z][A-Za-z]*[^!-\~]*$/d' -e '/^%%[A-Za-z][A-Za-z]*: /d'
-
-cat << ENDEPS
-%%Trailer
-cleartomark countdictstack exch sub { end } repeat restore
-%%EOF
-ENDEPS
-
-) >> "${outfile}"
+# Note, we expect 'ps2epsi.ps' to be in the same directory as 'ps2epsi'
+"$GS_EXECUTABLE" -q -dNOOUTERSAVE -dNODISPLAY -dLastPage=1 -sOutputFile="${outfile}" \
+ --permit-file-all="${infile}" -- "$LIBDIR/ps2epsi.ps" "${infile}" 1>&2
exit 0
diff --git a/lib/ps2epsi.bat b/lib/ps2epsi.bat
index f5e7b3e5d..b5ac5c28f 100755
--- a/lib/ps2epsi.bat
+++ b/lib/ps2epsi.bat
@@ -1,33 +1,15 @@
-@echo off
+@echo off
if %1/==/ goto usage
if %2/==/ goto usage
call "%~dp0gssetgs.bat"
+
set infile=%~1
set outfile=%~2
-rem First we need to determine the bounding box. ps2epsi.ps below will pick
-rem the result up from %outfile%
-%GSC% -q -dNOPAUSE -dBATCH -P- -sDEVICE=bbox -sOutputFile=NUL %1 2> %2
-
-rem Ghostscript uses %outfile% to define the output file
-%GSC% -q -dNOPAUSE -P- -sDEVICE=bit -sOutputFile=NUL ps2epsi.ps < %1
-
-rem We bracket the actual file with a few commands to help encapsulation
-echo %%%%Page: 1 1 >> %2
-echo %%%%BeginDocument: %2 >> %2
-echo /InitDictCount countdictstack def gsave save mark newpath >> %2
-echo userdict /setpagedevice /pop load put >> %2
-
-rem Append the original onto the preview header
-rem cat.ps uses the %infile% and %outfile% environment variables for the filenames
-%GSC% -q -dNOPAUSE -dBATCH -P- -sDEVICE=bit -sOutputFile=NUL cat.ps
-
-
-echo %%%%EndDocument >> %2
-echo countdictstack InitDictCount sub { end } repeat >> %2
-echo cleartomark restore grestore >> %2
+rem Now convert the input to EPSF and add the Preview to the EPSF file
+%GSC% -q -dNOOUTERSAVE -dNODISPLAY -dLastPage=1 -sOutputFile=%outfile% --permit-file-read=%infile% -- %~dp0ps2epsi.ps %infile%
goto end
diff --git a/lib/ps2epsi.cmd b/lib/ps2epsi.cmd
index 9eafdbd8b..c87d82e63 100755
--- a/lib/ps2epsi.cmd
+++ b/lib/ps2epsi.cmd
@@ -1,8 +1,3 @@
-/*
- * This file is maintained by a user: if you have any questions about it,
- * please contact Mark Hale (mark.hale@physics.org).
- */
-
@echo off
if %1/==/ goto usage
if %2/==/ goto usage
@@ -10,25 +5,8 @@ if %2/==/ goto usage
set infile=%1
set outfile=%2
-rem First we need to determine the bounding box. ps2epsi.ps below will pick
-rem the result up from %outfile%
-gsos2 -q -dNOPAUSE -dBATCH -P- -sDEVICE=bbox -sOutputFile=NUL %infile% 2> %outfile%
-
-rem Ghostscript uses %outfile% to define the output file
-gsos2 -q -dNOPAUSE -P- -sDEVICE=bit -sOutputFile=NUL ps2epsi.ps < %infile%
-
-rem We bracket the actual file with a few commands to help encapsulation
-echo %%%%Page: 1 1 >> %outfile%
-echo %%%%BeginDocument: %outfile% >> %outfile%
-echo /InitDictCount countdictstack def gsave save mark newpath >> %outfile%
-echo userdict /setpagedevice /pop load put >> %outfile%
-
-rem Append the original onto the preview header
-copy %outfile% + %infile%
-
-echo %%%%EndDocument >> %outfile%
-echo countdictstack InitDictCount sub { end } repeat >> %outfile%
-echo cleartomark restore grestore >> %outfile%
+rem Now convert the input to EPSF and add the Preview to the EPSF file
+gsos2 -q -dNOOUTERSAVE -dNODISPLAY -dLastPage=1 -sOutputFile=%outfile% --permit-file-read=%infile% %~dp0ps2epsi.ps %infile%
goto end
diff --git a/lib/ps2epsi.ps b/lib/ps2epsi.ps
index 9b98d4d9c..54621f928 100644
--- a/lib/ps2epsi.ps
+++ b/lib/ps2epsi.ps
@@ -11,234 +11,163 @@
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
% CA 94945, U.S.A., +1(415)492-9861, for further information.
-%
-
-% Convert an arbitrary PostScript file to an EPSI file.
-%
-% Please do not contact these users if you have questions. They no longer
-% have the time, interest, or current expertise to keep this code working.
-% If you find bugs, please send proposed fixes to bug-gs@ghostscript.com.
-%
-% Bug fix 2002-04-20 by rayjj: Bounding box was incorrect since it depended
-% on the dither pattern and gray shade at the boundary. Changed to use
-% 8-bit grayscale preview image to allow correct bounding box (at the
-% expense of a 8x larger preview image). Also moved .setsafe until after
-% the device and file operations are complete (but still before the input
-% file is processed.
-% Bug fix 2000-04-11 by lpd: if a font didn't have a FontName (which is the
-% case for bitmap fonts produced by recent versions of dvips), setfont
-% caused an error.
-% Bug fix 8/21/99 by lpd: many of the margin and width computations were
-% wrong (off by 1). The code only "worked" because the bugs were
-% (mostly) in conservative directions.
-% Modified 3/17/98 by lpd to make it possible to run this file without
-% running the ps2epsi script first, for debugging.
-% Bug fix 9/29/97 by lpd <ghost@aladdin.com>: if the page size wasn't an
-% exact multiple of 8 bits, an incorrect bounding box (or a rangecheck
-% error) could occur.
-% Patched 7/26/95 by
-% Greg P. Kochanski <gpk@bell-labs.com>
-% to add many new DSC comments and make the comments conforming.
-% Original version contributed by
-% George Cameron <george@bio-medical-physics.aberdeen.ac.uk>
-%
-% Initialize, and redefine copypage and showpage.
-
-% ps2edict is normally defined in the pre-loaded code created by the
-% ps2epsi script.
-/ps2edict where { pop } { /ps2edict 25 dict def } ifelse
-ps2edict begin
-
- % The main procedure
- /ps2epsi
- {
- % bbox written to outfile by bbox device from ps2epsi command file
- outfile (r) file /epsifile exch def
- /BBoxString epsifile 256 string readline pop def
- /HiresBBoxString epsifile 256 string readline pop def
- epsifile closefile
- % Open the file
- outfile (w) file /epsifile exch def
- % Get the device parameters
- currentdevice getdeviceprops .dicttomark
- /HWSize get aload pop
- /devheight exch def
- /devwidth exch def
- matrix defaultmatrix
- /devmatrix exch def
- % Make a corresponding 8-bit deep memory device
- devmatrix devwidth devheight
- 256 string 0 1 255 { 1 index exch dup 255 exch sub put } for
- makeimagedevice
- /arraydevice exch def
- arraydevice
- % Turn on anti-aliasing
- mark /TextAlphaBits 4 /GraphicsAlphaBits 4 6 -1 roll
- putdeviceprops
- setdevice % (does an erasepage)
- /rowwidth devwidth def
- /row rowwidth string def
- /zerorow rowwidth string def % all zero
- % Replace the definition of showpage
- userdict /showpage { ps2edict begin epsipage end } bind put
- userdict /setfont { ps2edict begin epsisetfont end } bind put
- userdict /setpagedevice /pop load put
- } bind def
-
- /epsifontdict 100 dict def
-
- /epsisetfont
- {
- % code here keeps a list of font names in dictionary epsifontdict
- /tmpfont exch def
- tmpfont /FontName known {
- /tmpfontname tmpfont /FontName get def
- epsifontdict tmpfontname known not { epsifontdict tmpfontname 0 put } if
- epsifontdict tmpfontname 2 copy get 1 add put
- } if
- tmpfont setfont
- } bind def
-
-% Get a scan line from the memory device, zeroing any bits beyond
-% the device width.
-/getscanline { % <device> <y> <string> getscanline <string>
- dup 4 1 roll copyscanlines pop
- 16#ff00 devwidth 7 and neg bitshift 255 and
- dup 0 ne {
- 1 index dup length 1 sub 2 copy get 4 -1 roll and put
- } {
- pop
- } ifelse
-} bind def
-
-/margintest { % <y-start> <step> <y-limit> margintest <y-non-blank>
- % <y-start> <step> <y-limit> margintest -
- { dup arraydevice exch row getscanline
- zerorow ne { exit } if pop
- } for
-} bind def
-
- /epsiNameStr 200 string def
- /epsiNpages 0 def
- /epsiNpageStr 20 string def
- /epsipage
- {
- /epsiNpages epsiNpages 1 add def
- /loopcount devheight 1 sub def
-
- % Find top margin -- minimum Y of non-blank scan line.
- -1 0 1 loopcount margintest
- dup -1 eq { (blank page!!\n) print quit }{ exch pop } ifelse
- /tm exch def
-
- % Find bottom margin -- maximum Y of non-blank scan line.
- loopcount -1 0 margintest
- /bm exch def
-
- % Initialise limit variables
- /loopcount rowwidth 1 sub def
- /lm loopcount def
- /rm 0 def
-
- % Find left and right boundaries of image
- tm 1 bm
- { % Get more data
- arraydevice exch row getscanline pop
- % Scan from left to find first non-zero element
- % We save first the element, then the index
- -1 0 1 loopcount
- { dup row exch get 0 ne { exch pop exit }{ pop } ifelse
- } for
- % If we found -1, row is blank ..
- dup -1 ne
- { % Find the leftmost index
- dup lm lt
- % If the new index is less, we save index and element
- { /lm exch def } { pop } ifelse
- % Now find the rightmost index
- loopcount -1 0
- { dup row exch get 0 ne { exit }{ pop } ifelse
- } for
- dup rm gt
- % If the new index is greater, we save index and element
- { /rm exch def } { pop } ifelse
- } {
- pop
- } ifelse
- } for
-
- % Write out the magic string and bounding box information
- epsifile (%!PS-Adobe-2.0 EPSF-1.2\n) writestring
- /epsititle where { pop epsifile epsititle writestring } if
- /epsicreator where { pop epsifile epsicreator writestring } if
- /epsicrdt where { pop epsifile epsicrdt writestring } if
- /epsifor where { pop epsifile epsifor writestring } if
- epsifile flushfile
-
- % Write out the page count:
- epsifile (%%Pages: ) writestring
- epsifile epsiNpages epsiNpageStr cvs writestring
- epsifile (\n) writestring
- epsifile flushfile
-
- % Write out the list of used fonts:
- epsifile (%%DocumentFonts:) writestring
- epsifontdict {
- epsifile ( ) writestring
- pop epsiNameStr cvs epsifile exch writestring
- } forall
- epsifile (\n) writestring
- epsifile flushfile
-
- epsifile BBoxString writestring epsifile (\n) writestring
- epsifile HiresBBoxString writestring epsifile (\n) writestring
-
- % Define character and bit widths for the output line buffer:
- /cwidth rm lm sub 1 add def
- /out cwidth string def
-
- epsifile (%%EndComments\n\n) writestring
- epsifile (%%BeginProlog\n) writestring
- epsifile (%%BeginPreview: ) writestring
- epsifile cwidth write==only epsifile ( ) writestring
- epsifile bm tm sub 1 add write==only epsifile ( 8 ) writestring
- epsifile bm tm sub 1 add
- cwidth 39 add 40 idiv mul write==
- epsifile flushfile
-
- gsave
-
- tm 1 bm
- { % Get a scan line interval from the array device
- arraydevice exch row copyscanlines lm cwidth getinterval
- % Write out the hex data as 40 bytes per line (82 chars)
- 0 40 cwidth
- { epsifile (% ) writestring
- epsifile exch 2 index exch
- dup cwidth exch sub 40 .min getinterval writehexstring
- epsifile (\n) writestring
- } for
- pop
- } for
-
- epsifile (%%EndImage\n) writestring
- epsifile (%%EndPreview\n) writestring
- epsifile flushfile
- grestore
- erasepage initgraphics
-
- DonePage 0 1 put
- } bind def
-
-(outfile) getenv
- { /outfile exch def
- ps2epsi
-
- /DonePage 1 string def
- (%stdin) (r) file cvx execute0
- DonePage 0 get 0 eq { showpage } if
+% Convert a PostScript file to an EPSI file, adding the Preview Image.
+
+% If the file is already EPSF, then skip the creation of an EPSF, and
+% only add the preview. A warning is issued if the %%Pages: comment
+% indicates that there is more than a single page in the input file.
+
+% Expected invocation:
+% gs -q -dNOOUTERSAVE -dNODISPLAY -dLastPage=1 -sOutputFile=out.epsi --permit-file-read=in.ps -- ps2epsi.ps in.ps
+
+% Usually this will be invoked by the ps2epsi script (or .bat or .cmd versions)
+
+false % no errors from initial param check
+% NOOUTERSAVE is needed for the SAVE to not remove the tempfile (if one was needed)
+vmstatus pop pop 0 gt { (Error: missing -dNOOUTERSAVE option) = pop true } if
+% NODISPLAY may not be strictly needed, but we don't want to open the default device
+/NODISPLAY where { pop } { (Error: missing -dNODISPLAY option) = pop true } ifelse
+% LastPage is needed if we are using eps2write on a PostScript (or PDF) file that has multiple pages.
+/LastPage where { pop } { (Error: missing -dLastPage option) = pop true } ifelse
+% OutputFile is needed so that it gets on the permit-file-writing list
+/OutputFile where { pop } { (Error: missing -sOutputFile option) = pop true } ifelse
+
+.shellarguments not count 3 lt or count -1 roll or
+{
+ (usage: gs -q -dNOOUTERSAVE -dNODISPLAY -dLastPage=1 -sOutputFile=out.epsi --permit-file-read=in.eps -- ps2epsi.ps in.ps) =
+ quit
+} {
+ dup /InputFile exch def
+ (r) file /I exch def
+} ifelse
+
+/O OutputFile (w) file def
+
+/S 65535 string def
+
+/R { I S readline not { (Error: Unexpected end of file.) = quit } if } bind def
+/WL { O exch writestring O (\n) writestring } bind def % Write with linefeed
+/TName null def
+
+/EPSFheader (%!PS-Adobe-3.0 EPSF-3.0) def
+% Read the header to check if this file was EPSF
+R
+dup EPSFheader ne {
+ % InputFile was not EPSF
+ pop % discard the first line of the InputFile
+ % run the file through eps2write (into a tempfile) to make an EPSF
+ (_ps2epsi) (w+) .tempfile closefile /TName exch def
+ /SAVE save def
+ (eps2write) finddevice mark /OutputFile TName 3 index putdeviceprops pop
+ setdevice
+ InputFile run
+ SAVE restore
+ /I TName (r) file def
+ R
+} if
+WL % Write the first line (either from InputFile or the tempfile
+
+% From the "5002 Encapsulated PostScript File Format Specification Version 3.0 1 May 1992"
+% The preview section must appear after the header comment section, but
+% before the document prologue definitions. That is, it should immediately
+% follow the %%EndComments: line in the EPS file.
+{ % loop until we see the %%EndComments line, writing those lines to output
+ R
+ dup (%%EndComments) anchorsearch exch pop { % discard the match or extra copy of the string
+ pop exit % found it
} if
+ % Check the %%Pages: comment to issue a warning if there is more than one page.
+ dup (%%Pages:) anchorsearch exch pop { % discard the match or extra copy of the string
+ cvi 1 gt {
+ (Warning: EPSI files can only have 1 page, Only the first page will be in the preview.) =
+ } if
+ } if
+ % Collect the BoundingBox data that will be used when generating the preview
+ dup (%%BoundingBox:) anchorsearch exch pop { % discard the match or extra copy of the string
+ mark
+ exch token not { (Error: invalid BoundingBox parameters) = quit } if
+ exch token not { (Error: invalid BoundingBox parameters) = quit } if
+ exch token not { (Error: invalid BoundingBox parameters) = quit } if
+ exch token not { (Error: invalid BoundingBox parameters) = quit } if
+ exch pop ]
+ /BBox exch def
+ % Preview dimensions
+ /PWidth BBox dup 2 get exch 0 get sub def
+ /PHeight BBox dup 3 get exch 1 get sub def
+ } if
+ WL % send to output file with linefeed.
+} loop
+
+WL % send to output file with linefeed.
+
+% If the InputFile already has a preview, skip past it
+R
+dup (%%BeginPreview) anchorsearch exch pop { % discard the match or extra copy of the string
+ pop
+ % Read lines until after the %%EndPreview
+ {
+ R
+ (%%EndPreview) anchorsearch exch pop { % discard the match or extra copy of the string
+ pop pop exit % found it
+ } if
+ } loop
+ % Get the next line for use after the generated preview
+ R
+}
+if
+/LineAfterEndComments exch def
+
+//null (w+) .tempfile
+closefile % will be opened by bit device
+/Pname exch def
+
+(bit) selectdevice
+<<
+ /GrayValues 256 % Gray, not monochrome
+ /OutputFile Pname
+ /TextAlphaBits 4
+ /GraphicsAlphaBits 4
+ /LastPage 1 % TBD: does this work?
+ /.IgnoreNumCopies true
+ /Install { BBox 0 get neg BBox 1 get neg translate { 1.0 exch sub } settransfer } % EPSI 00 is white
+ /HWResolution [ 72. 72. ]
+ /PageSize [ PWidth PHeight ]
+>> setpagedevice
+
+InputFile run
+
+/P Pname (r) file def % Preview data file
+/SP PWidth string def % One string per image line
+
+% Write the preview
+O (%%BeginPreview: ) writestring
+O PWidth write==only O ( ) writestring
+O PHeight write==only O ( 8 ) writestring
+O PHeight PWidth 39 add 40 idiv mul write== % 40 bytes per line
+O flushfile
+0 1 PHeight 1 sub {
+ pop
+ P SP readstring pop
+ 0 40 PWidth {
+ O (% ) writestring % 82 bytes on each line, plus EOL
+ SP exch 40 PWidth 2 index sub .min getinterval
+ O exch writehexstring
+ O (\n) writestring
+ } for
+ pop
+} for
+(%%EndPreview) WL
+
+% Write the line that followed the %%EndComments
+LineAfterEndComments WL
+
+% Copy the remainder of the inputfile
+{
+ I S readstring exch O exch writestring not { exit } if
+} loop
+
+% If we created a tempfile, delete it
+TName null ne { TName deletefile } if
-end
quit