NAME

PDF::Cairo - simple API for creating PDF files using the Cairo library

SYNOPSIS

PDF::Cairo is loosely based on the API of PDF::API2::Lite, but uses Cairo, Font::FreeType, and (optionally) Pango to provide better support for modern TrueType and OpenType fonts. Compatibility methods are provided to more easily convert existing scripts.

use PDF::Cairo qw(cm);
$pdf = PDF::Cairo->new(
    file => "output.pdf",
    paper => "a4",
    landscape => 1,
);
$font = $pdf->loadfont('Times-Bold');
$pdf->move(cm(2), cm(4));
$pdf->fillcolor('red');
$pdf->setfont($font, 32);
$pdf->print("Hamburgefontsiv");
$image = $pdf->loadimage("logo.png");
$pdf->showimage($image, cm(5), cm(5),
    scale => 0.5, rotate => 45);
$pdf->write;

DESCRIPTION

Cairo is a cross-platform vector graphics library that is capable of generating high-quality PDF output (as well as PNG, PS, and SVG). Unfortunately, the Cairo Perl module is not well documented or easy to use, especially in combination with Font::FreeType and/or Pango. PDF::Cairo adapts the simple and straightforward interface of PDF::API2::Lite, hiding the quirks of the underlying C libraries. Methods that do not return an explicit value return $self so they can be chained.

Many scripts can be ported from PDF::API2::Lite just by updating the module name; the "LIMITATIONS" section at the end of this manual documents a few exceptions and workarounds.

PDF::Cairo::Box is a simple rectangle-manipulation library for quickly dividing up a page, useful for making forms, graph papers, calendars, etc.

Creation

new %options
paper => $paper_size
file => $file
height => $Ypts
width => $Xpts
wide|landscape => 1
tall|portrait => 1

Creates a new PDF document object with the first page initialized. All arguments are optional. If called without either height/width or paper size, it defaults to US Letter (8.5x11 inches). You must use write(), saveas() or stringify() to output the results.

newpage %options

Ends the current page and creates a new one with the default graphics state. If called without any arguments, the new page will be the same size as the previous one.

write [$file]

Finishes the current PDF file and writes it to $file (either passed as an argument here or to new()). No further drawing operations can be performed.

pagebox

Creates a PDF::Cairo::Box with width and height set to the size of the current page in points. Does not take into account any coordinate transformations applied to the page.

Colors

Colors can be specified by name as per X11's rgb.txt file (see PDF::Cairo::Colors for a list), or by hex RGB value as #rgb, #rrggbb, or #rrrrggggbbbb.

fillcolor $color

Set the current fill color.

strokecolor $color

Set the current stroke color.

Graphics State Parameters

save

Saves the current graphics state.

restore

Restore the most recently saved graphics state.

linewidth $width

Set the current line width.

linedash [$on, $off, ...], $offset

Set the line dash style to the array reference of on-off lengths, starting the pattern at $on-off[$offset] (default $offset 0). If called without any arguments, a solid line will be drawn.

linecap $style

Set the line cap style to 'butt' (default), 'round', or 'square'.

linejoin $style

Set the line join style to 'miter' (default), 'round', or 'bevel'.

miterlimit $limit

Set the miter limit; if the current line join style is set to 'miter', the miter limit is used to determine whether the lines should be joined with a bevel instead of a miter. Cairo divides the length of the miter by the line width. If the result is greater than the miter limit, the style is converted to a bevel.

The default miter limit value is 10.0, which will convert joins with interior angles less than 11 degrees to bevels instead of miters. For reference, a miter limit of 2.0 makes the miter cutoff at 60 degrees, and a miter limit of 1.414 makes the cutoff at 90 degrees.

A miter limit for a desired angle can be computed as: miter limit = 1/sin(angle/2)

tolerance $flatness

Set the flatness tolerance (maximum distance in device pixels between the mathematically correct path and a polygon approximation). Cairo's default is 0.1, while PDF's is undefined and device-specific. Rarely used, unless you know the characteristics of the device where you'll eventually print your PDF file.

Coordinate Transformations

translate $Xdelta, $Ydelta

Translate the origin of the coordinate system.

rotate $degrees

Rotate the coordinate system counterclockwise. Use a negative argument to rotate clockwise.

scale $Xscale, [$Yscale]

Scale the coordinate system. If only one argument is passed, scale both X and Y.

skew $sa, $sb

Skews the coordinate system by $sa degrees (counter-clockwise) from the x axis and $sb degrees (clockwise) from the y axis.

Path Construction

move $x, $y

