1#! /bin/sh 2eval '(exit $?0)' && eval 'PERL_BADLANG=x;PATH="$PATH:.";export PERL_BADLANG\ 3 PATH;exec perl -x -S -- "$0" ${1+"$@"};#'if 0;eval 'setenv PERL_BADLANG x\ 4;setenv PATH "$PATH":.;exec perl -x -S -- "$0" $argv:q;#'.q 5#!perl -w 6+push@INC,'.';$0=~/(.*)/s;do(index($1,"/")<0?"./$1":$1);die$@if$@__END__+if 0 7;#Don't touch/remove lines 1--7: http://www.inf.bme.hu/~pts/Magic.Perl.Header 8# 9# sam2p_pdf_scale.pl: scale PDF created by sam2p to page size 10# by pts@fazekas.hu at Sat Jun 6 17:16:17 CEST 2009 11# 12# This program is free software; you can redistribute it and/or modify 13# it under the terms of the GNU General Public License as published by 14# the Free Software Foundation; either version 2 of the License, or 15# (at your option) any later version. 16# 17# This program is distributed in the hope that it will be useful, 18# but WITHOUT ANY WARRANTY; without even the implied warranty of 19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20# GNU General Public License for more details. 21# 22# TODO(pts): Rotate the image by 90 degrees if necessary. 23 24use integer; 25use strict; 26die "Usage: $0 <page-width-bp> <page-height-bp> <input.pdf> [<output.pdf>]\n". 27 "This program reads a PDF generated by sam2p, ". 28 "and scales it to page size.\n" if @ARGV != 3 and @ARGV != 4; 29die "page-width not a nonnegative number\n" if $ARGV[0] !~ m@\A[\d.]+\Z(?!\n)@; 30die "page-height not a nonnegative number\n" 31 if $ARGV[1] !~ m@\A[\d.]+\Z(?!\n)@; 32sub float2str($) { 33 no integer; 34 my $F = $_[0] + 0; 35 $F = "$F"; 36 if (index($F, 'e') >= 0) { 37 $F = sprintf("%.20f", $F); 38 $F =~ s@[.]?0+\Z@@; 39 } 40 $F 41} 42#** Desired page size dimensions. Must be integers, measured in bp (inch/72). 43my $dwidth = float2str($ARGV[0]); 44my $dheight = float2str($ARGV[1]); 45my $outfn = @ARGV == 4 ? $ARGV[3] : $ARGV[2]; 46my $F; 47die "cannot open input PDF: $ARGV[2]: $!\n" if !open($F, '<', $ARGV[2]); 48my $S = join('', <$F>); 49die if !close($F); 50die "sam2p PDF syntax error (no cm)\n" if $S!~m@\n((\d+) 0 0 (\d+) 0 0 cm\b)@g; 51my $cm_at = pos($S) - length($1); 52my $cm_size = length($1); 53my $iwidth = $2 + 0; 54my $iheight = $3 + 0; 55die "sam2p PDF image error (empty image)\n" if $iwidth < 0 or $iheight < 0; 56my $rest_at = rindex($S, "\nendstream\n") + 1; 57die "sam2p PDF syntax error (no endstream)\n" if $rest_at <= $cm_at; 58pos($S) = $rest_at; 59die "sam2p PDF syntax error (boxes not found)\n" if 60 $S!~m@(/MediaBox\s*\[0 0 (\d+) (\d+)\]\s*/CropBox\s*\[0 0 (\d+) (\d+)\])@g; 61my $boxes_at = pos($S) - length($1); 62my $boxes_size = length($1); 63die "sam2p PDF syntax error (image size mismatch)\n" if 64 $2 ne $iwidth or $3 ne $iheight or 65 $4 ne $iwidth or $5 ne $iheight; 66my $boxes_new = 67 "/MediaBox[0 0 $dwidth $dheight]\n/CropBox[0 0 $dwidth $dheight]"; 68substr($S, $boxes_at, $boxes_size) = $boxes_new; 69my($cwidth, $cheight); 70my($xshift, $yshift); 71{ no integer; 72 my $aheight = $iheight * $dwidth / $iwidth; 73 my $bwidth = $iwidth * $dheight / $iheight; 74 if ($aheight <= $dheight) { ($cwidth, $cheight) = ($dwidth, $aheight) } 75 else { ($cwidth, $cheight) = ($bwidth, $dheight) } 76 $xshift = ($dwidth - $cwidth) / 2; 77 $yshift = ($dheight - $cheight) / 2; 78} 79my $cm_new = float2str($cwidth)." 0 0 ".float2str($cheight)." ". 80 float2str($xshift)." ".float2str($yshift)." cm"; 81substr($S, $cm_at, $cm_size) = $cm_new; 82pos($S) = 0; 83if ($S =~ m@\n<</Length ((\d+)>>\nstream\nq\n)@g and pos($S) == $cm_at) { 84 substr($S, pos($S) - length($1), length($2)) = 85 sprintf("%".length($2)."d", $2 + length($cm_new) - $cm_size); 86} 87pos($S) = $boxes_at + length($boxes_new) + length($cm_new) - $cm_size; 88die "sam2p PDF syntax error (xref not found)\n" if 89 $S!~m@\sendobj\n(xref\n0 (\d+)\n0000000000 65535 f \n)@g; 90my $xref_at = pos($S) - length($1); 91my $obj_count = $2 - 1; 92my $ofss_at = pos($S); 93for (my $I = 1; $I <= $obj_count; ++$I) { 94 my $xrefe_at = $ofss_at + ($I - 1) * 20; 95 my $xrefe = substr($S, $xrefe_at, 20); 96 die "sam2p PDF syntax error (xref entry $I bad)\n" if 97 $xrefe!~m@\A(\d{10}) 00000 n \n\Z(?!\n)@; 98 my $ofs = $1 + 0; 99 $ofs += ( 100 ($ofs >= $boxes_at) ? length($boxes_new) - $boxes_size + 101 length($cm_new) - $cm_size : 102 ($ofs >= $cm_at) ? length($cm_new) - $cm_size : 0); 103 substr($S, $xrefe_at, 20) = sprintf("%010d 00000 n \n", $ofs); 104} 105pos($S) = $ofss_at + $obj_count * 20; 106die "sam2p PDF syntax error (startxref not found)\n" if 107 $S!~s@\nstartxref\n(\d+)\n@\nstartxref\n$xref_at\n@; 108die "cannot open output PDF: $outfn: $!\n" if !open($F, '>', $outfn); 109die if !print($F $S); 110die if !close($F); 111