#!/usr/bin/perl -w # Author : Dr. Detlef Groth dgroth(at)gmx(dot)de # Created : Sat Oct 21 07:27:38 2006 # Last Modified : <070603.1811> # $Log:$ package CombinePDFs; our $VERSION = "0.2" ; use PDF::Reuse; use strict; our @parts ; # keeps track of the pages ranges our $total = 0 ; # current page number sub addDoc { my $file = shift ; my $pages = shift; my $n = 0 ; if ($pages =~ m/^[0-9]+$/) { # single page prDoc($file,$pages,$pages); $n = 1 ; } elsif ($pages =~ m/^[0-9]+-[0-9]+$/) { # pagerange my @range = split(/-/,$pages); $n = prDoc($file,$range[0],$range[1]); } elsif ($pages =~ m/^[0-9]+-end+$/) { # pages till the end of the document my @range = split(/-/,$pages); $n = prDoc($file,$range[0]); } elsif ($pages eq "all") { $n = prDoc($file); } $total += $n ; #print "$file\t$total\n"; } sub createBookmarks { my $file = shift; my @last_levels ; my @bookmarks ; my $cnt = 0 ; my $current ; open (FILE, "$file") or die "Could not open file $file at $!" ; while (<FILE>) { next if /^\n/ ; if (/^([0-9])\s+"(.+)"\s+([0-9]+)\s*([0-9]*)/) { my $level = $1 ; my $text = $2 ; my $page = $3; $page-- ; my $scroll = $4; if ($level == 0) { if ($current) { $bookmarks[$cnt++] = $current; } # redefine current if ($scroll) { $current = { text => $text, act => "$page,40,$scroll", page => "$page,40,$scroll", close => 1 }; } else { $current = { text => $text, close => 1 , act => "this.pageNum = $page;", page => "$page" }; } } elsif ($level >= 1) { my $mark ; if ($scroll) { $mark = { text => $text, act => "$page,40,$scroll", page => "$page,40,$scroll" }; } else { $mark = { text => $text, act => "this.pageNum = $page;", page => "$page" }; } if ($level == 1) { if ($current->{kids}) { push @{$current->{kids}}, $mark; } else { $current->{kids} = [$mark]; } } elsif ($level == 2) { if ($current->{kids}[-1]->{kids}) { push @{$current->{kids}[-1]->{kids}}, $mark ; } else { $current->{kids}[0]->{kids} = [$mark] ; } } elsif ($level == 3) { if ($current->{kids}[-1]->{kids}[-1]) { push @{$current->{kids}[-1]->{kids}[-1]->{kids}}, $mark ; } else { $current->{kids}[-1]->{kids}[0]->{kids} = [$mark] ; } } } } } close (FILE); $bookmarks[$cnt] = $current; #prBookmark({text => "Dokument", close => 1, kids => \@bookmarks}); prBookmark(\@bookmarks); } sub createPDF { my $infile = shift ; my @infile = @{$infile} ; my $pages = shift ; my @pages = @{$pages} ; @parts = (); $total = 0; my $outfile = shift ; my $bookmarks = shift ; my $ndocs = $#pages ; unlink $outfile if (-e $outfile) ; unlink "$outfile.tmp" if (-e "$outfile.tmp") ; prFile($outfile); if($bookmarks) { createBookmarks($bookmarks); } foreach my $x (0..$ndocs) { push(@parts,$total); foreach my $prange (split(/,/,$pages[$x])) { addDoc($infile[$x],$prange); } } # last entry must be added as well push(@parts,$total); prEnd(); } sub isPDF { my $pdffile = shift; open (PDFFILE, "$pdffile") or die "Could not open file at $!" ; my $header = <PDFFILE> ; my $res = 0 ; if ($header =~ m/^%PDF-1.[0-9]/) { $res = 1 ; } close (PDFFILE); } sub getPagesParts { return @parts ; } sub addBookmarksByArray { my $infile = shift ; my $outfile = shift ; my @partnames = @_ ; my @last_levels ; my @bookmarks ; my $cnt = 0 ; my $current ; my $mark ; my $x = 0 ; foreach my $part (@partnames) { my @bm = split(/\t/,$part) ; if ($bm[0] == 0) { if ($current) { $bookmarks[$cnt++] = $current; } # redefine current if ($parts[$x] eq "None") { $current = { text => $bm[1], close => 1 }; } else { $current = { text => $bm[1], close => 1 , act => "this.pageNum = $parts[$x];", page => "$parts[$x]" }; } } elsif ($bm[0] == 1) { $mark = { text => $bm[1], act => "this.pageNum = $parts[$x];", page => "$parts[$x]" #act => $parts[$x] }; if ($current->{kids}) { push @{$current->{kids}}, $mark; } else { $current->{kids} = [$mark]; } } $x++; } $bookmarks[$cnt] = $current; prFile($outfile); prBookmark(\@bookmarks); prDoc($infile); prEnd(); prBookmark(\@bookmarks); prDoc($infile); prEnd(); } 1; __END__ =head1 NAME CombinePDFs - utility package for combining PDF documents with PDF::Reuse =head1 SYNOPSIS use CombinePDFs; prFile('myFile.pdf'); my @infiles = ('in1.pdf','in2.pdf','in1.pdf'); my @ranges = ('1-4,5','9-12','8-10'); if (CombinePDFs::isPDF(@infiles)) { CombinePDFs::createPDF(\@infiles,\@ranges,'outfile.pdf'); } prEnd(); =head1 DESCRIPTION This module provides an high level abstraction layer over the great PDF::Reuse module of Lars Lundberg. =head1 FUNCTION =head2 createPDF - add files with possible page ranges createPDF(\@infiles,\@ranges,$outfile,[$bookmarksfile]) The specified range might be a single page specified with a number, a range specified like from-to or the complete document specified with the keyword all. Different parts of a document can be separated with commas like seen in the SYNOPSIS. The optional $bookmarksfile must have the following format: <level> "<booomark text" <pagenumber> Root bookmarks have level=0, their childs level=1 and grandchilds level=2 and so on. =head2 isPDF - check a file if has a valid PDF-header isPDF($filename) Checks a file if ith contains a valid PDF-header. =cut