PostScript FAQ/Using PostScript

Using PostScript

edit

Do I need a PostScript printer?

edit

There are several situations when PostScript printer is desirable:

  • you need to print documents with placed EPS files
  • you receive print jobs from 3rd parties and need a portable page description language
  • you expect to print variable content documents
  • desktop printer serves as a cheap proofer for a more expensive printer or imagesetter
  • vector page description is much shorter than the raster image of the page
  • you run Unix-like system where PostScript language serves as a printer API.

Software RIP with a non-PostScript printer is becoming a good alternative to a PostScript printer. Unlike built-in RIP the software and hardware can be easily upgraded. The host OS also provides a better debugging environment.

How to create a PS file?

edit

PostScript is a low level page description language. The PostScript graphic model is based on presentation elements: lines, curves, characters, images. There is no notion of words, paragraphs, justification, footnotes, etc. Most authors prefer to work on the higher level and generate presentation formats (PostScript, PDF, PCL, etc.) from the high level page description.

TeX is a typesetting program designed for high-quality composition of material that contains a lot of mathematical and technical expressions. It has been adopted by many authors and publishers who generate technical books and papers. It was created by Professor Donald Knuth of Stanford University, originally for preparation of his book series The Art of Computer Programming.

groff (GNU troff) software is a typesetting package which reads plain text mixed with formatting commands and produces formatted output.

PostScript printer drivers on Mac OS and Microsoft Windows can generate PostScript file from the incoming GDI calls. So every application that prints can also generate PostScript. However the set of graphic primitives in the file will be limited by the GDI graphic model. Most graphic editors and DTP applications bypass GDI and generate PostScript directly. This helps to generate better PostScript and provides more flexible graphic model to the application.

Sometimes it is necessarily to create or modify PS files by hand. PostScript files can be big and contain binary data. The text editor should not expand tabs or normalize line ending. emacs is a good choice because it is extensible and includes a PostScript major mode.

How to send a PS file to a printer?

edit

On a Unix-like system you can use lpr:

lpr -S computer_name -P queuename filename.ps

On Microsoft Windows you can send the file to a printer as:

copy /b filename.ps lpr1

or

copy /b filename.ps \\computer_name_or_ip\printersharename

Some of the printers also support lpr protocol.

PrintFile is a freeware GUI Windows program that copies files the system print queue. It can also pick pages from the DSC-conforming PostScript file.

On Classic Mac OS, you can drop the file on the printer icon.

What is the best way to view a PS file on the screen?

edit

PostScript file is designed for sequential printing - images are often stored as inline streams, page size and resolution is a part of page description.

The viewer is expected to browse the document in random order and magnification. This can be achieved by converting the PostScript to an internal form that enables direct access to page elements and fast clipping of invisible objects. None of the PostScript viewers work this way.

GSview is a free graphical interface for Ghostscript developed by Russel Lang at Ghostgum Software. The page selection is implemented through DSC processing; zoom is implemented by re-interpretation of the page. GSview is available for Win32, Win32s, OS/2 and GNU/Linux. Older versions are available for Win16. There are other graphical X-Window front ends for Ghostscript - examples are mgv, Moonshiner and Okular.

PostScript can be easily converted to PDF using Ghostscript, ps2pdf online, Distiller, PDFCreator and a few of other programs. There are many more PDF viewers than PS viewers. Furthermore PDF viewers often are more user friendly than most PS viewers, the most convenient way to view a PS file is to convert it first into a PDF file. The most popular free PDF viewers are Adobe Reader, Evince, Foxit Reader, MuPDF, Okular, PDF-XChange Viewer, Sumatra PDF and Xpdf.

How to send a binary PostScript file to an ASCII-only printer?

edit

Many network printers don't accept PS files containing binary data.

Sometimes it is impossible to re-create the file as 7-bit ASCII but any file is easy to convert to ASCII stream and execute it through the corresponding decoding filter. The following script converts standard input to hexadecimal stream and adds the decoding code. All DSC comments will be hidden but most printers ignore them anyway. The script was tested on bash and GNU/Linux systems.