Begin a new (sub)path at ($x, $y).

rel_move $dx, $dy

Begin a new (sub)path offset from the current position by ($dx, $dy).

line $x, $y

Adds a line to the path from the current point to ($x, $y).

rel_line $dx, $dy

Adds a line to the path from the current point to a point that is offset from the current point by ($dx,$dy).

curve $cx1, $cy1, $cx2, $cy2, $x, $y

Extends the path in a curve from the current point to ($x, $y), using the two specified points to create a cubic Bézier curve, and updates the current position to be the new point.

rel_curve $dx1,$dy1, $dx2,$dy2, $dx3,$dy3

Adds a cubic Bézier spline to the path from the current point to a point offset from the current point by dx3 , dy3 ), using points offset by (dx1 , dy1 ) and (dx2 , dy2 ) as the control points. After this call the current point will be offset by (dx3 , dy3 ).

arc $x, $y, $a, $b, $alpha, $beta, $move

Extends the path along an arc of an ellipse centered at ($x, $y). The major and minor axes of the ellipse are $a and $b, respectively, and the arc moves from $alpha degrees to $beta degrees, counterclockwise. The current position is then set to the endpoint of the arc.

Set $move to a true value if this arc is the beginning of a new path instead of the continuation of an existing path.

poly $x1,$y1, $x2,$y2, ...

Equivalent to move($x1, $y1) followed by a series of line($xn, $yn).

rel_poly $dx1,$dy1, $dx2,$dy2, ...

Equivalent to rel_move($dx1, $dy1) followed by a series of rel_line($dxn, $dyn).

close

Adds a line segment to the path from the current point to the beginning of the current sub-path (the most recent point passed to move()), and closes this sub-path.

Closed Shapes

circle $x, $y, $radius

Creates a circular path centered on ($x, $y) with radius $radius.

ellipse $x, $y, $xRadius, $yRadius

Creates an elliptical path centered on ($x, $y), with major and minor axes specified by $a and $b, respectively.

polygon $x, $y, $scale, $sides, %options
edge => 1
inradius => 1

Creates a regular polygon path with $sides sides centered on ($x, $y) with circumradius length $scale. The bottom edge of the polygon is horizontal. If either the edge or inradius option is provided, set that length to $scale instead of the circumradius.

rect $x, $y, $width, $height

Draws a rectangle starting at ($x, $y) with $width and $height. Can also pass a single argument containing an array reference.

rel_rect $dx, $dy, $width, $height

Draws a rectangle offset from the current point by ($dx, $dy), with $width and $height. Can also pass a single argument containing an array reference.

roundrect $x, $y, $width, $height, [$radius]

Draws a rectangle starting at ($x, $y) with $width and $height, with corners rounded by $radius (defaults to 1/20th the length of the shortest side).

rel_roundrect $dx, $dy, $width, $height, [$radius]

Draws a rectangle offset from the current point by ($dx, $dy), with $width and $height, with corners rounded by $radius (defaults to 1/20th the length of the shortest side).

Path Painting

fill [evenodd => 1], [preserve => 1]

Fills the current path with the current fillcolor. The path is cleared unless you pass the preserve option. If a non-zero argument is provided, use the even-odd rule instead of the default non-zero winding rule.

stroke [preserve => 1]

Strokes the current path with the current linewidth and strokecolor. The path is cleared unless you pass the preserve option.

fillstroke [evenodd => 1]

Fills and then strokes the current path, exactly as if fill() and stroke() were called in order without clearing the path in between. If a non-zero argument is provided, use the even-odd rule instead of the default non-zero winding rule.

strokefill [evenodd => 1]

Strokes and then fills the current path, exactly as if stroke() and fill() were called in order without clearing the path in between. If a non-zero argument is provided, use the even-odd rule instead of the default non-zero winding rule.

clip [evenodd => 1], [preserve => 1]

Intersects the current path with the current clipping path. The path is cleared unless you pass the preserve option. If the evenodd argument is passed, use the even-odd rule instead of the default non-zero winding rule.

Note that this differs from PDF::API2, where you must call endpath() to clear the path after clip().

Text

loadfont $font, [$index|$metrics]

Load $font from disk with FreeType, returning a PDF::Cairo::Font object. If the file is not found in the current directory, the font path will be searched. If $font doesn't look like a file name, it will be matched against the PDF::API2 'core' and 'cjk' font names, and Fontconfig will be used to find something compatible.

For multi-font container formats (TTC, OTC, DFONT), $index can be supplied to select one of the other fonts; for PostScript PFB fonts, the location of an AFM metrics file can be supplied, or it will search the font path to find one with a matching name (case-insensitive).

