ETOOBUSY 🚀 minimal blogging for the impatient
PDF::Collage text align
TL;DR
Adding support for horizontal text alignment in PDF::Collage.
My (extremely) low-tech PDF template system PDF::Collage allows assembing a new PDF with some basic operations, like taking a page from another PDF or adding some text/images on top of a page.
Most of the times, this is just sufficient to get the job done. Although… the job can get done in a nicer way, sometimes.
One such occasion is when you have a letter (in the sense of the type of document) and some elements, like the recipient name/address, are written on the top-right, hopefully aligned to the right border. This is where aligning the text comes… handy.
I’m not aware of any way of doing this natively in PDF, and I doubt there is because of its nature. But… PDF::Builder::Resource::BaseFont has an aptly named width method that allows us to calculate the size of a string, so we’re done right?
This is how the text operation has evolved to take this into account:
sub _op_add_text ($self, $command) {
my $opts =
$self->_expand($command, qw< align page
font font_family font_size x y >);
my $content =
$self->_render_text($opts->@{qw< text text_template text_var >});
my $font = $self->_font($opts->{font} // $opts->{font_family});
my $font_size = $opts->{font_size};
my ($x, $y) = map { $_ // 0 } $opts->@{qw< x y >};
my $align = $opts->{align} // 'start';
if ($align ne 'start') {
my $width = $font_size * $font->width($content);
$x -= $align eq 'end' ? $width : ($width / 2);
}
my $page = $self->_pdf->open_page(__pageno($opts->{page} // 'last'));
my $text = $page->text;
$text->position($x, $y);
$text->font($font, $opts->{font_size});
$text->text($content // '');
return $self;
} ## end sub _op_add_text
There’s been some reshuffling because we need to know the fully rendered
string, as well as the reference X position, before we make any use of the
new align
option that we can fit into the several text operations. Then,
we’ll stick to the following convention:
- a missing value, an undefined value, or string
start
means that the text is aligned to the… start end
means that the text is aligned to the… end- everything else means that the text is aligned to the center.
A bit crude but it should work.
Anything different from start
(or its equivalents) mean that we have to
calculate the right X position for the start, by subtracting the right
amount depending on the needed alignment.
One interesting thing about the width
is that it assumes that the font is
1-pt
sized… so it’s necessary (and sufficient!) to multiply by the
actual font size and we have the whole string size. Neat!
Stay safe!