summaryrefslogtreecommitdiffstats
path: root/pdftool.pl
diff options
context:
space:
mode:
Diffstat (limited to 'pdftool.pl')
-rwxr-xr-xpdftool.pl608
1 files changed, 324 insertions, 284 deletions
diff --git a/pdftool.pl b/pdftool.pl
index 01b45a8..49c6e5a 100755
--- a/pdftool.pl
+++ b/pdftool.pl
@@ -15,6 +15,7 @@ use Pod::Usage;
use IPC::Open2;
use IPC::Open3;
use POSIX qw(floor);
+use Error qw(:try);
use strict;
@@ -289,6 +290,7 @@ map {&topoints ($_)} ( \$outwidth, \$outheight,
die "Margins are too big" if $outwidth <= $margin*2 or $outheight <= $margin*2;
+
#
# Check options
#
@@ -299,6 +301,7 @@ die "Bad nup: `$nup'" if
defined $nup && not ($nup =~ /^\d+$/ && $nup > 0);
+
#
# Open input and output files
#
@@ -329,9 +332,9 @@ if (defined $outfile && $outfile ne "-") {
# Detect filetype
#
# To avoid to seek into FIN, it gonna be copied from WRITE to READ in
-# background, once the filetype has been read
+# the background, once the filetype has been read
-# TODO: read specification to detect filetype properly
+# TODO: read specifications, to properly detect the filetype
my $filetype;
pipe *READ, *WRITE or die "Can't pipe: $!";
while (not (defined $filetype) && defined (my $l = <FIN>)) {
@@ -371,305 +374,313 @@ my @auxfiles;
# Pids, to waid for
my @pids;
+# Return value
+my $return = 0;
+
+try {
+ &pdftops();
+
+ &psselect() if defined $select;
+
+ my @bbox = &psbbox();
+
+ &psbook() if defined $book;
+
+ my ($landscape,$rotate) = &psnup (@bbox);
+
+ &pstopdf ($landscape,$rotate);
+}
+catch Error with {
-#
-# Conversion from PDF to PS, if necessary
-#
-my @cmd;
-if ($filetype eq "PDF") {
- unless (defined $infile && $inseek) {
- # Need to copy the whole input to an auxiliary file, since
- # conversion from PDF to PS requires random access to the data
+ # Print the error message
+ print LOG shift;
- $infile = "$tmpdir/pdftool-stdin-$$" . lc ".$filetype";
+ # Kill all the running childrens
+ kill 15, map {$$_[0]} @pids;
- open FINAUX, '>', "$infile"
- or die "Can't write into `$infile': $!";
- push @auxfiles, "$infile";
+ $return = 1;
+}
+
+finally {
+
+ # Avoid zombies
+ map { my ($pid, @cmd) = @$_;
+ my ($r,$v) = (waitpid ($pid, 0), $?);
+ warn "Can't run `" . &printcmd (@cmd) . "'"
+ if ($r != -1 and $v >> 8);
+ } @pids;
+
+ # Close opened file handles
+ map { close $_ or die "Can't close: $!" }
+ ( *READ, *FIN, *FOUT );
+
+ # Delete auxiliary files
+ unlink @auxfiles;
+
+ exit $return;
+};
+
+# Useless, but Perl doesn't see that this filehandle is used more than
+# one time (and even automatically closed by `open3')
+close GSIN;
- # cat > $infile
- while (<FIN>) {
- print FINAUX or die "Can't print: $!";
- }
- close FINAUX;
- }
- my ($first, $last);
- # pdftops doesn't provide any way to have page numbers relative to
- # the end of the document, hence there is no detection of the
- # smallest interval if $select contains `_'
- if (defined $select && not $select =~ /_/) {
- # Convert to PS only the pages we are interested in
- ($first, $last) = (1<<16,-(1<<16));
- for (split /,/, $select) {
- $_ =~ /^(\d*)(-?)(\d*)$/;
- my ($rmin,$sep,$rmax) = ($1,$2,$3);
- undef $first if $sep && not $rmin;
- undef $last if $sep && not $rmax;
- if ($rmin) {
- $first = $rmin if defined $first && $rmin < $first;
- $last = $rmin if defined $last && $rmin > $last;
- }
- if ($rmax) {
- $first = $rmax if defined $first && $rmax < $first;
- $last = $rmax if defined $last && $rmax > $last;
- }
- }
- # Calculate the new page range
- my @newselect;
- for (split /,/, $select) {
- $_ =~ /^(\d*)(-?)(\d*)$/;
- my ($rmin,$sep,$rmax) = ($1,$2,$3);
- if (defined $first) {
- $rmin -= $first-1 if $rmin;
- $rmax -= $first-1 if $rmax;
+# =========================================================
+
+
+
+#
+# Conversion from PDF to PS, if necessary
+# Reads from FIN, writes to IN
+#
+sub pdftops {
+
+ if ($filetype eq "PDF") {
+ unless (defined $infile && $inseek) {
+ # Need to copy the whole input to an auxiliary file, since
+ # conversion from PDF to PS requires random access to the data
+
+ $infile = "$tmpdir/pdftool-stdin-$$." . lc $filetype;
+
+ open FINAUX, '>', $infile
+ or die "Can't write into `$infile': $!";
+ push @auxfiles, $infile;
+
+ # cat > $infile
+ while (<FIN>) {
+ print FINAUX or die "Can't print: $!";
}
- push @newselect, "$rmin$sep$rmax";
+ close FINAUX;
}
+
+ my ($first, $last);
+ # pdftops doesn't provide any way to have page numbers relative to
+ # the end of the document, hence there is no detection of the
+ # smallest interval if $select contains `_'
+ if (defined $select && not $select =~ /_/) {
+ # Convert to PS only the pages we are interested in
+ ($first, $last) = (1<<16,-(1<<16));
+ for (split /,/, $select) {
+ $_ =~ /^(\d*)(-?)(\d*)$/;
+ my ($rmin,$sep,$rmax) = ($1,$2,$3);
+ undef $first if $sep && not $rmin;
+ undef $last if $sep && not $rmax;
+ if ($rmin) {
+ $first = $rmin if defined $first && $rmin < $first;
+ $last = $rmin if defined $last && $rmin > $last;
+ }
+ if ($rmax) {
+ $first = $rmax if defined $first && $rmax < $first;
+ $last = $rmax if defined $last && $rmax > $last;
+ }
+ }
+
+ # Calculate the new page range
+ my @newselect;
+ for (split /,/, $select) {
+ $_ =~ /^(\d*)(-?)(\d*)$/;
+ my ($rmin,$sep,$rmax) = ($1,$2,$3);
+ if (defined $first) {
+ $rmin -= $first-1 if $rmin;
+ $rmax -= $first-1 if $rmax;
+ }
+ push @newselect, "$rmin$sep$rmax";
+ }
+
+ $select = join ',', @newselect;
+ }
+
+ # Convert to PS
+ my @cmd = ('pdftops', '-origpagesizes', "$infile", '-');
+ push @cmd, '-f', $first if defined $first;
+ push @cmd, '-l', $last if defined $last;
+ push @cmd, '-q' if defined $quiet;
+ my $pid = open *PSIN, "-|", @cmd
+ or die "Can't run `" . &printcmd (@cmd) . "'";
+ push @pids, [$pid, @cmd];
- $select = join ',', @newselect;
+ } else {
+ open *PSIN, "<&FIN" or die "Can't dup: $!";
}
-
- # Convert to PS
- @cmd = ('pdftops', '-origpagesizes', "$infile", '-');
- push @cmd, '-f', $first if defined $first;
- push @cmd, '-l', $last if defined $last;
- push @cmd, '-q' if defined $quiet;
- my $pid = open *PSIN, "-|", @cmd
- or die "Can't run `" . &printcmd (@cmd) . "'";
- push @pids, [$pid, @cmd];
-} else {
- open *PSIN, "<&FIN" or die "Can't dup: $!";
+ open *IN, "<&PSIN" or die "Can't dup: $!";
}
-open *IN, "<&PSIN" or die "Can't dup: $!";
#
-# Select, if necessary
+# Select some pages in the document
+# Reads/writes from/to IN
#
-if (defined $select) {
- @cmd = ('psselect', $select);
+sub psselect {
+ my @cmd = ('psselect', '-p', $select);
push @cmd, '-q' if defined $quiet;
+
my $pid = open3 "<&IN", *OUT, ">&LOG", @cmd;
push @pids, [$pid, @cmd];
+
open *IN, "<&OUT" or die "Can't dup: $!";
}
#
-# Bounding box
+# Detect / calculate the bounding box
+# Reads/writes from/to IN
#
-my @bbox;
-if (defined $crop) {
- # Calculate the maximal bounding box
-
- unless (seek IN, 0, 1) {
- # The input is not seekable: have to create a seekable auxiliary file
-
- my $auxfile = "$tmpdir/pdftool-stdin-$$.ps";
+sub psbbox {
+ my @bbox;
- open AUXFD, '>', "$auxfile"
- or die "Can't write into `$auxfile': $!";
- push @auxfiles, $auxfile;
-
- # cat > $auxfile
- while (<IN>) {
- print AUXFD or die "Can't print: $!";
+ if (defined $crop) {
+ # Calculate the maximal bounding box
+
+ unless (seek IN, 0, 1) {
+ # The input is not seekable: have to create a seekable auxiliary
+ # file
+
+ my $auxfile = "$tmpdir/pdftool-stdin-$$.ps";
+
+ open AUXFD, '>', "$auxfile"
+ or die "Can't write into `$auxfile': $!";
+ push @auxfiles, $auxfile;
+
+ # cat > $auxfile
+ while (<IN>) {
+ print AUXFD or die "Can't print: $!";
+ }
+ close AUXFD or die "Can't close: $!";
+ close IN or die "Can't close: $!";
+
+ open IN, '<', "$auxfile" or die "Can't read `$auxfile': $!";
}
- close AUXFD or die "Can't close: $!";
- close IN or die "Can't close: $!";
-
- open IN, '<', "$auxfile" or die "Can't read `$auxfile': $!";
- }
-
- # Need to duplicate IN, since it will be closed in the parent process
- open *GSIN, '<&IN';
-
- @cmd = ('gs', '-sDEVICE=bbox', '-dBATCH', '-dNOPAUSE', '-');
- my $pid = open3 "<&GSIN", ">&GSOUT", *GSOUT, @cmd;
-
- my ($p,$c) = (0,0); # Page & character counter
- my ($x0, $y0, $x1, $y1) = (1<<16, 1<<16, -(1<<16), -(1<<16));
- while (<GSOUT>) {
- if ($_ =~ m/^\%\%BoundingBox: (\d+) (\d+) (\d+) (\d+)/) {
- $x0 = $1 if $1 < $x0;
- $y0 = $2 if $2 < $y0;
- $x1 = $3 if $3 > $x1;
- $y1 = $4 if $4 > $y1;
- unless (defined $quiet) {
- my $s = "[" . ++$p . "] ";
- $c += length $s;
- if ($c >= 80) {
- print LOG "\n" or die "Can't close: $!";
- $c = length $s;
+
+ # Need to duplicate IN, since it will be closed in the parent process
+ open *GSIN, '<&IN';
+
+ my @cmd = ('gs', '-sDEVICE=bbox', '-dBATCH', '-dNOPAUSE', '-');
+ my $pid = open3 "<&GSIN", ">&GSOUT", *GSOUT, @cmd;
+
+ my ($p,$c) = (0,0); # Page & character counter
+ my ($x0, $y0, $x1, $y1) = (1<<16, 1<<16, -(1<<16), -(1<<16));
+ while (<GSOUT>) {
+ if ($_ =~ m/^\%\%BoundingBox: (\d+) (\d+) (\d+) (\d+)/) {
+ $x0 = $1 if $1 < $x0;
+ $y0 = $2 if $2 < $y0;
+ $x1 = $3 if $3 > $x1;
+ $y1 = $4 if $4 > $y1;
+ unless (defined $quiet) {
+ my $s = "[" . ++$p . "] ";
+ $c += length $s;
+ if ($c >= 80) {
+ print LOG "\n" or die "Can't close: $!";
+ $c = length $s;
+ }
+ print LOG $s or die "Can't close: $!";
}
- print LOG $s or die "Can't close: $!";
}
}
- }
- close GSOUT or die "Can't close: $!";;
- print LOG "\n" or die "Can't close: $!" unless defined $quiet;
-
- # No zombie processes
- waitpid $pid, 0;
- die "Can't run `" . &printcmd (@cmd) . "'" if $? >> 8;
-
- die "Error when calculating bounding box" if ($x0 >= $x1 || $y0 >= $y1);
- @bbox = ($x0, $y0, $x1, $y1);
-
- # Let's go back to the beginning of the input
- seek IN, 0, 0 or die "$!";
-
-} elsif (defined $inwidth and defined $inheight) {
- @bbox = (0, 0, $inwidth, $inheight);
-} else {
- # Guess page size from the input file
-
- # To avoid to seek into IN, it gonna be copied from WRITE to READ
- # in background, once the Bounding Box has been read
- pipe *READ, *WRITE or die "Can't pipe: $!";
+ close GSOUT or die "Can't close: $!";
+ print LOG "\n" or die "Can't close: $!" unless defined $quiet;
+
+ # No zombie processes
+ waitpid $pid, 0;
+ die "Can't run `" . &printcmd (@cmd) . "'" if $? >> 8;
+
+ die "Error while calculating bounding box"
+ if ($x0 >= $x1 || $y0 >= $y1);
+ @bbox = ($x0, $y0, $x1, $y1);
+
+ # Let's go back to the beginning of the input
+ seek IN, 0, 0 or die "$!";
+
+ } elsif (defined $inwidth and defined $inheight) {
+ @bbox = (0, 0, $inwidth, $inheight);
- while (not (@bbox) && defined (my $l = <IN>)) {
- print WRITE $l or die "Can't close: $!";
- @bbox = ($1, $2, $3, $4)
- if ($l =~ m/^\%\%BoundingBox: (\d+) (\d+) (\d+) (\d+)/);
- }
-
- die "Cannot guess input page size!" unless @bbox;
-
- unless (my $pid = fork) {
- # Child: cat IN > WRITE in background
- die "Can't fork: $!" unless defined $pid;
- close READ or die "Can't close: $!";;
-
- while (<IN>) {
- print WRITE or die "Can't close: $!";
+ } else {
+ # Guess page size from the input file
+
+ # To avoid to seek into IN, it gonna be copied from WRITE to READ
+ # in background, once the Bounding Box has been read
+ pipe *READ, *WRITE or die "Can't pipe: $!";
+
+ while (not (@bbox) && defined (my $l = <IN>)) {
+ print WRITE $l or die "Can't close: $!";
+ @bbox = ($1, $2, $3, $4)
+ if ($l =~ m/^\%\%BoundingBox: (\d+) (\d+) (\d+) (\d+)/);
+ }
+
+ die "Cannot guess input page size!" unless @bbox;
+
+ unless (my $pid = fork) {
+ # Child: cat IN > WRITE in background
+ die "Can't fork: $!" unless defined $pid;
+ close READ or die "Can't close: $!";;
+
+ while (<IN>) {
+ print WRITE or die "Can't close: $!";
+ }
+ exit;
}
- exit;
+ # Parent
+
+ close WRITE or die "Can't close: $!";
+ close IN or die "Can't close: $!";
+
+ open *IN, "<&READ" or die "Can't dup: $!";
}
- # Parent
-
- close WRITE or die "Can't close: $!";
- close IN or die "Can't close: $!";
-
- open *IN, "<&READ" or die "Can't dup: $!";
+ return @bbox;
}
#
# PSBook
+# Reads/writes from/to IN
#
-if (defined $book) {
- @cmd = ('psbook');
+sub psbook {
+ my @cmd = ('psbook');
push @cmd, '-q' if defined $quiet;
my $pid = open3 "<&IN", *OUT, ">&LOG", @cmd;
- open *IN, "<&OUT" or die "Can't dup: $!";
push @pids, [$pid, @cmd];
-}
-
-
-#
-# PSNup (inlined here, to keep track of the possible rotation)
-#
-my $landscape;
-if ((($bbox[2]-$bbox[0] > $bbox[3]-$bbox[1])
- and not ($outwidth-2*$margin > $outheight-2*$margin))
- or
- (defined $screen
- and not ($bbox[2]-$bbox[0] > $bbox[3]-$bbox[1])
- and ($outwidth-2*$margin > $outheight-2*$margin))) {
- ($outheight, $outwidth) = ($outwidth, $outheight);
- $landscape = 1;
-}
-
-my ($horiz, $vert, $rotate, $scale, $hshift, $vshift)
- = &calc_layout ($nup, $border, \@bbox,
- $outwidth-2*$margin, $outheight-2*$margin);
-
-my ($ospecs,$especs) = &calc_specs ($horiz, $vert, $rotate, $scale,
- [$outwidth-2*$margin, $outheight-2*$margin,
- $hshift, $vshift]);
-my $land = ($outwidth > $outheight);
-$land = not $land if ($rotate%2);
-
-my $pagespecs;
-if (defined $screen || not $land) {
- $pagespecs = "$nup:" . join ('+', @$ospecs);
-} else {
- $pagespecs = 2*$nup . ':' . join ('+', @$ospecs) . ',' . join ('+', @$especs);
+ open *IN, "<&OUT" or die "Can't dup: $!";
}
-@cmd = ('pstops', '-w', $bbox[2], '-h', $bbox[3], $pagespecs);
-push @cmd, '-q' if defined $quiet;
-my $pid = open3 "<&IN", *OUT, ">&LOG", @cmd;
-open *IN, "<&OUT" or die "Can't dup: $!";
-push @pids, [$pid, @cmd];
#
-# Final file: Convert back to PDF
+# PSNup (inlined here, to keep track of the possible rotation)
+# Reads/writes from/to IN
#
-my $pagedevice;
-if (defined $screen || $land || $landscape) {
- $rotate = ($rotate+1)%4 if not (defined $screen) and $land;
- $pagedevice = "/Orientation $rotate /PageSize [$outwidth $outheight]";
-} else {
- $pagedevice = "/PageSize [$outwidth $outheight]";
-}
-
-@cmd = ('gs', "-sDEVICE=pdfwrite", "-sOutputFile=%stdout%", "-dBATCH",
- "-dNOPAUSE", "-dAutoRotatePages=/None",
- "-c", "<< $pagedevice >> setpagedevice",
- "-f", "-");
-$pid = open3 "<&IN", ">&FOUT", ">&LOG", @cmd;
-push @pids, [$pid, @cmd];
-
-
-
-# Avoid zombies
-map { my ($pid, @cmd) = @$_;
-# print STDERR "PID: ", $pid, " Cmd: `", &printcmd (@cmd), "'";
- my ($r,$v) = (waitpid ($pid, 0), $?);
- warn "Can't run `" . &printcmd (@cmd) . "'" if ($r != -1 and $v >> 8);
- } @pids;
-
-
-map { close $_ or die "Can't close: $!" }
- ( *READ, *FIN, *FOUT );
-
-
-# Delete auxiliary files
-unlink @auxfiles;
-
-
-
-# Useless, but Perl doesn't see that this filehandle is used more than
-# one time (and even automatically closed by `open3')
-exit;
-close GSIN;
+sub psnup {
+ my @bbox = @_;
+ my ($landscape, $rotate);
+ if ((($bbox[2]-$bbox[0] > $bbox[3]-$bbox[1])
+ and not ($outwidth-2*$margin > $outheight-2*$margin))
+ or
+ (defined $screen
+ and not ($bbox[2]-$bbox[0] > $bbox[3]-$bbox[1])
+ and ($outwidth-2*$margin > $outheight-2*$margin))) {
+ ($outheight, $outwidth) = ($outwidth, $outheight);
+ $landscape = 1;
+ }
-# =========================================================
+
+ #
+ # Finding the best layout is an optimisation problem. We try all of
+ # the combinations of width*height in both normal and rotated form,
+ # and minimise the wasted space.
+ #
-#
-# Finding the best layout is an optimisation problem. We try all of the
-# combinations of width*height in both normal and rotated form, and
-# minimise the wasted space.
-#
-sub calc_layout {
- my ($nup, $border, $bbox, $outwidth, $outheight) = @_;
+ my ($ow,$oh) = ($outwidth-2*$margin, $outheight-2*$margin);
- my ($inwidth, $inheight) = ($bbox[2]-$bbox[0], $bbox[3]-$bbox[1]);
- my ($horiz, $vert, $rotate, $scale, $hshift, $vshift);
+ my ($iw, $ih) = ($bbox[2]-$bbox[0], $bbox[3]-$bbox[1]);
+ my ($horiz, $vert, $scale, $hshift, $vshift);
my $tolerance = 100000; # layout tolerance
my $best = $tolerance;
@@ -677,31 +688,31 @@ sub calc_layout {
for (my $hor = 1; $hor; $hor = &nextdiv($hor, $nup)) {
my $ver = $nup / $hor;
# try normal orientation first
- my $scl = &min ($outheight/($inheight*$ver), $outwidth/($inwidth*$hor));
+ my $scl = &min ($oh/($ih*$ver), $ow/($iw*$hor));
- my $optim = ($outwidth-$scl*$inwidth*$hor)*($outwidth-$scl*$inwidth*$hor)
- + ($outheight-$scl*$inheight*$ver)*($outheight-$scl*$inheight*$ver);
+ my $optim = ($ow-$scl*$iw*$hor) * ($ow-$scl*$iw*$hor)
+ + ($oh-$scl*$ih*$ver) * ($oh-$scl*$ih*$ver);
if ($optim < $best) {
$best = $optim;
# recalculate scale to allow for internal borders
- $scale = &min (($outheight-2*$border*$ver)/($inheight*$ver),
- ($outwidth-2*$border*$hor)/($inwidth*$hor));
- $hshift = ($outwidth/$hor - ($bbox[2]+$bbox[0])*$scale)/2;
- $vshift = ($outheight/$ver - ($bbox[3]+$bbox[1])*$scale)/2;
+ $scale = &min (($oh-2*$border*$ver)/($ih*$ver),
+ ($ow-2*$border*$hor)/($iw*$hor));
+ $hshift = ($ow/$hor - ($bbox[2]+$bbox[0])*$scale)/2;
+ $vshift = ($oh/$ver - ($bbox[3]+$bbox[1])*$scale)/2;
($horiz, $vert) = ($hor, $ver);
$rotate = 0;
}
# try rotated orientation
- $scl = &min ($outheight/($inwidth*$hor), $outwidth/($inheight*$ver));
- $optim = ($outheight-$scl*$inwidth*$hor)*($outheight-$scl*$inwidth*$hor)
- + ($outwidth-$scl*$inheight*$ver)*($outwidth-$scl*$inheight*$ver);
+ $scl = &min ($oh/($iw*$hor), $ow/($ih*$ver));
+ $optim = ($oh-$scl*$iw*$hor) * ($oh-$scl*$iw*$hor)
+ + ($ow-$scl*$ih*$ver) * ($ow-$scl*$ih*$ver);
if ($optim < $best) {
$best = $optim;
# recalculate scale to allow for internal borders
- $scale = &min (($outheight-2*$border*$hor)/($inwidth*$hor),
- ($outwidth-2*$border*$ver)/($inheight*$ver));
- $hshift = ($outwidth/$ver - ($bbox[3]+$bbox[1])*$scale)/2;
- $vshift = ($outheight/$hor - ($bbox[2]+$bbox[0])*$scale)/2;
+ $scale = &min (($oh-2*$border*$hor)/($iw*$hor),
+ ($ow-2*$border*$ver)/($ih*$ver));
+ $hshift = ($ow/$ver - ($bbox[3]+$bbox[1])*$scale)/2;
+ $vshift = ($oh/$hor - ($bbox[2]+$bbox[0])*$scale)/2;
($horiz, $vert) = ($ver, $hor);
$rotate = 3;
}
@@ -710,20 +721,11 @@ sub calc_layout {
# fail if nothing better than worst tolerance was found
die "Can't find acceptable layout for $nup-up" if $best == $tolerance;
- return ($horiz, $vert, $rotate, $scale, $hshift, $vshift);
-}
-
-
-
-#
-# Construct pstops specification list
-#
-sub calc_specs {
- my ($horiz, $vert, $rotate, $scale, $bbox) = @_;
- my ($outwidth, $outheight, $hshift, $vshift) = @$bbox;
+ #
+ # Construct pstops specification list
+ #
my $n = $horiz * $vert;
-
my (@ospecs, @especs); # specs for odd and even pages
for (my $pageno = 0; $pageno < $n; $pageno++) {
@@ -743,7 +745,7 @@ sub calc_specs {
$up = $pageno % $vert;
}
($orot,$erot) = ('L','R');
- $xoff = ($across+1)*$outwidth/$horiz - $hshift;
+ $xoff = ($across+1)*$ow/$horiz - $hshift;
} else {
if (defined $column) {
# column=1; leftright=1; topbottom=1;
@@ -754,19 +756,66 @@ sub calc_specs {
$across = $pageno % $horiz;
$up = $vert-1 - floor($pageno / $horiz);
}
- $xoff = $across*$outwidth/$horiz + $hshift;
+ $xoff = $across*$ow/$horiz + $hshift;
}
- $yoff = $up*$outheight/$vert + $vshift;
+ $yoff = $up*$oh/$vert + $vshift;
push @ospecs, sprintf ("%d%s@%.3f(%.3f,%.3f)",
$pageno, $orot, $scale,
$xoff+$margin, $yoff+$margin);
push @especs, sprintf ("%d%s@%.3f(%.3f,%.3f)",
$n + $pageno, $erot, $scale,
- $outwidth-$xoff+$margin,
- $outheight-$yoff+$margin);
+ $ow-$xoff+$margin, $oh-$yoff+$margin);
}
- return (\@ospecs,\@especs);
+
+ ($ow,$oh) = ($oh,$ow) if $rotate%2;
+
+ my $pagespecs;
+ if (defined $screen || $ow < $oh) {
+ $pagespecs = $nup . ':' . join ('+', @ospecs);
+ } else {
+ $pagespecs = 2*$nup . ':' . join ('+', @ospecs)
+ . ',' . join ('+', @especs);
+ }
+
+ my @cmd = ('pstops', '-w', $bbox[2], '-h', $bbox[3], $pagespecs);
+ push @cmd, '-q' if defined $quiet;
+
+ my $pid = open3 "<&IN", *OUT, ">&LOG", @cmd;
+ push @pids, [$pid, @cmd];
+
+ open *IN, "<&OUT" or die "Can't dup: $!";
+
+ return ($landscape,$rotate);
+}
+
+
+
+#
+# Final file: Convert back to PDF
+# Reads from IN, writes to FOUT
+#
+sub pstopdf {
+ my ($landscape,$rotate) = @_;
+
+ my ($ow,$oh) = ($outwidth,$outheight);
+ ($ow,$oh) = ($oh,$ow) if $rotate%2;
+
+ my $pagedevice;
+ if (defined $screen || $oh < $oh || $landscape) {
+ $rotate = ($rotate+1)%4 if not (defined $screen) and $oh < $ow;
+ $pagedevice = "/Orientation $rotate /PageSize [$outwidth $outheight]";
+ } else {
+ $pagedevice = "/PageSize [$outwidth $outheight]";
+ }
+
+ my @cmd = ('gs', "-sDEVICE=pdfwrite", "-sOutputFile=%stdout%", "-dBATCH",
+ "-dNOPAUSE", "-dAutoRotatePages=/None",
+ "-c", "<< $pagedevice >> setpagedevice",
+ "-f", "-");
+
+ my $pid = open3 "<&IN", ">&FOUT", ">&LOG", @cmd;
+ push @pids, [$pid, @cmd];
}
@@ -835,7 +884,7 @@ sub papersize {
} elsif ($p eq "quarto") {
($$w,$$h) = (610, 780); # 8.5in * 10.83in
} elsif ($p eq "10x14") {
- ($$w,$$h) = ("10in", "14in");
+ ($$w,$$h) = ("10in", "14in");
} else {
die "Unknown paper size: `$p'";
}
@@ -859,8 +908,6 @@ sub printcmd {
join ' ', @cmd;
}
-
-
sub nextdiv {
my ($n, $m) = @_;
while (++$n <= $m) {
@@ -869,15 +916,8 @@ sub nextdiv {
return 0;
}
-
sub min {
my ($n, $m) = @_;
return $n if $n < $m;
return $m;
}
-
-
-sub round {
- return floor ($_[0] + .5);
-}
-