#! /bin/sh
echo '%!'
echo 'currentfile /ASCIIHexDecode filter cvx exec'
od -A n -v -t x1
echo '>'

The version of the script for MS-DOS and Windows has to read '>' character from itself because echo ">" prints ">" (with the quotes).

@echo off
rem ">"
echo %%!
echo currentfile /ASCIIHexDecode filter cvx exec
od -A n -v -t x1
od -A n -v -t c -j 16 -N 1 %0

od (octal dump) comes from the GNU Textutils package. It is available on all stock Unix-like systems (including macOS) and can be installed on Windows with Cygwin or MinGW packages.

PostScript utilities can be easily programmed using the PostScript language. The following program reads the input file or standard input, compresses it, optionally converts it using ASCII85 encoding, and writes to output file or standard output. The program is run by Ghostscript using:

 gs -q [-dASCII] [-dLEVEL3] -- encode.ps [INFILE [OUTFILE]]

Where:

-q suppresses writing of copyright information to stdout
-dASCII selects ASCII85 encoding
-dLEVEL3 selects Flate encoding introduced in level 3
encode.ps is the program
INFILE is input file, defaults to stdin
OUTFILE is output file, defaults to stdout
%!
% encode.ps - compress and encode PS file to reduce upload time.
% This won't work if the file contains multiple jobs separated by ^D
%
/stderr (%stderr)(w) file def
/error { stderr exch writestring } bind def
/closetarget <</CloseTarget true>> readonly def
%
/openfile  % fname mode -> file
{ { file } stopped
    { exch (Cannot open file: ) error error (w) eq { (for writing\n) } { (for reading\n) } ifelse error
      flush quit
    }
  if
} bind def
%
/main      % - -> -
{ mark shellarguments
    { counttomark 2 le
        { counttomark
            { { (%stdin)(r) file (%stdout)(w) file }
              { (r) openfile (%stdout)(w) file }
              { (w) openfile exch (r) openfile exch }
            }
          exch get exec dup                   % input output output
          //systemdict /ASCII .knownget dup { true eq and } if
            { //closetarget /ASCII85Encode filter
              (/ASCII85Decode filter)
            }
            { () }
          ifelse
          exch                                % input output () output
          //systemdict /LEVEL3 .knownget dup { true eq and } if
            { //closetarget /FlateEncode filter exch
              (/FlateDecode filter)
            }
            { //closetarget /LZWEncode filter exch
              (/LZWDecode filter)
            }
          ifelse
          concatstrings                       % input output output ()
          2 index (%!\ncurrentfile) writestring
          2 index exch writestring
          exch ( cvx exec\n) writestring
          exch 61440 string                   % output input buf
            { 3 copy readstring pop           % output input buf output buf
              dup () eq { pop pop exit } if
              writestring
            }
          loop
          pop closefile closefile false
        }
        { (Incorrect number of file name arguments.\n) error true
        }
      ifelse
    }
    { (Missing '--' preceding encode.ps\n) error true
    }
  ifelse
    { (Usage: gs -q -dASCII -dLEVEL3 -- encode.ps INFILE OUTFILE\n) error flush
    }
  if
} bind def
%
main clear quit

If needed, DSC processing can be done before downloading the file to the printer. Development of a DSC-aware ASCII85-based converter is left for the exercise of the reader.

How to print an EPS file?

edit

Encapsulated PostScript, or EPS, files are usually meant for inclusion in printable PostScript or other EPS files. Unlike the printable PostScript they can have:

  • showpage operator not included
  • image shifted outside of the printable area
  • image size too big or too small
  • PC-style header and preview

Thus, sending EPS files to a PostScript printer directly may cause a PostScript error or only page to be printed.

The standard way is to place EPS in the page in a graphic design application and print.

In order to directly print an EPS file, you need to add a PS header that does all the necessary adjustments.

cat header.ps file.eps | lpr

A suitable header is given as an example on the net.anastigmatix.Import resource page.

How to check whether a PostScript file is valid ?

edit

Send the file to a PostScript interpreter. If you like the results the file is valid. PostScript interpreters include:

There are others of course, but these are the simplest/cheapest to get hold of.