setfont $fontref, [$size]

Set the current font and size. Default size is 1 point.

setfontsize $size

Set the size of the current font.

align => 'left|right|center'
valign => 'baseline|top|center'
shift => $vertical_shift
center => 1

Display text at current position, with current font and fillcolor. If the first argument is a font reference, the PDF::API2::Lite compatibility version of print() will be used instead.

The current position will be moved to the end of the displayed text. Any vertical shift will not affect the baseline of subsequent calls to print().

autosize $text, $box

Set the size of the current font to the largest value that allows $text to fit inside of the specified PDF::Cairo::Box object.

extents $text

Returns a PDF::Cairo::Box object containing the ink extents of $text as it would be rendered with the current font/size.

textpath $text

Add the outlines of the glyphs in $text to the current path, using the current font and size.

Raster Images

loadimage $file

Load a PNG-format image from $file. Returns a Cairo image surface that can be placed any number of times with showimage(); height() and width() methods are available to determine appropriate scaling values.

If ImageMagick's convert command is available, it will be used to convert other image formats into PNG.

showimage $image, $x, $y, %options
align => 'left|center|right'
valign => 'top|center|bottom'
center => 1
scale => $scale
size => [ $width, $height ]
x_scale => $scale
y_scale => $scale
rotate => $degrees

Display $image with its lower-left corner at ($x, $y), scaled at 100% in the current user coordinate unless one of the scaling options is supplied.

Advanced and Experimental

loadsvg $file|$string

Create an object with recording() containing an SVG image rendered with Image::CairoSVG, with the lower-left corner at (0,0). It can be rendered with place() as many times as you want. height() and width() methods are available to determine appropriate scaling values.

Note that Image::CairoSVG only supports path operators, and ignores filters, fonts, and text, so many complex SVG files will not render as expected.

path ['move|line|curve|close', [$x, $y, ...], ...]

Appends an array of move/line/curve/close operations to the current path. This is done with Cairo's append_path() method, so it's more efficient than calling each method one-by-one.

If no arguments are passed, returns the current path in this format, and then clears the path.

place $recording, $x,$y, %options
clip => [ $width, $height]
dx => $offset_x
dy => $offset_y
align => 'left|center|right'
valign => 'top|center|bottom'
center => 1
scale => $scale
size => [ $width, $height ]
x_scale => $scale
y_scale => $scale
rotate => $degrees

Places the recording object $recording with its lower-left corner at ($x,$y). If the clip argument is provided, the recording is clipped to that width/height before rendering. If $dx or $dy is provided, the recording will be offset by those amounts before rendering. This can be used to do things like tile a large image across multiple pages.

recording %options
paper => $paper_size
height => $Ypts
width => $Xpts
wide|landscape => 1
tall|portrait => 1

Creates a new PDF::Cairo recording object. You can draw on it normally, but can only access the results with place(). Options are the same as new(). height() and width() methods are available to determine appropriate scaling values. Recording surfaces are clipped to their size.

Utility Functions

These are imported from PDF::Cairo::Util so you don't have to explicitly use that module in every script.

cm $centimeters

Converts the arguments from centimeters to points. Importable.

in $inches

Converts the arguments from inches to points. Importable.

mm $millimeters

Converts the arguments from millimeters to points. Importable.

paper_size %options
paper => $paper_size
wide|landscape => 1
tall|portrait => 1

Return size in points of a paper type. The default is "US Letter" (8.5x11 inches). The wide/tall options can be used to ensure that the orientation of the page is as expected. Importable.

The supported paper sizes are listed in PDF::Cairo::Papers.

regular_polygon $sides

Calculate the vertices of a regular polygon with $sides sides with radius 1, along with the relative lengths of the inradius and edge.

Returns a hashref:

{
  points => [ [$x0, $y0], ... ],
  edge => $edge_length,
  inradius => $inradius_length,
  radius => 1,
}

Calling the polygon($cx, $cy, $radius, $sides) method is equivalent to:

$poly = regular_polygon($sides);
@points = map(@$_, @{$poly->{points}});
$pdf->save;
$pdf->translate($cx, $cy);
$pdf->scale($radius);
$pdf->poly(@points);
$pdf->close;
$pdf->restore;

PDF::API2 Compatibility

addFontDirs $directory, ...

Append one or more directories to the font search path. Returns the current font path.

clip $use_even_odd

Additional way to specify even-odd fill rule for clip().

cjkfont $font

