NAME

PostScript::File - Class for creating Adobe PostScript files

VERSION

This document describes version 2.23 of PostScript::File, released October 10, 2015 as part of PostScript-File version 2.23.

Attributes and methods added since version 2.00 are marked with the version they were added in (e.g. "(v2.10)"). Because there were significant API changes in 2.00, I recommend that any code using PostScript::File specify a minimum version of at least 2.

SYNOPSIS

Simplest

A 'hello world' program:

use PostScript::File 2;

my $ps = PostScript::File->new(reencode => 'cp1252');

$ps->add_to_page( <<END_PAGE );
    /Helvetica findfont
    12 scalefont
    setfont
    72 300 moveto
    (hello world) show
END_PAGE

$ps->output( "test" );

All options

my $ps = PostScript::File->new(
    paper => 'Letter',
    height => 500,
    width => 400,
    bottom => 30,
    top => 30,
    left => 30,
    right => 30,
    clip_command => 'stroke',
    clipping => 1,
    eps => 1,
    dir => '~/foo',
    file => "bar",
    landscape => 0,

    headings => 1,
    reencode => 'cp1252',
    font_suffix => '-iso',
    need_fonts  => [qw(Helvetica Helvetica-Bold)],

    errors => 1,
    errmsg => 'Failed:',
    errfont => 'Helvetica',
    errsize => 12,
    errx => 72,
    erry => 300,

    debug => 2,
    db_active => 1,
    db_xgap => 120,
    db_xtab => 8,
    db_base => 300,
    db_ytop => 500,
    db_color => '1 0 0 setrgbcolor',
    db_font => 'Times-Roman',
    db_fontsize => 11,
    db_bufsize => 256,
);

DESCRIPTION

PostScript::File is a class that writes PostScript files following Adobe's Document Structuring Conventions (DSC). You should be familiar with the DSC if you're using this class directly; consult the PostScript Language Document Structuring Conventions Specification linked to in "SEE ALSO".

There are also a number of modules that build upon PostScript::File to produce various kinds of documents without requiring knowledge of PostScript. These are listed in "SEE ALSO".

It is possible to construct and output files in either normal PostScript (*.ps files) or as Encapsulated PostScript (*.epsf or *.epsi files). By default a minimal file is output, but support for font encoding, PostScript error reporting and debugging can be built in if required.

Documents can typically be built using only these functions:

new           The constructor, with many options
add_procset   Add PostScript functions to the prolog
add_to_page   Add PostScript to construct each page
newpage       Begins a new page in the document
output        Construct the file and saves it

The rest of the module involves fine-tuning this. Some settings only really make sense when given once, while others can control each page independently. See new for the functions that duplicate option settings, they all have get_ counterparts. The following provide additional support.

get/set_bounding_box
get/set_page_bounding_box
get/set_page_clipping
get/set_page_landscape
set_page_margins
get_pagecount
draw_bounding_box
clip_bounding_box

The functions which insert entries into each of the DSC sections all begin with 'add_'. They also have get_ counterparts.

add_comment
add_preview
add_default
add_resource
add_procset
add_setup
add_page_setup
add_to_page
add_page_trailer
add_trailer

Finally, there are a few stand-alone functions. These are not methods and are available for export if requested.

check_tilde
check_file
incpage_label
incpage_roman

Hyphens and Minus Signs

In ASCII, the character \x2D (\055) is used as both a hyphen and a minus sign. Unicode calls this character HYPHEN-MINUS (U+002D). PostScript has two characters, which it calls /hyphen and /minus. The difference is that /minus is usually wider than /hyphen (except in Courier, of course).

