public
Last active

create single PDF from many .pod or .pm files

  • Download Gist
multi_pdf.pl
Perl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#!/usr/bin/env perl
use Modern::Perl;
 
BEGIN {
if (@ARGV != 2) {
print STDERR "usage: $0 DIR OUTPUT\n";
exit 1;
}
}
 
{
# a simple class that uses App::pod2pdf to create pdfs containing many pod files
# The hierarchical outline is generated on the fly while traversing directories
 
package MultiPDF;
use Moose;
use Path::Class;
use App::pod2pdf;
 
has parser => (
is => 'ro',
isa => 'App::pod2pdf',
lazy => 1,
default => sub { App::pod2pdf->new },
);
 
has pdf => (
is => 'ro',
isa => 'PDF::API2',
lazy => 1,
builder => '_build_pdf',
);
 
sub _build_pdf {
my $self = shift;
 
$self->parser->{pdf},
}
 
sub process_file {
my $self = shift;
my $file = shift;
 
say "processing file: $file";
 
$self->parser->parse_from_file($file->stringify);
$self->parser->formfeed;
return $self;
}
 
sub process_dir {
my $self = shift;
my $dir = Path::Class::Dir->new(shift);
 
my %structure; # { _outline => PDF::API2::Outline }
 
$dir->recurse(
depthfirst => 1,
callback => sub {
my $file = shift;
 
return if !-f $file || $file->basename !~ m{[.](?:pm|pod) \z}xms;
 
my $nr_pages = $self->pdf->pages;
$self->process_file($file);
 
my $name = $file->basename;
$name =~ s{[.]\w+ \z}{}xms;
 
my $tree = \%structure;
my $outline = $structure{_outline} ||= $self->pdf->outlines->outline;
 
foreach my $part (grep { $_ ne '.' } $file->relative($dir)->dir->dir_list, $name) {
$tree = $tree->{$part} ||= { _outline => $outline->outline };
$outline = $tree->{_outline};
$outline->title($part);
}
$outline->dest($self->pdf->openpage($nr_pages));
}
);
return $self;
}
 
sub print {
my $self = shift;
 
$self->parser->output;
}
 
sub save_as {
my $self = shift;
my $path = shift;
 
$self->pdf->saveas($path);
}
}
 
MultiPDF->new
->process_dir($ARGV[0])
->save_as($ARGV[1]);

Hi Wolfgang,

I like the idea. I got this running on v5.10.1 by dropping the '2012' argument to Modern::Perl and it generates pages for each file found, but did not generate an outline. I don't know anything about PDF::API2 to know why this is the case.

For usability I also added the following (inside a BEGIN block because I hate waiting for Moose to start up when arguments are missing):

BEGIN {
    unless @ARGV == 2 {
        print STDERR "usage: $0 DIR OUTPUT\n";
        exit 1;
    }
}

And this at the bottom:

MultiPDF->new
    ->process_dir($ARGV[0])
    ->save_as($ARGV[1]);

Regards,
Mark.

Mark,

you are absolutely right. There is no need to force usage of Perl 5.14. There are more things to improve like handling .pm versus .pod files, omitting files without any documentation and maybe much more cases not handled right now. But for a first try I think it is not that bad.

I will try to operate with different versions of Perl in order to find out why outlines seem to work unreliably. The outline handling in PDF::API2 by itself is available since 2005 if I correctly read the 'Changes' file. So it looks like I did not handle this part right.

Thanks for your feedback.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.