In fact this will check correctness of the PostScript program only on the interpreter where it has been tested. Different interpreters provide very different execution environment that can make PS program take a different branch.

PostScript program can produce unexpected output without reporting any PostScript errors. In the mission-critical situation a proof page printed on the laser printer and signed by the designer is mandatory.

How to count pages in a PS file?

edit

Interpret the file using bbox device and count HiResBoundingBox lines.

gs -q -dNOPAUSE -dBATCH -sDEVICE=bbox foo.ps 2>&1 | grep -c HiResBoundingBox

Somewhat faster is also the command

yes | gs -q -dBATCH -sDEVICE=nullpage foo.ps | grep -c showpage

Assuming the document is DSC-conforming one can count %%Page comments directly in the document.

grep -c %%Page: file.ps

How to determine which pages are color and which are monochrome?

edit

First, you need to decide what makes the page a color page. Probably, monochrome page has zero density of CMY components. To check this using Ghostscript you need to select a true color CMYK device, install correct CRD and rasterize the file.

The page is a color page if any pixel has non-zero components in CMY planes.

How to print only some pages from a PS file?

edit

DSC (Document Structure Convention) was intended to provide an easy way to parse the PostScript document, rearrange pages, add missing fonts, substitute images, etc. Although most programs generate DSC comments few programs use them. It appears that correctness of DSC comments has been never tested even by major vendors.

Sometimes the document claiming DSC conformance fails with PostScript errors after modification. Even worse the pages can be spoiled in some subtle way. For instance, some characters of the incrementally downloadable font may be silently replaced with a default character.

Page selection based on DSC comments is used by PrintFile and GSview.

PDF can serve as a convenient intermediate format esp. when page extraction is performed more than once. You can use Ghostscript to convert the file to PDF and extract a range of pages as following:

ps2pdf input.ps output.pdf
gs -dFirstPage=1 -dLastPage=2 output.pdf

Occasionally, other graphic formats can work better than PDF. The author once wrote bilist.cpp to place two A5 pages on a single A4 page and rearrange pages into signatures for some old PCL printer.

How to rearrange pages of a PS file for printing a brochure?

edit

There are several ways to solve this problem. Every approach has its advantages.

Direct manipulation preserves most of PS structure and takes least processor time. Unfortunately, it is only applicable for DSC-conforming PostScript files. Although most DSC files generated by mainstream applications claim DSC conformance few have been tested as such. For instance, Microsoft PS driver generates non-conforming files by default.

psselect from psutils can select and reorder pages in the DSC-conforming PS file.

Conversion to raster image is a simple and reliable approach. For instance bilist.cpp extracts pages from the PCL file, reorders pages into signatures, and places them 2-up. Ghostscript can be used for PostScript to PCL conversion.

Conversion to PDF greatly simplifies further document processing. Pages in PDF file can be extracted and printed in any size or order. The PostScript file can be converted to PDF using several applications. For instance, Ghostscript

ps2pdf input.ps output.pdf

To extract a range of pages from a PDF file into another PDF file use

ps2pdf -dFirstPage#111 -dLastPage#666 input.pdf output.pdf

To extract a range of pages from a PDF file and convert to PS file use:

ps2ps -dFirstPage#111 -dLastPage#666 input.pdf output.ps

It is always safe to concatenate PDF files as following

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=file.pdf \
   -c save pop -f file1.dsc file2.dsc file3.dsc ...

The methods above are sufficient to rearrange pages in any order but complex jobs can be done more efficiently. The PDF file can be convertrd to a simple DSC-conforming PS file.

pdf2dsc source.pdf output.dsc

The output file will be very simple, because all the complexity is hidden inside Ghostscript libraries. The format is trivial to modify using any DSC utility, text editor, or script.

%!PS-Adobe-3.0
%...
/Page null def/Page# 0 def/PDFSave null def/DSCPageCount 0 def
/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def
GS_PDF_ProcSet begin pdfdict begin
file.pdf) (r) file { DELAYSAFER { .setsafe } if } stopped pop
pdfopen begin
%%Page: 1 1
1 DoPDFPage
%%Page: 2 2
2 DoPDFPage
%%Trailer
currentdict pdfclose end end end
%%EOF

