Reputation: 598
I have lots of pdf documents to merge together, so I wrote this code to do it. It works for the case where I only have two pdf documents to merge, but if I give it more than two, the extra documents come out garbled. Can you help me find what's wrong?
#!/usr/bin/perl
use PDF::API2;
use List::Util qw( reduce );
# Given two pdfs and a page number, appends the given page of the second pdf to the first pdf
sub append_page_to_pdf {
my ( $pdf1, $pdf2, $pg ) = @_;
$pdf1->importpage( $pdf2, $pg );
}
# Given two pdfs, appends the second to the first. Closes pdf2
sub merge_2_pdfs {
my ($pdf1, $pdf2) = @_;
map &append_page_to_pdf( $pdf1, $pdf2, $_ ), 1..$pdf2->pages;
$pdf2->end;
return $pdf1;
}
# does what it says
sub open_pdf {
my $file = $_[0];
my $pdf = PDF::API2->open( $file );
print "Opened pdf ( $file )\n";
return $pdf;
}
# reduces merge_2_pdfs over an array of pdfs
sub merge_pdfs {
my @files = @_;
my $starting_filename = shift @files;
my $start_pdf = &open_pdf( $starting_filename );
my $final_pdf = reduce { &merge_2_pdfs( $a, &open_pdf( $b ) ) } $start_pdf, @files;
return $final_pdf;
}
# Get the arguments ie save_name, file1, file2, file3, ...
my @files = @ARGV;
my $save_name = shift @files;
my $save = &merge_pdfs( @files );
$save->saveas( $save_name );
Upvotes: 2
Views: 4333
Reputation: 8963
Another possibility is my library, CAM::PDF.
my $pdf1 = CAM::PDF->new($file1) or die;
my $pdf2 = CAM::PDF->new($file2) or die;
my $pdf3 = CAM::PDF->new($file3) or die;
$pdf1->appendPDF($pdf2);
$pdf1->appendPDF($pdf3);
$pdf1->cleanoutput($outfile);
or wrap it in a loop over @ARGV perhaps. For just two PDFs, I have a simple cmdline wrapper to do the same:
appendpdf.pl file1.pdf file2.pdf out.pdf
Upvotes: 1
Reputation: 6798
The actual problem in your code is because you shift
one of the files off before you merge them.
my $save_name = shift @files;
# which should be
my $save_name = $files[0];
Otherwise, the code actually works, and I didn't find anything garbled.
A few tips:
use strict
and use warnings
The general practice now is to omit the &
in your subroutine calls. See here for exceptions to that rule.
In this case, the subroutines make your code verbose, which made it harder to follow. Here's something more concise.
use strict;
use warnings;
use List::Util 'reduce';
use PDF::API2;
my $new
= reduce { $a->importpage($b, $_) foreach 1 .. $b->pages; $a }
map { PDF::API2->open($_) }
@ARGV;
$new->saveas('new.pdf');
A simple loop is a little more straighforward to read than using reduce
.
use PDF::API2;
my $new = PDF::API2->new;
foreach my $filename (@ARGV) {
my $pdf = PDF::API2->open($filename);
$new->importpage($pdf, $_) foreach 1 .. $pdf->pages;
}
$new->saveas('new.pdf');
Upvotes: 4
Reputation: 118128
prFile('myFile.pdf');
for my $pdf (@PDFS) {
prDoc($pdf);
}
prEnd();
Upvotes: 1