NAME
PDF::Make::Builder - High level chainable PDF document builder
SYNOPSIS
use PDF::Make::Builder;
# Simple document
PDF::Make::Builder->new(file_name => 'report.pdf')
->add_page(page_size => 'A4')
->title('Quarterly Report')
->author('Jane Smith')
->add_h1(text => 'Introduction')
->add_text(text => 'Revenue increased 15% year-over-year.')
->add_image(image => 'chart.jpg', w => 400)
->save;
# With configuration defaults
my $b = PDF::Make::Builder->new(
file_name => 'styled.pdf',
configure => {
text => { font => { family => 'Times', size => 11 } },
h1 => { font => { family => 'Helvetica', size => 24 } },
},
);
$b->add_page(page_size => 'Letter', padding => 36)
->add_h1(text => 'Title')
->add_text(text => 'Body text inherits Times 11pt.')
->save;
DESCRIPTION
PDF::Make::Builder is the recommended high level API for creating PDF documents. It wraps the low level PDF::Make::Document and PDF::Make::Canvas with a chainable, bottom-left coordinate system that handles page layout, word-wrap, font management, and content placement automatically.
Every method returns $self, enabling fluent method chaining.
CONSTRUCTOR
new(%args)
my $b = PDF::Make::Builder->new(
file_name => 'output.pdf', # required
configure => { ... }, # optional defaults
page_offset => 0, # page number offset
);
file_name(Str, required) - Output filename..pdfis appended if missing.configure(HashRef) - Default font/style overrides keyed by element type (text,h1-h6,toc). Each accepts afontsub-hash withfamily,size,colour,line_height.
METHODS
Page Management
add_page(%args)
$b->add_page(
page_size => 'A4', # A4, Letter, Legal, A3, A5, B5, Tabloid
padding => 20, # margin in points
columns => 1, # number of text columns
background => '#fff', # hex background color
);
Add a new page and make it the current page. Finalises the previous page's content stream automatically.
open_page($num)
$b->open_page(2); # switch to page 2 (1-based)
Switch the current page to an existing page by number.
remove_page($index)
$b->remove_page(0); # remove first page (0-based)
Remove a page by 0-based index. Remaining pages are renumbered.
move_page($from, $to)
$b->move_page(2, 0); # move page 3 to position 1
Move a page from one position to another (0-based indices).
duplicate_page($index)
$b->duplicate_page(0); # duplicate first page
Create a copy of a page (layout only, not content).
rotate_page($index, $degrees)
$b->rotate_page(0, 90); # rotate first page 90 degrees
Rotate a page. Valid values: 0, 90, 180, 270.
set_columns($n)
$b->set_columns(2);
Set the number of text columns on the current page.
Metadata
All metadata methods set values on the underlying PDF Info dictionary.
title($text)
$b->title('My Document');
author($text)
$b->author('Jane Smith');
subject($text)
$b->subject('Annual Report');
keywords($text)
$b->keywords('pdf, report, 2026');
creator($text)
$b->creator('MyApp v2.0');
producer($text)
$b->producer('PDF::Make');
Text Content
add_text(%args)
$b->add_text(
text => 'Hello world',
font => { family => 'Helvetica', size => 12, colour => '#333' },
align => 'left', # left, center, right
indent => 0, # first-line indent in points
padding => 5, # vertical padding
);
Add a paragraph of word-wrapped text at the current cursor position. Overflows to new pages automatically.
add_h1(%args) .. add_h6(%args)
$b->add_h1(text => 'Chapter Title');
$b->add_h2(text => 'Section');
Add headings with preset font sizes. H1 is largest (24pt bold), H6 is smallest (10pt bold). Accepts the same arguments as add_text.
add_lines(@lines)
$b->add_lines(
'First line of text.',
'Second line of text.',
{ text => 'Styled line', font => { size => 14, colour => '#c00' } },
);
Convenience wrapper that calls add_text for each element in @lines. Each element may be a plain string (used as text => $str) or a HashRef of named arguments passed directly to add_text.
Shapes
add_line(%args)
$b->add_line(
x => 72, # start X
ex => 523, # end X
fill_colour => '#000',
type => 'solid', # solid, dashed, dotted
);
add_box(%args)
$b->add_box(x => 72, w => 200, h => 100, fill_colour => '#eee');
add_circle(%args)
$b->add_circle(cx => 200, cy => 400, r => 50, fill_colour => '#0066cc');
add_ellipse(%args)
$b->add_ellipse(cx => 200, cy => 400, rx => 80, ry => 40);
add_pie(%args)
$b->add_pie(
cx => 200, cy => 400, r => 50,
start_angle => 0, end_angle => 90,
fill_colour => '#cc0000',
);
Images
add_image(%args)
$b->add_image(
image => 'photo.jpg', # path to JPEG or PNG
w => 300, # width (height auto-calculated)
align => 'center', # left, center
);
Fonts
load_font(%args)
$b->load_font(family => 'Courier', size => 10, colour => '#333');
Set the default font for subsequent text operations.
load_ttf($path, %args)
$b->load_ttf('fonts/MyFont.ttf', name => 'MF1');
Load a TrueType font file and register it in the document.
Table of Contents
add_toc(%args)
$b->add_toc(title => 'Contents');
Initialise a table of contents. TOC entries are collected from headings and rendered during save().
Headers and Footers
add_page_header(%args)
$b->add_page_header(
cb => sub { my ($builder, $page, $num) = @_; ... },
height => 30,
);
Add a repeating header to all pages (current and future).
add_page_footer(%args)
$b->add_page_footer(
cb => sub { my ($builder, $page, $num) = @_; ... },
height => 30,
);
Add a repeating footer to all pages.
remove_page_header()
Remove the page header from subsequent pages.
remove_page_footer()
Remove the page footer from subsequent pages.
remove_page_header_and_footer()
Remove both header and footer from subsequent pages.
Outlines (Bookmarks)
add_outline($title, %args)
$b->add_outline('Chapter 1', page => 0);
$b->add_outline('Section 1.1', page => 0, parent => 'Chapter 1');
$b->add_outline('Chapter 2', page => 1, dest => 'FitH', top => 700);
Add a PDF outline (bookmark) entry.
page(Int, default 0) - 0-based page indexparent(Str) - Title of the parent outline for nestingdest(Str, default 'Fit') - Destination type: Fit, FitH, FitV, XYZleft,top,zoom(Num) - Destination parameters
Links and Actions
add_link(%args)
# External URL
$b->add_link(url => 'https://example.com', rect => [72, 700, 200, 720]);
# Builder coordinates (bottom-left origin)
$b->add_link(url => 'https://example.com', x => 72, y => 140, w => 220, h => 28);
# Internal page link
$b->add_link(page => 3, rect => [72, 670, 200, 690]);
# Named action (NextPage, PrevPage, FirstPage, LastPage, Print)
$b->add_link(action => 'NextPage', rect => [72, 640, 200, 660]);
# Link to external PDF
$b->add_link(file => 'other.pdf', file_page => 0, rect => [72, 610, 200, 630]);
Add a clickable link annotation. Requires rect as [x0, y0, x1, y1] in PDF coordinates. Provide one of: url (external), page (internal GoTo), action (named action), or file (external PDF).
For builder-layer coordinates (bottom-left origin), provide x, y, w, and h instead of rect. These are converted to PDF annotation coordinates automatically.
Attachments
attach(%args)
$b->attach(
name => 'data.csv', # required
data => $csv_string, # provide data or path
path => '/path/to/file', # alternative to data
mime => 'text/csv', # auto-detected if omitted
description => 'Raw export data',
);
Embed a file attachment in the PDF.
Watermarks
add_watermark(%args)
$b->add_watermark(
text => 'DRAFT', # required
opacity => 0.3,
rotation => 45,
color => [0.8, 0.2, 0.2],
size => 72,
);
Add a text watermark to all pages. See PDF::Make::Watermark for all options.
Layers (Optional Content Groups)
add_layer($name, %args)
$b->add_layer('Dimensions', visible => 1);
Create a named layer on the current page.
begin_layer($name)
$b->begin_layer('Dimensions');
Start drawing on the named layer.
end_layer()
$b->end_layer;
Stop drawing on the current layer.
Redaction
mark_redaction(%args)
$b->mark_redaction(
page => 0, # 0-based page index
rect => [100, 700, 300, 720],
overlay_color => [0, 0, 0],
overlay_text => 'REDACTED',
);
Mark a rectangular area for redaction.
apply_redactions()
Apply all redaction marks across all pages.
sanitize()
Remove all metadata (title, author, etc.) from the document.
Color Spaces
set_color_space($type, %args)
$b->set_color_space('sRGB');
$b->set_color_space('separation',
name => 'PANTONE 185 C', c => 0, m => 0.81, y => 0.69, k => 0);
Register a color space in the document.
Tagged PDF (Accessibility)
enable_tagging()
$b->enable_tagging;
Enable tagged PDF output with a structure tree for accessibility.
Form Fields
add_field(%args)
Structured mode (cursor-based component rendering):
$b->add_field(
type => 'text',
name => 'email',
label => 'Email Address',
w => 300,
default_value => 'user@example.com',
);
$b->add_field(
type => 'checkbox',
name => 'agree',
label => 'I agree to the terms',
w => 16, h => 16,
);
Raw mode (explicit coordinates):
$b->add_field(
type => 'text',
name => 'email',
raw_mode => 1,
rect => [72, 700, 300, 720],
default => 'user@example.com',
);
Single form API with two modes:
=over 4
=item * Structured mode via C<type>/C<name> (cursor-based layout,
labels, styled borders). Supported types: C<text>, C<checkbox>, C<radio>,
C<combo>/C<dropdown>, C<listbox>/C<list>, C<button>.
=item * Raw mode via C<raw_mode =E<gt> 1> or explicit coordinates
(C<rect>, C<x>, C<y>) for direct widget placement.
=back
See L<PDF::Make::Builder::Form::Field> for structured-mode properties.
flatten_form()
Burn form field appearances into page content (makes fields non-editable).
Encryption
encrypt(%args)
$b->encrypt(password => 'secret', algorithm => 'AES-256');
$b->encrypt(
user_password => 'read',
owner_password => 'admin',
permissions => 0x04,
algorithm => 'AES-128', # RC4-40, RC4-128, AES-128, AES-256
);
Configure PDF encryption. Applied during save().
Digital Signatures
sign(%args)
$b->sign(pkcs12 => 'cert.p12', password => 'secret', reason => 'Approval');
Configure a digital signature. Applied during save().
Annotations
add_note(%args)
Visual note (drawn callout box with lines of text):
$b->add_note(
lines => [
'Note: Review section 3.2 before final sign-off.',
{ text => '-- QA Team, 2026-04-21', size => 9, italic => 1 },
],
bg_colour => '#fffbeb',
colour => '#92400e',
x => 72, w => 300, h => 70,
);
Annotation note (PDF viewer sticky note):
$b->add_note(
rect => [72, 700, 92, 720],
text => 'Review this section',
icon => 'Comment', # Note, Comment, Key, Help, Paragraph, Insert
open => 1, # show expanded
);
When lines (or text as an ArrayRef) is supplied the method draws a coloured rectangle with the lines rendered inside it. Omit y to use cursor-relative placement.
Visual note options:
lines(ArrayRef, required) - Lines to render. Each element is a plain string or a HashRef withtext,size,colour,italickeys.x(Num, default 72) - Left edgey(Num) - Bottom edge; omit to use cursor positionw(Num, default 300) - Widthh(Num, default 70) - Heightbg_colour/fill_colour(Str, default '#fffbeb') - Background fillcolour(Str, default '#92400e') - Default text coloursize(Num, default 10) - Default font sizepadding(Num, default 12) - Inner padding in pointsline_gap(Num, default 14) - Vertical gap between lines in points
add_stamp(%args)
Visual stamp (drawn box with centred bold label):
$b->add_stamp(
text => 'APPROVED',
bg_colour => '#dcfce7',
colour => '#16a34a',
size => 24,
x => 72,
w => 200,
h => 50,
);
Annotation stamp (PDF viewer rubber-stamp annotation):
$b->add_stamp(
rect => [400, 700, 550, 750],
type => 'Approved', # Draft, Approved, Confidential, Final, etc.
);
When text is supplied the method draws a coloured rectangle with centred bold text on the current page. Provide y to place it at an absolute coordinate, or omit y to use cursor-relative placement (the cursor advances past the stamp automatically).
Visual stamp options:
text(Str, required) - The label to displayx(Num, default 72) - Left edgey(Num) - Bottom edge; omit to use cursor positionw(Num, default 200) - Widthh(Num, default 50) - Heightbg_colour/fill_colour(Str, default '#e5e7eb') - Background fillcolour(Str, default '#111827') - Text and border coloursize(Num, default 20) - Font sizeborder(Num, default 0) - Border width; 0 means no borderborder_colour(Str) - Border colour; defaults tocolour
Annotation stamp types: Draft, Approved, Experimental, NotApproved, AsIs, Expired, NotForPublicRelease, Confidential, Final, Sold, Departmental, ForLegalReview.
Bates Numbering
add_bates(%args)
$b->add_bates(
prefix => 'ACME',
start => 1,
digits => 6,
suffix => '-2026',
position => 'bottom_right',
);
Apply Bates numbering to all pages. See PDF::Make::Watermark for full options.
Custom Metadata
set_meta($key, $value)
$b->set_meta('Department', 'Engineering');
Set a custom metadata key in the PDF Info dictionary.
get_meta($key)
my $val = $b->get_meta('Department');
Get a custom metadata value.
Page Info
page_count()
my $n = $b->page_count;
Returns the number of pages in the document.
Text Extraction
extract_text($file, $page_index)
my $text = $b->extract_text('existing.pdf', 0);
Extract text from page $page_index (default 0) of an existing PDF file.
Opening Existing PDFs
open_existing($file, %args)
my $b = PDF::Make::Builder->open_existing('input.pdf',
file_name => 'output.pdf',
);
$b->add_page->add_text(text => 'New page appended');
$b->save;
Class method. Parses an existing PDF and creates a Builder with pages matching the original dimensions. New content can then be added and saved.
Output
to_bytes()
my $pdf_data = $b->to_bytes;
Finalise and return the PDF as a byte string (instead of writing to file). Useful for serving PDFs over HTTP or embedding in other formats.
Lifecycle
save()
$b->save;
Finalise all pages, apply encryption/signatures, render headers/footers and TOC, then write the PDF to file_name.
onsave($key, $method, %args)
Register a callback to run during save.
PAGE SIZES
Supported named sizes for add_page(page_size => ...):
A3 842 x 1191 pt
A4 595 x 842 pt
A5 420 x 595 pt
B5 499 x 709 pt
Letter 612 x 792 pt
Legal 612 x 1008 pt
Tabloid 792 x 1224 pt
SEE ALSO
PDF::Make for the distribution overview.
PDF::Make::Document, PDF::Make::Canvas for the low-level API.
PDF::Make::Builder::Text, PDF::Make::Builder::Font, PDF::Make::Builder::Page, PDF::Make::Builder::Image.
AUTHOR
LNATION <email@lnation.org>
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.