Updated file can be converted back to PDF.

ps2pdf source.dsc result.pdf

The DSC file uses GS libraries, which is fine if the DSC file is fed to Ghostscript only. To generate a portable PS file convert it back to PS.

Why does my PS driver generate color drawings but grayscale images?

edit

When the driver generates PostScript stream for monochrome printer it often converts color images to grayscale for better transmission time, faster rendering, and lower resource usage. Conversion of vector objects to grayscale doesn't save much space or time. So the driver leaves it to the PostScript interpreter.

This problem often happens when the job is printed to Generic PostScript printer driver. Generic driver is not the best one. It is limited to the common subset of PostScript language available on most printers. It is monochrome, has small choice of media, fonts, no special features.The PostScript file from Generic driver will print on wide variety of printers but many features will be missing.

Although it appears like every printer uses a special driver it is the same driver configured for different printers. The driver takes configuration parameters from PPD file. When possible the native PPD file should be used. The Acrobat Distiller PPD is a good choice to generate a color PostScript file free of vendor-specific features.

How to recombine plates in preseparated PostScript file?

edit

It is very simple to rasterize the pages and recombine the pages into the composite file. Rasterization can be done at 8 bit per plane or 1 bit per plane depending whether any color correction is desired for the composite image.

Merging the planes on vector level is much more difficult. The only known tool for this job is the Seps2Comp Acrobat plug-in from Creo (now discontinued and unsupported). The PostScript file can be converted to PDF using a number of programs including Ghostscript and Acrobat Distiller.

How to remove black frames around n-up pages?

edit

Windows driver generates black frames around virtual pages when it does n-up printing. The frames are drawn in nupshowpage procedure. To remove the frames this procedure must be modified. On level 3 interpreters Hack-MSDriver-n-up IdiomSet can identify and replace this procedure when the job file is loaded by the interpreter. No modification of the job file is needed. To activate the replacement you need to copy the idiom file to /Resource/IdiomSet/ directory on the printer or host-based interpreter. The PostScript root directory on a host-based interpreter likely to be different from the system root. For one-time replacement you can also prepend the IdiomSet file to the job file.

For level 1 and 2 interpreters one has to remove framenup { ... } if fragment from the job file itself using any text editor.

%!PS-Adobe-3.0
%%Title: Hack-MSDriver-n-up
% Remove black frame around n-up pages generated by MS Driver
%%VMusage: 0 0
%%VMlocation: global
%%EndComments
%%BeginResource: IdiomSet Hack-MSDriver-n-up
currentuserparams /IdiomRecognition get
<</IdiomRecognition false>> setuserparams
currentglobal true setglobal
/Hack-MSDriver-n-up
<< 8 dict begin
   /; /grestore load def
   /V /div load def
   /@ /dup load def
   /~ /exch load def
   /rs /rectstroke load def
   /! /pop load def
   /? /ifelse load def
   /+ /translate load def
   /nupshowpage
     [ { ; $m concat
         framenup
           { pagemarg_nup 2 V nups V
             @ $m idtransform abs neg ~ abs neg ~
             paperw_nup paperh_nup rs
           }
         if
         /pgx_nup pgx_nup 1 add
         @ nx_nup eq
           { ! 0 store paperw_nup 1 nx_nup sub mul
             /pgy_nup pgy_nup
             1 add @ ny_nup eq
               { ! 0 store paperh_nup 1 ny_nup sub mul
               }
               { store paperh_nup
               }
             ?
           }
           { store paperw_nup 0
           }
         ? + $m matrix invertmatrix concat startpage
       } bind
       { ; $m concat
         /pgx_nup pgx_nup 1 add
         @ nx_nup eq
           { ! 0 store paperw_nup 1 nx_nup sub mul
             /pgy_nup pgy_nup
             1 add @ ny_nup eq
               { ! 0 store paperh_nup 1 ny_nup sub mul
               }
               { store paperh_nup
               }
             ?
           }
           { store paperw_nup 0
           }
         ? + $m matrix invertmatrix concat startpage
       } bind
     ]
   end