In PostScript's StandardEncoding (what you get if you don't use "reencode"), character \x2D is /hyphen, and /minus is not available. In the Latin1-based encodings created by reencode, character \x2D is /minus, and character \xAD is /hyphen. (\xAD is supposed to be a "soft hyphen" (U+00AD) that appears only if the line is broken at that point, but it doesn't work that way in PostScript.)

Unicode has additional non-ambiguous characters: HYPHEN (U+2010), NON-BREAKING HYPHEN (U+2011), and MINUS SIGN (U+2212). The first two always indicate /hyphen, and the last is always /minus. When you set reencode to cp1252 or iso-8859-1, those characters will be handled automatically.

To make it easier to handle strings containing HYPHEN-MINUS, PostScript::File provides the "auto_hyphen" attribute. When this is true (the default when using cp1252 or iso-8859-1), the "pstr" method will automatically translate HYPHEN-MINUS to either HYPHEN or MINUS SIGN. (This happens only when pstr is called as an object method.)

The rule is that if a HYPHEN-MINUS is surrounded by whitespace, or surrounded by digits, or it's preceded by whitespace or punctuation and followed by a digit, or it's followed by a currency symbol, it's translated to MINUS SIGN. Otherwise, it's translated to HYPHEN.

ATTRIBUTES

Unlike many classes that use the same method for reading and writing an attribute's value, PostScript::File has separate methods for reading and writing. The read accessor is prefixed with get_, and the write accessor is prefixed with set_. If no write accessor is mentioned, then the attribute is read-only.

auto_hyphen

$ps = PostScript::File->new( auto_hyphen => $translate )

$translate = $ps->get_auto_hyphen

$ps->set_auto_hyphen( $translate )

If $translate is a true value, then "pstr" will do automatic hyphen-minus translation when called as an object method (but only if the document uses character set translation). (Default: true) See "Hyphens and Minus Signs".

clipping

$ps = PostScript::File->new( clipping => $clipping )

$clipping = $ps->get_clipping

$ps->set_clipping( $clipping )

If $clipping is true, printing will be clipped to each page's bounding box. This is the document's default value. Each page has its own "page_clipping" attribute, which is initialized to this default value when the page is created. (Default: false)

eps

$ps = PostScript::File->new( eps => $eps )

$eps = $ps->get_eps

$eps is true if this is an Encapsulated PostScript document. False indicates an ordinary PostScript document.

extensions

$ps = PostScript::File->new( extensions => $extensions )

$extensions = $ps->get_extensions

The PostScript extensions required by this document, for use in the %%Extensions DSC comment. (Default: undef, meaning omit the %%Extensions comment)

file_ext

$ps = PostScript::File->new( file_ext => $file_ext )

$file_ext = $ps->get_file_ext

$ps->set_file_ext( $file_ext )

If $file_ext is undef (the default), then the extension is set automatically based on the output type. .ps will be added for ordinary PostScript files. EPS files have an extension of .epsf without or .epsi with a preview image.

If $file_ext is the empty string, then no extension will be added to the filename. Otherwise, it should be a string like '.ps' or '.eps'. (But setting this has no effect on the actual type of the output file, only its name.)

filename

$ps = PostScript::File->new( file => $file, [dir => $dir] )

$filename = $ps->get_filename

$ps->set_filename( $file, [$dir] )
$file

An optional fully qualified path-and-file, a simple file name, the empty string (which stands for the special file File::Spec->devnull), or undef (which indicates the document has no associated filename).

$dir

An optional directory name. If present (and $file is not already an absolute path), it is prepended to $file. If no $file was specified, $dir is ignored.

The base filename for the output file(s). When the filename is set, if that filename includes a directory component, the directories are created immediately (if they don't already exist).

See "file_ext" for details on how the filename extension is handled.

If "eps" has been set, multiple pages will have the page label appended to the file name.

Example:

$ps = PostScript::File->new( eps => 1 );
$ps->set_filename( "pics", "~/book" );
$ps->newpage("vi");
    ... draw page
$ps->newpage("7");
    ... draw page
$ps->newpage();
    ... draw page
$ps->output();

The three pages for user 'chris' on a Unix system would be:

/home/chris/book/pics-vi.epsf
/home/chris/book/pics-7.epsf
/home/chris/book/pics-8.epsf

It would be wise to use set_page_bounding_box explicitly for each page if using multiple pages in EPS files.

incpage_handler

$ps = PostScript::File->new( incpage_handler => \&handler )

$handler = $ps->get_incpage_handler

$ps->set_incpage_handler( [\&handler] )

The function used to increment the page label when creating a new page. \&handler is a reference to a subroutine that takes the current page label as its only argument and returns the new label.

This module provides the "incpage_label" (which uses Perl's autoincrement operator) and "incpage_roman" (which handles lowercase Roman numberals from i to xxxix, 1-39) functions for use as incpage_handler. (Default: \&incpage_label)

langlevel

$ps = PostScript::File->new( langlevel => $langlevel )

$langlevel = $ps->get_langlevel

$ps->set_min_langlevel( $langlevel ) # added in v2.20

The level of the PostScript language used in this document, for use in the %%LanguageLevel DSC comment. The "set_min_langlevel" method can be used to raise the language level, but it cannot be decreased. (Default: undef, meaning omit the %%LanguageLevel comment)

order

$ps = PostScript::File->new( order => $order )

$order = $ps->get_order

The order the pages are defined in the document, for use in the %%PageOrder DSC comment. It must be one of "Ascend", "Descend" or "Special" (meaning a document manager must not reorder the pages). The default is undef, meaning omit the %%PageOrder comment.

strip (attribute)

$ps = PostScript::File->new( strip => $strip )

$strip = $ps->get_strip

$ps->set_strip( $strip )

Determine whether the PostScript code is filtered. $strip must be one of the following values: space strips leading spaces so the user can indent freely without increasing the file size. comments removes lines beginning with '%' as well. all_comments (v2.20) also removes comments that aren't at the beginning of a line. See also the strip method, which actually does the filtering described here.

Passing undef or omitting $strip sets it to the default value, space.

title

$ps = PostScript::File->new( title => $title )

$title = $ps->get_title

The document's title for use in the %%Title DSC comment. The default (undef) means to use the document's filename as the title. If no filename is available when the document is output, the %%Title comment wil be omitted.

version

$ps = PostScript::File->new( version => $version )

$version = $ps->get_version

The document's version for use in the %%Version DSC comment. The $version should be a string in the form VERNUM REV, where VERNUM is a floating point number and REV is an unsigned integer. (Default: undef, meaning omit the %%Version comment)

Paper Size and Margins

These attributes are interrelated, and changing one may change the others.

bounding_box

( $llx, $lly, $urx, $ury ) = $ps->get_bounding_box

$ps->set_bounding_box( $llx, $lly, $urx, $ury )

The bounding box for the whole document. The lower left corner is ($llx, $lly), and the upper right corner is ($urx, $ury).

Setting the bounding box automatically enables clipping. Call $ps->set_clipping(0) afterwards to undo that.

The default bounding_box is calculated from the paper size (taken from the "paper", "height", and "width" attributes) and the "left", "right", "top", and "bottom" margins.

Each page also has an individual "page_bounding_box", which is initialized from the document's bounding_box when the page is created.

height

$ps = PostScript::File->new( height => $height )

$height = $ps->get_height

$ps->set_height( $height )

The page height in points. This is normally the longer dimension of the paper. Note that in landscape mode this is actually the width of the bounding box.

Setting this sets "paper" to "Custom" and the "bounding_box" is expanded to the full height.

landscape

$ps = PostScript::File->new( landscape => $landscape )

$landscape = $ps->get_landscape

$ps->set_landscape( $landscape )

If $landscape is true, the page is rotated 90 degrees counter-clockwise, swapping the meaning of height & width. (Default: false)

In landscape mode the coordinates are rotated 90 degrees and the origin moved to the bottom left corner. Thus the coordinate system appears the same to the user, with the origin at the bottom left.

paper

$ps = PostScript::File->new( paper => $paper_size )

$paper_size = $ps->get_paper

$ps->set_paper( $paper_size )

Set the paper size of each page. A document can be created using a standard paper size without having to remember the size of paper using PostScript points. Valid choices are currently A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, Executive, Folio, Half-Letter, Letter, US-Letter, Legal, US-Legal, Tabloid, SuperB, Ledger, 'Comm #10 Envelope', Envelope-Monarch, Envelope-DL, Envelope-C5, and EuroPostcard. (Default: "A4")

You can also give a string in the form 'WIDTHxHEIGHT', where WIDTH and HEIGHT are numbers (in points). This sets the paper size to "Custom".

Setting this also sets "bounding_box", "height", and "width" to the full height and width of the paper.

width

$ps = PostScript::File->new( width => $width )

$width = $ps->get_width

$ps->set_width( $width )

The page width in points. This is normally the shorter dimension of the paper. Note that in landscape mode this is actually the height of the bounding box.

Setting this sets "paper" to "Custom" and the "bounding_box" is expanded to the full width.

Page Attributes

The following attributes can have a different value for every page. You can't set them directly in the constructor, but they all have a document-wide default value that each page inherits when it is created. When accessing or setting them, $page is the page label. If $page is omitted, it defaults to the current page.

page_bounding_box

( $llx, $lly, $urx, $ury ) = $ps->get_page_bounding_box( [$page] )

$ps->set_page_bounding_box( [$page,] $llx, $lly, $urx, $ury )

The bounding box for this page. The lower left corner is ($llx, $lly), and the upper right corner is ($urx, $ury).

Note that calling set_page_bounding_box automatically enables clipping for that page. If this isn't what you want, call $ps->set_page_clipping(0) afterwards.

When a page is created, page_bounding_box is initialized from the document's "bounding_box" attribute.

page_clipping

$clipping = $ps->get_page_clipping( [$page] )

$ps->set_page_clipping( [[$page,] $clipping] )

If $clipping is true, printing will be clipped to this page's bounding box. (Default: false)

When a page is created, page_clipping is initialized from the document's "clipping" attribute.

page_label

$ps = PostScript::File->new( page => $page )

$page = $ps->get_page_label

$ps->set_page_label( [$page] )

The label for the current page (used in the %%Page comment). (Default: "1")

Unlike the other page attributes, you can only access the page_label of the current page. (Since pages are specified by label, it makes no sense to ask for the label of a different page.)

When a page is created, page_label is initialized by passing the previous page's label to the "incpage_handler". For the first page, it's initialized from the page given to the constructor.

page_landscape

$landscape = $ps->get_page_landscape( [$page] )

$ps->set_page_landscape( [[$page,] $landscape] )

If $landscape is true, this page is using landscape mode. (Default: false)

When a page is created, page_landscape is initialized from the document's "landscape" attribute.

METHODS

Note: In the following descriptions, [] are used to denote optional parameters, not array references.

Constructor

new

$ps = PostScript::File->new(options)

Create a new PostScript::File object, either a set of pages or an Encapsulated PostScript (EPS) file. Options are hash keys and values. All values should be in the native PostScript units of 1/72 inch.

Example

$ps = PostScript::File->new(
        eps       => 1,
        landscape => 1,
        width     => 216,
        height    => 288,
        left      => 36,
        right     => 44,
        clipping  => 1,
      );

This creates an Encapsulated PostScript document, 4 by 3 inch pages printing landscape with left and right margins of around half an inch. The width is always the shortest side, even in landscape mode. 3*72=216 and 4*72=288. Being in landscape mode, these would be swapped. The bounding box used for clipping would then be from (50,0) to (244,216).

options may be a single hash reference instead of an options list, but the hash must have the same structure. This is more convenient when used as a base class.

The following keys are recognized options:

Attributes

The following attributes can be set through the constructor: "auto_hyphen", "clipping", "eps", "extensions", "file_ext", "filename", "height", "incpage_handler", "landscape", "langlevel", "order", "page_label", "paper", strip, "title", "version", and "width".

File size keys

There are four options which control how much gets put into the resulting file.

debug

undef

No debug code is added to the file. Of course there must be no calls to debug functions in the PostScript code. This is the default.

0

db_ functions are replaced by dummy functions which do nothing.

1

A range of functions are added to the file to support debugging PostScript. This switch is similar to the 'C' NDEBUG macro in that debugging statements may be left in the PostScript code but their effect is removed.

Of course, being an interpreted language, it is not quite the same as the calls still takes up space - they just do nothing. See "POSTSCRIPT DEBUGGING SUPPORT" for details of the functions.

2

Loads the debug functions and gives some reassuring output at the start and a stack dump at the end of each page.

A mark is placed on the stack at the beginning of each page and 'cleartomark' is given at the end, avoiding potential invalidrestore errors. Note, however, that if the page does not end with a clean stack, it will fail when debugging is turned off.

errors

PostScript has a nasty habit of failing silently. If errors is true, code that prints fatal error messages on the bottom left of the paper is added to the file. For user functions, a PostScript function report_error is defined. This expects a message string on the stack, which it prints before stopping. (Default: true)

headings

If true, add PostScript DSC comments recording the date of creation and user's name. (Default: false)

The comments inserted when headings is true are:

%%For: USER@HOSTNAME
%%Creator: Perl module PostScript::File v2.23
%%CreationDate: Sun Jan  1 00:00:00 2012
%%DocumentMedia: US-Letter 612 792 80 ( ) ( )

USER comes from getlogin() || getpwuid($<), and HOSTNAME comes from Sys::Hostname. The DocumentMedia values come from the paper size attributes. The DocumentMedia comment is omitted from EPS files.

If you want different values, leave headings false and use "add_comment" to add whatever you want.

reencode

Requests that a font re-encode function be added and that the fonts used by this document get re-encoded in the specified encoding. The only allowed values are cp1252, iso-8859-1, and ISOLatin1Encoding. You should almost always set this to cp1252, even if you are not using Windows.

The list of fonts to re-encode comes from the "need_fonts" parameter, the "need_resource" method, and all fonts added using "embed_font" or "add_resource". The Symbol font is never re-encoded, because it uses a non-standard character set.

Setting this to cp1252 or iso-8859-1 also causes the document to be encoded in that character set. Any strings you add to the document that have the UTF-8 flag set will be re-encoded automatically. Strings that do not have the UTF-8 flag are expected to be in the correct character set already. This means that you should be able to set this to cp1252, use Unicode characters in your code and the "-iso" versions of the fonts, and just have it do the right thing.

Windows code page 1252 (a.k.a. WinLatin1) is a superset of the printable characters in ISO-8859-1 (a.k.a. Latin1). It adds a number of characters that are not in Latin1, especially common punctuation marks like the curly quotation marks, en & em dashes, Euro sign, and ellipsis. These characters exist in the standard PostScript fonts, but there's no easy way to access them when using the standard or ISOLatin1 encodings. http://en.wikipedia.org/wiki/Windows-1252

For backwards compatibility with versions of PostScript::File older than 1.05, setting this to ISOLatin1Encoding re-encodes the fonts, but does not do any character set translation in the document.

Initialization keys

There are a few initialization settings that are only relevant when the file object is constructed.

bottom

The margin in from the paper's bottom edge, specifying the non-printable area. Remember to specify clipping if that is what is wanted. (Default: 28)

clip_command

The bounding box is used for clipping if this is set to "clip" or is drawn with "stroke". This also makes the whole page area available for debugging output. (Default: "clip").

font_suffix

This string is appended to each font name as it is re-encoded. (Default: "-iso")

The string value is appended to these to make the new names.

Example:

$ps = PostScript::File->new(
        font_suffix => "-iso",
        reencode => "cp1252"
      );

"Courier" still has the standard mapping while "Courier-iso" includes the additional European characters.

left

The margin in from the paper's left edge, specifying the non-printable area. Remember to specify clipping if that is what is wanted. (Default: 28)

need_fonts

An arrayref of font names required by this document. This is equivalent to calling $ps->need_resource(font => @$arrayref). See "need_resource" for details.

newpage

(v2.10) Normally, an initial page is created automatically (using the label specified by page). But starting with PostScript::File 2.10, you can pass newpage => 0 to override this. This makes for more natural loops:

use PostScript::File 2.10;
my $ps = PostScript::File->new(newpage => 0);
for (@pages) {
  $ps->newpage;  # don't need "unless first page"
  ...
}

It's important to require PostScript::File 2.10 if you do this, because older versions would produce an initial blank page.

If you don't pass a page label to the first call to newpage, it will be taken from the page option. After the first page, the page label will increment as specified by "incpage_handler".

The margin in from the paper's right edge. It is a positive offset, so right=36 will leave a half inch no-go margin on the right hand side of the page. Remember to specify clipping if that is what is wanted. (Default: 28)

top

The margin in from the paper's top edge. It is a positive offset, so top=36 will leave a half inch no-go margin at the top of the page. Remember to specify clipping if that is what is wanted. (Default: 28)

Debugging support keys

This makes most sense in the PostScript code rather than Perl. However, it is convenient to be able to set defaults for the output position and so on. See "POSTSCRIPT DEBUGGING SUPPORT" for further details.

db_active

Set to 0 to temporarily suppress the debug output. (Default: 1)

db_base

Debug printing will not occur below this point. (Default: 6)

db_bufsize

The size of string buffers used. Output must be no longer than this. (Default: 256)

db_color

This is the whole PostScript command (with any parameters) to specify the colour of the text printed by the debug routines. (Default: "0 setgray")

db_font

The name of the font to use. (Default: "Courier")

Courier
Courier-Bold
Courier-BoldOblique
Courier-Oblique
Helvetica
Helvetica-Bold
Helvetica-BoldOblique
Helvetica-Oblique
Times-Roman
Times-Bold
Times-BoldItalic
Times-Italic
Symbol

db_fontsize

The size of the font. PostScript uses its own units, but they are almost points. (Default: 10)

db_xgap

Typically, the output comprises single values such as a column showing the stack contents. db_xgap specifies the width of each column. By default, this is calculated to allow 4 columns across the page.

db_xpos

The left edge, where debug output starts. (Default: 6)

db_xtab

The amount indented by db_indent. (Default: 10)

db_ytop

The top line of debugging output. Defaults to 6 below the top of the page.

Error handling keys

If errors is set, the position of any fatal error message can be controlled with the following options. Each value is placed into a PostScript variable of the same name, so they can be overridden from within the code if necessary.

errfont

The name of the font used to show the error message. (Default: "Courier-Bold")

errmsg

The error message comprises two lines. The second is the name of the PostScript error. This sets the first line. (Default: "ERROR:")

errsize

Size of the error message font. (Default: 12)

errx

X position of the error message on the page. (Default: (72))

erry

Y position of the error message on the page. (Default: (72))

Main Methods

newpage

$ps->newpage( [$page] )

Generate a new PostScript page, unless in a EPS file when it is ignored.

If $page is not specified the previous page's label is incremented using the "incpage_handler".

output

$ps->output( [$file, [$dir]] )

If $file is an open filehandle, write the PostScript document to that filehandle and return nothing.

If a filename has been given either here, to new, or to set_filename, write the PostScript document to that file and return its pathname. ($file and $dir have the same meaning here as they do in set_filename.)

If no filename has been given, or $file is undef, return the PostScript document as a string.

In eps mode, each page of the document becomes a separate EPS file. In list context, returns a list of these files (either the pathname or the PostScript code as explained above). In scalar context, only the first page is returned (but all pages will still be processed). If you pass a filehandle when you have multiple pages, all the documents are written to that filehandle, which is probably not what you want.

Use this option whenever output is required to disk. The current PostScript document in memory is not cleared, and can still be extended or output again.

as_string

$postscript_code = $ps->as_string

This returns the PostScript document as a string. It is equivalent to $ps->output(undef).

testable_output

$postscript_code = $ps->testable_output( [$verbatim] )

This returns the PostScript document as a string, but with the PostScript::File generated code removed (unless $verbatim is true). This is intended for use in test scripts, so they won't see changes in the output caused by different versions of PostScript::File. The PostScript code returned by this method will probably not work in a PostScript interpreter.

If $verbatim is true, this is equivalent to $ps->output(undef).

Access Methods

Use these get_ and set_ methods to access a PostScript::File object's data.

get_metrics

$metrics = $ps->get_metrics( $font, [$size, [$encoding]] )

Construct a PostScript::File::Metrics object for $font. The $encoding is normally determined automatically from the font name and the document's encoding. The default $size is 1000.

If this document uses "reencode", and the font ends with "font_suffix", then the Metrics object will use that encoding. Otherwise, the encoding is std (except for the Symbol font, which always uses sym).

No matter what encoding the font uses, the Metrics object will always use the same Unicode translation setting as this document. It also inherits the current value of the "auto_hyphen" attribute.

set_min_langlevel

$new_langlevel = $ps->set_min_langlevel( $langlevel )

(v2.20) Set the "langlevel" attribute of this document to $langlevel, but only if the current level is less than $langlevel. It returns the value of langlevel, which will be greater than or equal to $langlevel.

set_page_margins

$ps->set_page_margins( [$page,] $left, $bottom, $right, $top )

This sets the "page_bounding_box" based on the paper size and the specified margins. It also automatically enables clipping for the page. If this isn't what you want, call $ps->set_page_clipping(0) afterwards.

get_page_printable_height

$height = $ps->get_page_printable_height( [$page] )

(v2.10) Returns the height of the page's bounding box (ury - lly).

get_page_printable_width

$width = $ps->get_page_printable_width( [$page] )

(v2.10) Returns the width of the page's bounding box (urx - llx.

get_page_variable

$value = $ps->get_page_variable( $key )

Retrieve a user defined value previously assigned by "set_page_variable".

set_page_variable

$ps->set_page_variable( $key, $value )

Assign a user defined hash key and value only valid on the current page. Provided to keep track of states within the PostScript code, such as which styles are currently active. PostScript::File does not use this (except to clear it at the start of each page). It is recommended that $key is the module name to avoid clashes. The $value could then be a hash holding any number of user variables.

get_pagecount

$pages = $ps->get_pagecount

Returns the number of pages currently in the document.

get_printable_height

$height = $ps->get_printable_height

(v2.10) Returns the height of the document's bounding box (ury - lly).

get_printable_width

$width = $ps->get_printable_width

(v2.10) Returns the width of the document's bounding box (urx - llx).

get_variable

$value = $ps->get_variable( $key )

Retrieve a user defined value previously assigned by "set_variable".

set_variable

$ps->set_variable( $key, $value )

Assign a user defined hash key and value. Provided to keep track of states within the PostScript code, such as which dictionaries are currently open. PostScript::File does not use this - it is provided for client programs. It is recommended that $key is the module name to avoid clashes. The $value could then be a hash holding any number of user variables.

Content Methods

add_comment

$ps->add_comment( $comment )

Append a comment to the document's DSC comments section. Most of the required and recommended comments are set directly from the document's attributes, so this method should rarely be needed. It is provided for completeness so that comments not otherwise supported can be added. $comment should contain the bare PostScript DSC name and value, with additional lines merely prefixed by +. It should NOT end with a newline.

Programs written for older versions of PostScript::File might use this to add a DocumentNeededResources comment. That is now deprecated; you should use "need_resource" instead.

Examples:

$ps->add_comment("ProofMode: NotifyMe");
$ps->add_comment("Requirements: manualfeed");

get_comments

$comments = $ps->get_comments

Retrieve any extra DSC comments added by "add_comment".

add_default

$ps->add_default( $default )

Use this to append a PostScript DSC comment to the Defaults section. These would be typically values like PageCustomColors: or PageRequirements:. The format is the same as for "add_comment".

get_defaults

$comments = $ps->get_defaults

Returns the contents of the DSC Defaults section, if any.

embed_document

$code = $ps->embed_document( $filename )

This reads the contents of $filename, which should be a PostScript file. It returns a string with the contents of the file surrounded by %%BeginDocument and %%EndDocument comments, and adds $filename to the list of document supplied resources.

You must pass the returned string to add_to_page or some other method that will actually include it in the document.

embed_font

$font_name = $ps->embed_font( $filename, [$type] )

This reads the contents of $filename, which must contain a PostScript font. It calls "add_resource" to add the font to the document, and returns the name of the font (without a leading slash).

If $type is omitted, the $filename's extension is used as the type. Type names are not case sensitive. The currently supported types are:

PFA

A PostScript font in ASCII format

PFB

A PostScript font in binary format. This requires the t1ascii program from http://www.lcdf.org/type/#t1utils. (You can set $PostScript::File::t1ascii to the name of the program to use. It defaults to t1ascii.)

TTF

A TrueType font. This requires the ttftotype42 program from http://www.lcdf.org/type/#typetools. (You can set $PostScript::File::ttftotype42 to the name of the program to use. It defaults to ttftotype42.)

Since TrueType (a.k.a. Type42) font support was introduced in PostScript level 2, embedding a TTF font automatically sets langlevel to 2 (unless it was already set to a higher level). Be aware that not all printers can handle Type42 fonts. (Even PostScript level 2 printers need not support them.) Ghostscript does support Type42 fonts (when compiled with the ttfont option).

need_resource

$ps->need_resource( $type, @resources )

This adds resources to the DocumentNeededResources comment. $type is one of encoding, file, font, form, pattern, or procset (case sensitive).

Any number of resources (of a single type) may be added in one call. For most types, $resource[N] is just the resource name. But for procset, each element of @resources should be an arrayref of 3 elements: [$name, $version, $revision]. Names that contain special characters such as spaces will be quoted automatically.

If need_resource is never called for the font type (and "need_fonts" is not used), it assumes the document requires all 13 of the standard PostScript fonts: Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic, and Symbol. But this behaviour is deprecated; a document should explicitly list the fonts it requires. If you don't use any of the standard fonts, pass need_fonts => [] to the constructor (or call $ps->need_resource('font')) to indicate that.

add_to_page

$ps->add_to_page( [$page,] $code )

This appends $code to the specified $page, which can be any page label. (Default: the current page)

If the specified $page does not exist, a new page is added with that label. Note that this is added on the end, not in the order you might expect. So adding "vi" to page set "iii, iv, v, 6, 7, 8" would create a new page after "8" not after "v".

Examples

$ps->add_to_page( <<END_PAGE );
    ...PostScript building this page
END_PAGE

$ps->add_to_page( "3", <<END_PAGE );
    ...PostScript building page 3
END_PAGE

The first example adds code onto the end of the current page. The second one either adds additional code to page 3 if it exists, or starts a new one.

get_page

$code = $ps->get_page( [$page] )

Returns the PostScript code from the body of the page.

add_page_setup

$ps->add_page_setup( $code )

Appends $code to the DSC PageSetup section. Note that this is a document-global value, although the code will be repeated on each page.

Also note that any settings defined here will be active for each page separately. Use "add_setup" if you want to carry settings from one page to another.

get_page_setup

$setup = $ps->get_page_setup

Returns the contents of the DSC PageSetup section, if any. Note that this is a document-global value, although the code will be repeated on each page.

add_page_trailer

$ps->add_page_trailer( $code )

Appends $code to the DSC PageTrailer section. Note that this is a document-global value, although the code will be repeated on each page.

Code added here is output after each page. It may refer to settings made during "add_page_setup" or "add_to_page".

get_page_trailer

$code = $ps->get_page_trailer

Returns the contents of the DSC PageTrailer section, if any. Note that this is a document-global value, although the code will be repeated on each page.

add_preview

$ps->add_preview( $width, $height, $depth, $lines, $preview )

Sets the EPSI format preview for this document - an ASCII representation of a bitmap. Only EPS files should have a preview, but that is not enforced. If an EPS file has a preview it becomes an EPSI file rather than EPSF.

get_preview

$preview = $ps->get_preview

Returns the EPSI preview of the document, if any, including the %%BeginPreview and %%EndPreview comments.

add_procset

$ps->add_procset( $name, $code, [$version, [$revision]] )

(v2.20) Add a ProcSet containing user defined functions to the PostScript prolog. $name is an arbitrary identifier of this resource. $code is a block of PostScript code, usually from a 'here' document. If the document already contains ProcSet $name (as reported by has_procset, then add_procset does nothing.

$version is a real number, and $revision is an unsigned integer. They both default to 0. PostScript::File does not make any use of these, but a PostScript document manager may assume that a procset with a higher revision number may be substituted for a procset with the same name and version but a lower revision.

Returns true if the ProcSet was added, or false if it already existed.

Example

$ps->add_procset( "My_Functions", <<END_FUNCTIONS );
    % PostScript code can be freely indented
    % as leading spaces and blank lines
    % (and comments, if desired) are stripped

    % foo does this...
    /foo {
        ... definition of foo
    } bind def

    % bar does that...
    /bar {
        ... definition of bar
    } bind def
END_FUNCTIONS

Note that get_procsets (in common with the others) will return all user defined functions possibly including those added by other classes.

has_procset

$exists = $ps->has_procset( $name )

(v2.20) This returns true if $name has already been included in the file. The name should be identical to that given to "add_procset".

get_procsets

$code = $ps->get_procsets

(v2.20) Return all the procsets defined in this document.

add_resource

$ps->add_resource( $type, $name, $params, $resource )
$type

A string indicating the DSC type of the resource. It should be one of Document, Feature, encoding, file, font, form, or pattern (case sensitive).

$name

An arbitrary identifier of this resource. (For a Font, it must be the PostScript name of the font, without a leading slash.)

$params

Some resource types require parameters. See the Adobe documentation for details.

$resource

A string containing the PostScript code. Probably best provided a 'here' document.

Use this to add fonts or images (although you may prefer "embed_font" or "embed_document"). "add_procset" is provided for functions.

Example

$ps->add_resource( "File", "My_File1",
                   "", <<END_FILE1 );
    ...PostScript resource definition
END_FILE1

get_resources

$resources = $ps->get_resources

Returns all resources provided by this document. This does not include procsets.

add_setup

$ps->add_setup( $code )

This appends $code to the DSC Setup section. Use this for setpagedevice, statusdict or other settings that initialize the device or document.

get_setup

$setup = $ps->get_setup

Returns the contents of the DSC Setup section, if any.

add_trailer

$ps->add_trailer( $code )

Appends $code to the document's DSC Trailer section. Use this for any tidying up after all the pages are output.

get_trailer

$code = $ps->get_trailer

Returns the contents of the document's DSC Trailer section, if any.

use_functions

$ps->use_functions( @function_names )

This requests that the PostScript functions listed in @function_names be included in this document. See PostScript::File::Functions for a list of available functions.

Text Processing Methods

convert_hyphens

$converted_text = $ps->convert_hyphens( $text )

Converts any HYPHEN-MINUS (U+002D) characters in $text to either HYPHEN (U+2010) or MINUS SIGN (U+2212) according to the rules described in "Hyphens and Minus Signs". This has the side-effect of setting the UTF-8 flag on $converted_text.

If $text does not have the UTF-8 flag set, it is assumed to be in the document's character encoding.

If $text does not contain any HYPHEN-MINUS characters, it is returned as-is.

decode_text

$text = $ps->decode_text( $encoded_text, [$preserve_minus] )

This is the inverse of "encode_text". It converts $encoded_text from the document's character encoding into Unicode. If $encoded_text already has the UTF-8 flag set, or the document is not using character translation, then it returns $encoded_text as-is.

If the optional argument $preserve_minus is true (and $encoded_text is not being returned as-is), then any HYPHEN-MINUS (U+002D) characters in $encoded_text are decoded as MINUS SIGN (U+2212). This ensures that encode_text will treat them as minus signs instead of hyphens.

encode_text

$encoded_text = $ps->encode_text( $text )

This returns $text converted to the document's character encoding. If $text does not have the UTF-8 flag set, or the document is not using character translation, then it returns $text as-is.

pstr

$code = $ps->pstr( $string, [$nowrap] )

$code = PostScript::File->pstr( $string, [$nowrap] )

$code = pstr( $string )

Converts the string to a PostScript string literal. If the result is more than 240 characters, it will be broken into multiple lines. (A PostScript file should not contain lines with more than 255 characters.)

When called as a class or object method, you can pass a second parameter $nowrap. If this optional parameter is true, then the string will not be wrapped, no matter how long it is.

When called as an object method, pstr will do automatic hyphen-minus translation if "auto_hyphen" is true. This has the side-effect of setting the UTF-8 flag on the returned string. (If the UTF-8 flag was not set on the input string, it will be decoded using the document's character set.) See "Hyphens and Minus Signs". For this reason, pstr should normally be called as an object method.

strip (method)

$ps->strip( $code )

$ps->strip( $strip => @code )

The strip method filters PostScript code according to the value of $strip, which can be any valid value for the strip attribute. The code is modified in-place; there is no return value. If $code is undef, it is left unchanged.

When called with a single argument, strips $code according to the current value of the strip attribute.

SUBROUTINES

array_as_string

$code = array_as_string( @array )

Converts a Perl array to a PostScript array literal. The array elements are used as-is. If you want an array of strings, you should do something like:

$code = array_as_string( map { $ps->pstr($_) } @array )

check_file

$pathname = check_file( $file, [$dir, [$create]] )
$file

An optional fully qualified path-and-file or a simple file name. If omitted or the empty string, the special file File::Spec->devnull is returned.

$dir

An optional directory path. If defined (and $file is not already an absolute path), it is prepended to $file.

$create

If true, create the file if it doesn't exist already. (Default: false)

This converts a filename and optional directory to an absolute path, and then creates any directories that don't already exist. Any leading ~ is expanded to the user's home directory using "check_tilde".

If $create is true, and $pathname does not exist, it is created as an empty file.

File::Spec is used throughout so file access should be portable.

check_tilde

$expanded_path = check_tilde( $path )

Expands a leading ~ or ~user in $path to the home directory.

incpage_label

$next_label = incpage_label( $label )

This function applies Perl's autoincrement operator to $label and returns the result. (This means that the magic string autoincrement applies to values that match /^[a-zA-Z]*[0-9]*\z/.)

This function is the default value of the "incpage_handler" attribute.

incpage_roman

$next_label = incpage_roman( $label )

This function increments lower case Roman numerals. $label must be a value between "i" and "xxxviii" (1 to 38), and $next_label will be "ii" to "xxxix" (2 to 39). That should be quite enough for numbering the odd preface.

This function is normally used as the value of the "incpage_handler" attribute:

$ps->set_incpage_handler( \&PostScript::File::incpage_roman )

quote_text

$quoted = quote_text( $string )

$quoted = PostScript::File->quote_text( $string )

$quoted = $ps->quote_text( $string )

Quotes the string if it contains special characters, making it suitable for a DSC comment. Strings without special characters are returned unchanged.

This may also be called as a class or object method, but it does not do hyphen-minus translation, even if "auto_hyphen" is true.

str

$code = str( $value )

If $value is an arrayref, returns array_as_string(@$value). Otherwise, returns $value as-is. This function was designed to simplify passing colors to the PostScript function "setColor" in PostScript::File::Functions, which expects either an RGB array or a greyscale decimal.

POSTSCRIPT DEBUGGING SUPPORT

This section documents the PostScript functions which provide debugging output. Please note that any clipping or bounding boxes will also hide the debugging output which by default starts at the top left of the page. Typical new options required for debugging would include the following.

$ps = PostScript::File->new (
        errors => "page",
        debug => 2,
        clipcmd => "stroke" );

The debugging output is printed on the page being drawn. In practice this works fine, especially as it is possible to move the output around. Where the text appears is controlled by a number of PostScript variables, most of which may also be given as options to new.

The main controller is db_active which needs to be non-zero for any output to be seen. It might be useful to set this to 0 in new, then at some point in your code enable it. Remember that the debugdict dictionary needs to be selected in order for any of its variables to be changed. This is better done with db_on but it illustrates the point.

/debugdict begin
    /db_active 1 def
end
(this will now show) db_show

At any time, the next output will appear at db_xpos and db_ypos. These can of course be set directly. However, after most prints, the equivalent of a 'newline' is executed. It moves down db_fontsize and left to db_xpos. If, however, that would take it below db_ybase, db_ypos is reset to db_ytop and the x coordinate will have db_xgap added to it, starting a new column.

The positioning of the debug output is changed by setting db_xpos and db_ytop to the top left starting position, with db_ybase guarding the bottom. Extending to the right is controlled by not printing too much! Judicious use of db_active can help there.

PostScript functions

x0 y0 x1 y1 cliptobox

This function is only available if 'clipping' is set. By calling the Perl method draw_bounding_box (and resetting with clip_bounding_box) it is possible to use this to identify areas on the page.

$ps->draw_bounding_box();
$ps->add_to_page( <<END_CODE );
    ...
    my_l my_b my_r my_t cliptobox
    ...
END_CODE
$ps->clip_bounding_box();

msg report_error

If 'errors' is enabled, this call allows you to report a fatal error from within your PostScript code. It expects a string on the stack and it does not return.

All the db_ variables (including function names) are defined within their own dictionary (debugdict). But this can be ignored by all calls originating from within code passed to add_to_page (usually including add_procset code) as the dictionary is automatically put on the stack before each page and taken off as each finishes.

any db_show

The workhorse of the system. This takes the item off the top of the stack and outputs a string representation of it. So you can call it on numbers or strings and it will show them. Arrays are printed using db_array and marks are shown as '--mark--'.

n msg db_nshow

This shows top n items on the stack. It requires a number and a string on the stack, which it removes. It prints out msg then the top n items on the stack, assuming there are that many. It can be used to do a labelled stack dump. Note that if new was given the option debug = 2>, There will always be a '--mark--' entry at the base of the stack. See "debug".

count (at this point) db_nshow

db_stack

Prints out the contents of the stack. No stack requirements.

The stack contents is printed top first, the last item printed is the lowest one inspected.

array db_print

The closest this module has to a print statement. It takes an array of strings and/or numbers off the top of the stack and prints them with a space in between each item.

[ (myvar1=) myvar1 (str2=) str2 ] db_print

will print something like the following.

myvar= 23.4 str2= abc

When printing something from the stack you need to take into account the array-building items, too. In the next example, at the point '2 index' fetches 111, the stack holds '222 111 [ (top=)' but 'index' requires 5 to get at 222 because the stack now holds '222 111 [ (top=) 111 (next=)'.

222 111
[ (top=) 2 index (next=) 5 index ] db_print

willl output this.

top= 111 next= 222

It is important that the output does not exceed the string buffer size. The default is 256, but it can be changed by giving new the option bufsize.

x y msg db_point

It is common to have coordinates as the top two items on the stack. This call inspects them. It pops the message off the stack, leaving x and y in place, then prints all three.

450 666
(starting point=) db_print
moveto

would produce:

starting point= ( 450 , 666 )

array db_array

Like "db_print" but the array is printed enclosed within square brackets.

var db_where

A 'where' search is made to find the dictionary containing var. The messages 'found' or 'not found' are output accordingly. Of course, var should be quoted with '/' to put the name on the stack, otherwise it will either be executed or force an error.

db_newcol

Starts the next debugging column. No stack requirements.

db_on

Enable debug output

db_off

Disable debug output

db_down

Does a 'carriage-return, line-feed'. No stack requirements.

db_indent

Moves output right by db_xtab. No stack requirements. Useful for indenting output within loops.

db_unindent

Moves output left by db_xtab. No stack requirements.

EXPORTS

No functions are exported by default. All the functions listed in "SUBROUTINES" may be exported by request.

In addition, the pstr method may be exported as a subroutine, but this usage is deprecated.

BUGS AND LIMITATIONS

When making EPS files, the landscape transformation throws the coordinates off. To work around this, avoid the landscape flag and set width and height differently.

Most of these functions have only had a couple of tests, so please feel free to report all you find.

AUTHOR

Chris Willmot <chris AT willmot.co.uk>

Thanks to Johan Vromans for the ISOLatin1Encoding.

As of September 2009, PostScript::File is now being maintained by Christopher J. Madsen <perl AT cjmweb.net>.

Please report any bugs or feature requests to <bug-PostScript-File AT rt.cpan.org>, or through the web interface at http://rt.cpan.org/Public/Bug/Report.html?Queue=PostScript-File

You can follow or contribute to PostScript::File's development at https://github.com/madsen/postscript-file.

COPYRIGHT AND LICENSE

Copyright 2002, 2003 Christopher P Willmot. All rights reserved.

Copyright 2015 Christopher J. Madsen. All rights reserved.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

SEE ALSO

PostScript Language Document Structuring Conventions Specification Version 3.0 and Encapsulated PostScript File Format Specification Version 3.0 published by Adobe, 1992. http://partners.adobe.com/asn/developer/technotes/postscript.html

PostScript::Convert, for PDF or PNG output.

PostScript::Calendar, for creating monthly calendars.

PostScript::Report, for creating tabular reports.

PostScript::ScheduleGrid, for printing schedules in a grid format.

PostScript::ScheduleGrid::XMLTV, for printing TV listings in a grid format.

PostScript::Graph::Paper, PostScript::Graph::Style, PostScript::Graph::Key, PostScript::Graph::XY, PostScript::Graph::Bar, PostScript::Graph::Stock.

DISCLAIMER OF WARRANTY

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.