Perl API2 Font Examples

Justifying text without scaling

The built-in $txt->text_justify scales the text involved. It squeezes and stretches. Unless your column is nice and wide, the results are noticably crappy.

This example uses character spacing to get a nice clean justify like you would find in a newspaper.


#!/usr/local/bin/perl
use PDF::API2;

my $pdf  = PDF::API2->new(-file => "$$.pdf");
delete $pdf->{forcecompress};
$pdf->mediabox(612,792); ## 8.5 x 11 at 72 point thingies/inch.

$page = $pdf->page;                                  ## Create a new page.
$gfx = $page->gfx;                                   ## Graphics layer for lines and such.
my $txt = $page->text;                               ## Text Layer
$txt->compress;

## Create all needed font references.
my $times = $pdf->corefont('Times-Roman');

my $y;
my $xcol;
my $yStart = 792;

my $summary = "This is the text that will be split out into the various 
	thingees. This is paragraph one, and it has too much text in it.
This is paragraph two, and it also has more than one line of text.";

my @allLines = split/\n+/, $summary;


my $para;
foreach $para (@allLines){
	$txt->font($times, 7);
	$y -= 9;
	my $indent = 1;
	my $check = 1;
	while ($check){
		my ($charspace, $text, $over);
		if ($indent){
			$txt->translate($xcol-52,$y);
			($charspace, $text, $over) = newspaper_line($para, 124);
			$txt->charspace($charspace); 
			$txt->text($text);
			$indent = 0;
		}
		else {
			$txt->translate($xcol-72,$y);
			($charspace, $text, $over) = newspaper_line($para, 144);
			$txt->charspace($charspace); 
			$txt->text($text);
		}
		if ($over){
			$para = $over;
			$y -= 10;
		} else {
			$check = 0;
		}
	}
}

$pdf->finishobjects($page,$gfx,$txt);
$pdf->saveas;
$pdf->end();


sub newspaper_line {
	my $text = shift;
	my $width = shift;
	$txt->charspace(0); 
	## Accepts FONT, SIZE, TEXT, WIDTH
	## Returns CHARSPACE, RENDERTEXT, REMAINDERTEXT

	## Start out by splitting the TEXT on spaces into a big array.
	my @words = split/ +/, $text;
	my $i = 0;
	my $tempLine;

	## Now go through progressively larger strings until it no longer fits.
	## for ($i = 0; $i <= $#words; ++$i){
	do {
		$tempLine .= "$words[$i] ";
		++$i;
	} until ( ( $txt->advancewidth($tempLine) > $width ) || ($i > $#words ) );
	if (($i > $#words) && !( $txt->advancewidth($tempLine) > $width )){
		return(0, $tempLine, "");
	}
	--$i; ## then decrement so it DOES fit.
	## warn "We are taking $i words.";

	my $k; ## another looper for segmenting the word array....
	my $run;
	my $overrun;
	for ($k = 0; $k <= $#words; ++$k){
		if ($k < $i) { $run .= "$words[$k] " }	
		else { $overrun .= "$words[$k] " }
	}

	## Set up the control.
	$txt->charspace(0); 
	my $nominal = $txt->advancewidth($run);
	## Now the experiment.
	$txt->charspace(1); 
	my $experiment = $txt->advancewidth($run);
	## SINCE 0 -> $nominal   AND   1 -> $experiment
	if (!($nominal)) {return 0}
	my $diff = $experiment - $nominal;
	my $min  = $width - $nominal;
	my $target = $min / $diff;
	$txt->charspace($target); 
	my $final = $txt->advancewidth($run);
	$txt->charspace(0); 
	return($target, $run, $overrun);
}