>> /IdiomSet defineresource pop
setglobal <</IdiomRecognition 3 -1 roll>> setuserparams
%%EndResource
%%EOF

How to print A4 on US Letter or vice versa?

edit

To be written.

The document can be scaled or just shifted.

psresize -PA4 -pletter a4.ps letter.ps
psnup -pletter -Pa4 a4file.ps letterfile.ps

Fix pagedevice, policy 3,

How to extract figures from PostScript files?

edit

Figures in PostScript document are often included as EPS files and can be easily extracted with a text editor. In the DSC-conforming document the EPS file is framed by using a text editor.

%%BeginDocument
...
%%EndDocument

Don't forget that EPS files can be nested.

EPS files extracted from the PostScript file don't have a preview, which can be re-generated with Ghostscript.

How to change color PostScript to black-and-white?*

edit

If you can run Perl, look for bw_convert, a tiny perl script that will change every RGB color declaration in a PostScript file to a black or grey value. Simply enough, it replaces "setrgbcolor" with "pop pop pop 0 setgray". The script can be found at bw_convert. The script author is not documented on that site. However, this script is really an excellent example of how not to do things; the author has not really grasped that PostScript is a programming language, and that simple lexical changes will often fail, while adding an extra line of code at the start would be more effective. The script also does not touch images, CMYK data, or level 2 color operators.

A similar thing can be done by adding the following line at the beginning of a PostScript file:

/setrgbcolor {0.11 mul 3 1 roll 0.59 mul 3 1 roll 0.30 mul add add setgray} def

It will overwrite setrgbcolor with setgray and calculate a grayscale color. Still this will not affect images and might not change everything that you wanted to change. There also could be other problems so no warranty on that.

How to tweak RGB to CMYK conversion but leave other objects intact?

edit

Level 3 PostScript has a powerful method for tweaking correction of device-dependent colors to device-independent colors: /UseCIEColor page device key and DefaultGray, DefaultRGB, DefaultCMYK color spaces.

When UseCIEColor flag is on, grayscale, RGB, and CMYK colors are interpreted as the colors in DefaultGray, DefaultRGB, and DefaultCMYK color spaces. It is little known that an array form of device color spaces ( e.g. [DeviceCMYK]) can be defined as a Default* resource effectively disabling the corresponding conversion.

Conversion of CMYK to device-independent colors is often undesirable because of the loss of black generation information.

How to get date and time?

edit

Built-in access to the date and time is with currentdevparams and setdevparams on the %Calendar% device, which appeared in the PostScript Language Reference Manual version 2012 supplement for PostScript LanguageLevel 2. The following code will write the date and time to standard output:

(%Calendar%) /IODevice resourcestatus {
  pop pop (%Calendar%) currentdevparams
  dup /Running get {
    dup /Year get 4 string cvs print (-) print
    dup /Month get 2 string cvs print (-) print
    dup /Day get 2 string cvs print ( ) print
    dup /Hour get 2 string cvs print (:) print
    dup /Minute get 100 add 3 string cvs 1 2 getinterval print (:) print
    /Second get 100 add 3 string cvs 1 2 getinterval print (\n) print
  } {
    (Clock/calendar is present but not running.\n) print
  } ifelse
} {
  (No clock/calendar present.\n) print
} ifelse

The standard does not provide for timezone information and the clock is generally set for local time. Its range extends to 2079. If the interpreter is running on a host operating system, the OS is likely to determine whether setdevparams can actually set the clock.

A host-based PostScript interpreter can access the file system, including named pipes and devices, so possibilities are endless. This example was tested on GNU+Linux using the specific interpreter Ghostscript.

Type the following on one terminal:

mkfifo foo
while true; do date >foo; done

Run gs -dNODISPLAY on another terminal in the same directory, then type

/t { (foo)(r) file closefile (foo)(r) file dup
    28 string readstring pop = closefile} def

Now, typing t at the Ghostscript prompt shows the current time, using the host OS date command instead of the %Calendar% device.

PostScript has been used to implement an HTTP server.