Load something vaguely appropriate for the requested PDF::API2 CJK font name. See PDF::Cairo::Font for recommended alternatives.

corefont $fontname

Load the closest match to a PDF::API2 core font, as described in PDF::Cairo::Font.

endpath

Ends current (sub)path without close(). Generally only used after clip(), so it's effectively a no-op in PDF::Cairo.

fill $use_even_odd

Additional way to specify even-odd fill rule for fill().

fillstroke $use_even_odd

Additional way to specify even-odd fill rule for fillstroke().

image $image, $x, $y, ($width, $height) | [$scale]

Wrapper for showimage().

image_gif $file

Alias for loadimage(); requires ImageMagick convert program.

image_jpg $file

Alias for loadimage(); requires ImageMagick convert program.

image_png $file

Alias for loadimage().

image_pnm $file

Alias for loadimage(); requires ImageMagick convert program.

image_tiff $file

Alias for loadimage(); requires ImageMagick convert program.

linedash $length
linedash $dash1, $gap1, ...
linedash -pattern => [$dash1, $gap1, ...], -shift => $offset

Additional ways to pass arguments to linedash().

page [$width, $height]

Emulates the behavior of PDF::API2::Lite's page() method, which starts a new page, defaulting to the size of the previous page if there was one. Note that this does not accept the four-argument form with the coordinates of the lower-left and upper-right corners.

Sadly necessary, since I use it all the time with PDF::API2::Lite.

psfont $font

Load a Type 1 font from disk using FreeType. If a matching AFM file is found in the font path, it will also be loaded.

rectxy $x1, $x1, $x2, $y2

Draw a rectangle with opposite corners at ($x1, $y1) and ($x2, $y2).

restorestate

Alias for restore().

saveas $file

Finishes the current PDF file and saves it to $file. No further drawing operations can be performed.

savestate

Alias for save().

stringify

Finishes the current PDF file and returns it as a scalar. No further drawing operations can be performed.

transform %options
-translate => [$x, $y]
-rotate => $degrees
-scale => [$sx, $sy]
-skew => [$sa, $sb]

Perform multiple coordinate transforms at once, in PDF-canonical order.

ttfont $font

Load a TrueType/OpenType font from disk using FreeType.

PDF::API2::Lite Text Compatibility

These methods should not be used in new code, and are present solely to simplify converting existing scripts that use PDF::API2::Lite. Use PDF::Cairo::Layout instead. Honestly, in over 15 years of using PDF::API2::Lite, I never once used these methods.

Note that this is the Lite version, which exposes only a subset of the functionality in PDF::API2::Content.

textstart

Starts a block of text with the baseline set to (0, 0). You must translate the origin to get the text to appear anywhere else.

textfont $font, $size

Set the current font to $font at $size.

textlead $leading

Set the spacing between lines to $leading (default is 0, which prints all lines on top of each other).

text $string

Display text at current position, with the current font and fillcolor. The current position will be moved to the end of the displayed text.

nl

Move to the beginning of the next line of text (0, -$leading * ($lines - 1)).

textend

End the current text block.

LIMITATIONS

  • libcairo version must be 1.10.0 or greater to support recording surfaces, which this module makes extensive use of. Future versions will require 1.16.0 or greater to support metadata, outlines, hyperlinks, page labels, etc.

  • The fillcolor/strokecolor methods do not currently support the various %cmyk, &hsl, !hsv options for setting color values. (TODO)

  • All images are converted to PNG before embedding in the output. This is a limitation of the Cairo library.

  • Vector images placed with loadimage() are rasterized with ImageMagick's convert command.

  • Cairo only supports one active color at a time, not separate stroke and fill colors. I maintain a separate save/restore stack to work around this, and hopefully I haven't missed any edge cases.

  • No built-in support for the standard PDF fonts. All fonts will be embedded in the output, and unless you load a specific font file from disk, what you get when you specify a font name like "Helvetica-Bold" will depend on your computer's Fontconfig settings.

  • On a Mac, Fontconfig will only search a short list of well-known directories, which does not include the locations used by font managers like Typekit and FontExplorer Pro.

AUTHOR

J Greely, <jgreely at cpan.org>

SEE ALSO

PDF::API2, PDF::Builder, Cairo, Font::FreeType, Pango, Fontconfig, ImageMagick

Pages 187-192 of Adobe PPD Specifications

BUGS

Please report any bugs or feature requests to bug-pdf-cairo at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=PDF-Cairo. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc PDF::Cairo

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

This software is Copyright (c) 2019 by J Greely.

This is free software, licensed under:

MIT License