Source

script_print / print_in_parts.pl

Full commit
#!/usr/bin/perl -w
#

=head1 print_in_parts.pl

Print given .pdf file in pieces, 20 pages each, waiting for the
end of earlier part before sending next one.

Requires modern Linux printing tools (lp and lpstat, I test the script
on Ubuntu with CUPS), uses default printer configured on the machine,
claims A4 page size, and requests two-side printing.  Those options
(printer, page size, duplex) can be fine-tuned if necessary by editing
printing command in the script code.

Requires also perl plus Moose, MooseX::Getopt, and PDF::API2 modules.

Simplest usage (print whole bigfile.pdf in chunks of 20 pages):

    perl print_in_parts.pl --file=bigfile.pdf

More complicated usage:

    perl print_in_parts.pl --file=bigfile.pdf --since=41 --split=10

(print, in chunks of 10 pages, part of bigfile.pdf starting from page 41)

=cut

package PrintMe;
use Moose;
use namespace::autoclean;
use PDF::API2;
use List::Util qw(min);
use autodie qw(:all);
with 'MooseX::Getopt';

has 'file' => (is => 'ro', isa=>'Str', required => 1,
               documentation => 'File to print (something.pdf)');
has 'split' => (is => 'ro', isa=>'Int', required => 1,
                default => sub { 20 },
                documentation => 'Split every ... pages (default: 20)');
has 'since' => (is => 'ro', isa=>'Int', required => 1,
                default => sub { 1 },
                documentation => 'Start from page ... (default: 1)');
has 'verbose' => (is => 'ro', isa=>'Bool', required => 0, default => 0,
                  documentation => "Be more verbose");

sub run {
    my $self = shift;

    unless($self->file =~ /\.pdf$/i) {
        die "Only .pdf files are currently handled.\nNote: support for .ps could be easily added if useful.\n";
    }

    # TODO: handle also .ps files. For those, pages count can be calculated
    # using: 
    #   gs -q -dBATCH -sDEVICE=nullpage source.ps | grep -c showpage
    # or (faster but can fail for uglier files)  directly by counting 
    #   %%Page:
    # lines

    my $doc = PDF::API2->open($self->file);
    my $pages_count = $doc->pages;
    undef $doc;
    my $start = $self->since;
    while($start <= $pages_count) {
        my $end = min($start + $self->split - 1, $pages_count);
        $self->print_part($self->file, $start, $end);
        $start = $end + 1;
    }
}

sub print_part {
    my ($self, $filename, $since, $to) = @_;

    $self->wait_for_inactive_printer;

    print "Printing pages $since-$to from $filename\n";

    # TODO: make printer, media and duplex to be script options

    my $command = "lp -o media=a4 -o sides=two-sided-long-edge -P '$since-$to' '$filename'";
    print "Trying:\n$command\n" if $self->verbose;
    system($command);

}

sub wait_for_inactive_printer {
    my $self = shift;

    print "Waiting for printer inactivity...";

    while($self->printer_active()) {
        sleep(1);
    }

    print ".. printer ready\n" if $self->verbose;
}

# Checking whether anything happens on default printer
sub printer_active {
    my $self = shift;

    # TODO: make printer an option

    print "Checking lpstat...\n" if $self->verbose;
    my $active = 0;
    open(my $fd, "lpstat |");
    while(<$fd>) {
        unless(/^$/) {
            $active = 1;
            print "    $_" if $self->verbose;
        }
    }
    close($fd);

    return $active;
}

###########################################################################
# Main
###########################################################################

package main;

my $app = PrintMe->new_with_options();
$app->run();