summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/pdfcrop
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-09-08 23:09:42 +0000
committerKarl Berry <karl@freefriends.org>2010-09-08 23:09:42 +0000
commit09c06007c38c5bd1bfe5a3b367fe3a273277da8d (patch)
tree6eec50f8ad3b635e9d549d2ddd061baba211af86 /Master/texmf-dist/scripts/pdfcrop
parentee2de76f7db0b19a657a7f3b9ba8768bc8e69e37 (diff)
pdfcrop 1.29 (26aug10ff.)
git-svn-id: svn://tug.org/texlive/trunk@19616 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/pdfcrop')
-rwxr-xr-xMaster/texmf-dist/scripts/pdfcrop/pdfcrop.pl308
1 files changed, 255 insertions, 53 deletions
diff --git a/Master/texmf-dist/scripts/pdfcrop/pdfcrop.pl b/Master/texmf-dist/scripts/pdfcrop/pdfcrop.pl
index 5855eb0849e..c96b2d92742 100755
--- a/Master/texmf-dist/scripts/pdfcrop/pdfcrop.pl
+++ b/Master/texmf-dist/scripts/pdfcrop/pdfcrop.pl
@@ -1,5 +1,4 @@
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' && eval 'exec perl -S $0 $argv:q'
- if 0;
+#!/usr/bin/env perl
use strict;
$^W=1; # turn warning on
#
@@ -22,8 +21,8 @@ $^W=1; # turn warning on
#
my $file = "pdfcrop.pl";
my $program = uc($&) if $file =~ /^\w+/;
-my $version = "1.23";
-my $date = "2010/01/09";
+my $version = "1.29";
+my $date = "2010/09/06";
my $author = "Heiko Oberdiek";
my $copyright = "Copyright (c) 2002-2010 by $author.";
#
@@ -69,6 +68,26 @@ my $copyright = "Copyright (c) 2002-2010 by $author.";
# 2009/12/29 v1.22: * Syntax description for option --bbox fixed
# (Lukas Prochazka).
# 2010/01/09 v1.23: * Options --bbox-odd and -bbox-even added.
+# 2010/08/16 v1.24: * Workaround added for buggy ghostscript ports
+# that print the BoundingBox data twice.
+# 2010/08/26 v1.25: * Fix for the case that the PDF file contains
+# an entry /CropBox different to /MediaBox.
+# * \pageinclude implemented for XeTeX.
+# * XeTeX: --clip does not die, but this option
+# is ignored, because XeTeX always clip.
+# 2010/08/26 v1.26: * XeTeX's \XeTeXpdffile expects keyword
+# `media', not `mediabox'.
+# * New option --pdfversion.
+# Default is `auto' that means the PDF version
+# is inherited from the input file. Before
+# pdfcrop has used the TeX engine's default.
+# * Option --luatex fixed (extra empty page at end).
+# 2010/09/03 v1.27: * Workaround of v1.24 fixed.
+# 2010/09/06 v1.28: * The Windows registry is searched if Ghostscript
+# is not found via PATH.
+# * Windows only: support of spaces in command
+# names in unrestricted mode.
+# 2010/09/06 v1.29: * Find the latest Ghostscript version in registry.
### program identification
my $title = "$program $version, $date - $copyright\n";
@@ -79,6 +98,11 @@ my $Error = "!!! Error:"; # error prefix
### make ENV safer
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
+# Windows detection (no SIGHUP)
+my $Win = 0;
+$Win = 1 if $^O =~ /mswin32/i;
+$Win = 1 if $^O =~ /cygwin/i;
+
### string constants for Ghostscript run
# get Ghostscript command name
$::opt_gscmd = '';
@@ -126,6 +150,9 @@ sub find_ghostscript () {
}
last if $found;
}
+ if (not $found and $Win) {
+ $found = SearchRegistry();
+ }
if ($found) {
print "* Autodetected ghostscript command: $::opt_gscmd\n" if $::opt_debug;
}
@@ -135,10 +162,83 @@ sub find_ghostscript () {
}
}
-# Windows detection (no SIGHUP)
-my $Win = 0;
-$Win = 1 if $^O =~ /mswin32/i;
-$Win = 1 if $^O =~ /cygwin/i;
+sub SearchRegistry () {
+ my $found = 0;
+ eval 'use Win32::TieRegistry qw|KEY_READ REG_SZ|;';
+ if ($@) {
+ if ($::opt_debug) {
+ print "* Registry lookup for Ghostscript failed:\n";
+ my $msg = $@;
+ $msg =~ s/\s+$//;
+ foreach (split /\r?\n/, $msg) {
+ print " $_\n";
+ }
+ }
+ return $found;
+ }
+ my $open_params = {Access => KEY_READ(), Delimiter => '/'};
+ my $key_name_software = 'HKEY_LOCAL_MACHINE/SOFTWARE/';
+ my $current_key = $key_name_software;
+ my $software = new Win32::TieRegistry $current_key, $open_params;
+ if (not $software) {
+ print "* Cannot find or access registry key `$current_key'!\n"
+ if $::opt_verbose;
+ return $found;
+ }
+ print "* Search registry at `$current_key'.\n" if $::opt_debug;
+ my %list;
+ foreach my $key_name_gs (grep /Ghostscript/i, $software->SubKeyNames()) {
+ $current_key = "$key_name_software$key_name_gs/";
+ print "* Registry entry found: $current_key\n" if $::opt_debug;
+ my $key_gs = $software->Open($key_name_gs, $open_params);
+ if (not $key_gs) {
+ print "* Cannot open registry key `$current_key'!\n" if $::opt_debug;
+ next;
+ }
+ foreach my $key_name_version ($key_gs->SubKeyNames()) {
+ $current_key = "$key_name_software$key_name_gs/$key_name_version/";
+ print "* Registry entry found: $current_key\n" if $::opt_debug;
+ if (not $key_name_version =~ /^(\d+)\.(\d+)$/) {
+ print " The sub key is not a version number!\n" if $::opt_debug;
+ next;
+ }
+ my $version_main = $1;
+ my $version_sub = $2;
+ $current_key = "$key_name_software$key_name_gs/$key_name_version/";
+ my $key_version = $key_gs->Open($key_name_version, $open_params);
+ if (not $key_version) {
+ print "* Cannot open registry key `$current_key'!\n" if $::opt_debug;
+ next;
+ }
+ $key_version->FixSzNulls(1);
+ my ($value, $type) = $key_version->GetValue('GS_DLL');
+ if ($value and $type == REG_SZ()) {
+ print " GS_DLL = $value\n" if $::opt_debug;
+ $value =~ s|([\\/])([^\\/]+\.dll)$|$1gswin32c.exe|i;
+ if (-f $value) {
+ print " EXE found: $value\n" if $::opt_debug;
+ }
+ else {
+ print " EXE not found!\n" if $::opt_debug;
+ next;
+ }
+ my $sortkey = sprintf '%02d.%03d %s',
+ $version_main, $version_sub, $key_name_gs;
+ $list{$sortkey} = $value;
+ }
+ else {
+ print " Missing key `GS_DLL' with type `REG_SZ'!\n" if $::opt_debug;
+ }
+ }
+ }
+ foreach my $entry (reverse sort keys %list) {
+ $::opt_gscmd = $list{$entry};
+ print "* Found (via registry): $::opt_gscmd\n" if $::opt_debug;
+ $found = 1;
+ last;
+ }
+ return $found;
+}
# restricted mode
my $restricted = 0;
@@ -191,6 +291,7 @@ $::opt_bbox = "";
$::opt_bbox_odd = "";
$::opt_bbox_even = "";
$::opt_initex = 0;
+$::opt_pdfversion = "auto";
sub usage ($) {
my $ret = shift;
@@ -198,38 +299,46 @@ sub usage ($) {
my $usage = <<"END_OF_USAGE";
${title}Syntax: \L$program\E [options] <input[.pdf]> [output file]
Function: Margins are calculated and removed for each page in the file.
-Options: (defaults:)
+Options: (defaults:)
--help print usage
--version print version number
- --(no)verbose verbose printing ($bool[$::opt_verbose])
- --(no)debug debug informations ($bool[$::opt_debug])
- --gscmd <name> call of ghostscript ($::opt_gscmd)
+ --(no)verbose verbose printing ($bool[$::opt_verbose])
+ --(no)debug debug informations ($bool[$::opt_debug])
+ --gscmd <name> call of ghostscript ($::opt_gscmd)
--pdftex | --xetex | --luatex
- use pdfTeX | use XeTeX | use LuaTeX ($::opt_tex)
- --pdftexcmd <name> call of pdfTeX ($::opt_pdftexcmd)
- --xetexcmd <name> call of XeTeX ($::opt_xetexcmd)
- --luatexcmd <name> call of LuaTeX ($::opt_luatexcmd)
- --margins "<left> <top> <right> <bottom>" ($::opt_margins)
+ use pdfTeX | use XeTeX | use LuaTeX ($::opt_tex)
+ --pdftexcmd <name> call of pdfTeX ($::opt_pdftexcmd)
+ --xetexcmd <name> call of XeTeX ($::opt_xetexcmd)
+ --luatexcmd <name> call of LuaTeX ($::opt_luatexcmd)
+ --margins "<left> <top> <right> <bottom>" ($::opt_margins)
add extra margins, unit is bp. If only one number is
given, then it is used for all margins, in the case
of two numbers they are also used for right and bottom.
- --(no)clip clipping support, if margins are set ($bool[$::opt_clip])
+ --(no)clip clipping support, if margins are set ($bool[$::opt_clip])
(not available for --xetex)
- --(no)hires using `%%HiResBoundingBox' ($bool[$::opt_hires])
+ --(no)hires using `%%HiResBoundingBox' ($bool[$::opt_hires])
instead of `%%BoundingBox'
- --(no)ini use iniTeX variant of the TeX compiler ($bool[$::opt_initex])
+ --(no)ini use iniTeX variant of the TeX compiler ($bool[$::opt_initex])
Expert options:
- --restricted turn on restricted mode ($bool[$restricted])
+ --restricted turn on restricted mode ($bool[$restricted])
--papersize <foo> parameter for gs's -sPAPERSIZE=<foo>,
- use only with older gs versions <7.32 ($::opt_papersize)
- --resolution <xres>x<yres> ()
+ use only with older gs versions <7.32 ($::opt_papersize)
+ --resolution <xres>x<yres> ($::opt_resolution)
--resolution <res> pass argument to ghostscript's option -r
Example: --resolution 72
- --bbox "<left> <bottom> <right> <top>" ()
+ --bbox "<left> <bottom> <right> <top>" ($::opt_bbox)
override bounding box found by ghostscript
with origin at the lower left corner
- --bbox-odd, --bbox-even ()
- Same as --bbox, but for odd, even pages only
+ --bbox-odd Same as --bbox, but for odd pages only ($::opt_bbox_odd)
+ --bbox-even Same as --bbox, but for even pages only ($::opt_bbox_even)
+ --pdfversion <1.x> | auto | none
+ Set the PDF version to 1.x, 1 < x < 8.
+ If `auto' is given as value, then the
+ PDF version is taken from the header
+ of the input PDF file.
+ An empty value or `none' uses the
+ default of the TeX engine. ($::opt_pdfversion)
+
Examples:
\L$program\E --margins 10 input.pdf output.pdf
\L$program\E --margins '5 10 5 20' --clip input.pdf output.pdf
@@ -272,6 +381,7 @@ GetOptions(
"bbox-odd=s" => \$::opt_bbox_odd,
"bbox-even=s" => \$::opt_bbox_even,
"restricted" => sub { $restricted = 1; },
+ "pdfversion=s" => \$::opt_pdfversion,
) or usage(1);
!$::opt_help or usage(0);
@@ -286,6 +396,15 @@ $::opt_verbose = 1 if $::opt_debug;
print $title;
+print "* Restricted mode: ", ($restricted ? "enabled" : "disabled"), "\n"
+ if $::opt_debug;
+
+$::opt_pdfversion =~ /^(|none|auto|1\.([2-7]))$/
+ or die "!!! Error: Invalid value `$::opt_pdfversion' for option `--pdfversion'!\n";
+print "* Option `pdfversion': $::opt_pdfversion\n" if $::opt_debug;
+$::opt_pdfversion = $2 if $2;
+$::opt_pdfversion = '' if $::opt_pdfversion eq 'none';
+
find_ghostscript();
if ($::opt_bbox) {
@@ -340,6 +459,24 @@ if (! -f $inputfile) {
print "* Input file: $inputfile\n" if $::opt_debug;
+if ($::opt_pdfversion eq 'auto') {
+ open(IN, '<', $inputfile) or die "!!! Error: Cannot open `$inputfile'!\n";
+ my $buf;
+ read(IN, $buf, 1024) or die "!!! Error: Cannot read the header of `$inputfile' failed!\n";
+ close(IN);
+ if ($buf =~ /%PDF-1.([0-7])\s/) {
+ $::opt_pdfversion = $1;
+ print "* PDF header: %PDF-1.$::opt_pdfversion\n" if $::opt_verbose;
+ $::opt_pdfversion = 2 if $::opt_pdfversion < 2;
+ }
+ else {
+ die "!!! Error: Cannot find PDF header of `$inputfile'!\n";
+ }
+}
+print '* Using PDF minor version: ',
+ ($::opt_pdfversion ? $::opt_pdfversion : "engine's default"),
+ "\n" if $::opt_debug;
+
### output file
if (@ARGV) {
$outputfile = shift @ARGV;
@@ -352,10 +489,6 @@ else {
print "* Output file: $outputfile\n" if $::opt_debug;
-if (($::opt_tex eq 'xetex') && $::opt_clip) {
- die "$Error No clipping support for XeTeX!\n";
-}
-
### margins
my ($llx, $lly, $urx, $ury) = (0, 0, 0, 0);
if ($::opt_margins =~
@@ -401,16 +534,25 @@ my %cmd = (
'xetexcmd' => \$::opt_xetexcmd
);
foreach my $cmd (keys %cmd) {
- my $val = ${$cmd{$cmd}};
+ my $cmd_ref = $cmd{$cmd};
+ $$cmd_ref =~ s/^\s+//;
+ $$cmd_ref =~ s/\s+$//;
+ my $val = $$cmd_ref;
next unless $val;
- $val =~ s/^\s+//;
- $val =~ s/\s+$//;
next unless $val;
if ($val =~ /`/) {
die "$Error Forbidden backtick for option `--$cmd' ($val)!\n";
}
if ($val =~ /\s/) {
- die "$Error Forbidden whitespace for option `--$cmd' ($val)!\n";
+ my $err = 0;
+ if ($restricted or not $Win) {
+ $err = 1;
+ }
+ else {
+ $err = 1 if $val =~ /\.exe.*\s/i;
+ $err = 1 if $val =~ /\s[-\/]/;
+ }
+ die "$Error Forbidden whitespace for option `--$cmd' ($val)!\n" if $err;
}
}
if ($restricted) {
@@ -429,6 +571,9 @@ if ($restricted) {
or die "$Error: Invalid Ghostscript program name in restricted mode!\n";
}
}
+if ($Win and $::opt_gscmd =~ /\s/) {
+ $::opt_gscmd = "\"$::opt_gscmd\"";
+}
### cleanup system
my @unlink_files = ();
@@ -532,24 +677,26 @@ if ($::opt_tex eq 'luatex') {
'pdfmapfile',
'pdfximage',
'pdflastximage',
- 'pdfrefximage'
+ 'pdfrefximage',
+ 'pdfminorversion',
})
tex.print('1')
end
}%
\ifx\TESTluatexversion\UnDeFiNeD\else 1\fi %
=11 %
- \global\let\luatexversion\luatexversion
- \global\let\pdfoutput\TESTpdfoutput
- \global\let\pdfcompresslevel\TESTpdfcompresslevel
- \global\let\pdfhorigin\TESTpdfhorigin
- \global\let\pdfvorigin\TESTpdfvorigin
- \global\let\pdfpagewidth\TESTpdfpagewidth
- \global\let\pdfpageheight\TESTpdfpageheight
- \global\let\pdfmapfile\TESTpdfmapfile
- \global\let\pdfximage\TESTpdfximage
- \global\let\pdflastximage\TESTpdflastximage
- \global\let\pdfrefximage\TESTpdfrefximage
+ \global\let\luatexversion\luatexversion %
+ \global\let\pdfoutput\TESTpdfoutput %
+ \global\let\pdfcompresslevel\TESTpdfcompresslevel %
+ \global\let\pdfhorigin\TESTpdfhorigin %
+ \global\let\pdfvorigin\TESTpdfvorigin %
+ \global\let\pdfpagewidth\TESTpdfpagewidth %
+ \global\let\pdfpageheight\TESTpdfpageheight %
+ \global\let\pdfmapfile\TESTpdfmapfile %
+ \global\let\pdfximage\TESTpdfximage %
+ \global\let\pdflastximage\TESTpdflastximage %
+ \global\let\pdfrefximage\TESTpdfrefximage %
+ \global\let\pdfminorversion\TESTpdfminorversion %
\else %
\errmessage{%
Missing \string\luatexversion %
@@ -564,10 +711,20 @@ if ($::opt_tex eq 'pdftex' or $::opt_tex eq 'luatex') {
\pdfoutput=1 %
\pdfcompresslevel=9 %
\csname pdfmapfile\endcsname{}
+\def\setpdfversion#1{%
+ \ifx\pdfminorversion\undefined
+ \ifx\pdfoptionpdfminorversion\undefined
+ \else
+ \pdfoptionpdfminorversion=#1\relax
+ \fi
+ \else
+ \pdfminorversion=#1\relax
+ \fi
+}
\def\page #1 [#2 #3 #4 #5]{%
\count0=#1\relax
\setbox0=\hbox{%
- \pdfximage page #1{\pdffile}%
+ \pdfximage page #1 mediabox{\pdffile}%
\pdfrefximage\pdflastximage
}%
\pdfhorigin=-#2bp\relax
@@ -585,7 +742,7 @@ if ($::opt_tex eq 'pdftex' or $::opt_tex eq 'luatex') {
\edef\imagewidth{\the\dimen0}%
\dimen0=#5bp\relax \advance\dimen0 by -#3bp\relax
\edef\imageheight{\the\dimen0}%
- \pdfximage page #1{\pdffile}%
+ \pdfximage page #1 mediabox{\pdffile}%
\setbox0=\hbox{%
\kern -#2bp\relax
\lower #3bp\hbox{\pdfrefximage\pdflastximage}%
@@ -607,7 +764,7 @@ if ($::opt_tex eq 'pdftex' or $::opt_tex eq 'luatex') {
\def\pageinclude#1{%
\pdfhorigin=0pt\relax
\pdfvorigin=0pt\relax
- \pdfximage page #1{\pdffile}%
+ \pdfximage page #1 mediabox{\pdffile}%
\setbox0=\hbox{\pdfrefximage\pdflastximage}%
\pdfpagewidth=\wd0\relax
\pdfpageheight=\ht0\relax
@@ -617,6 +774,7 @@ if ($::opt_tex eq 'pdftex' or $::opt_tex eq 'luatex') {
}%
}
END_TMP_HEAD
+ print TMP "\\setpdfversion{$::opt_pdfversion}\n" if $::opt_pdfversion;
}
else { # XeTeX
print TMP <<'END_TMP_HEAD';
@@ -626,7 +784,7 @@ else { # XeTeX
\def\page #1 [#2 #3 #4 #5]{%
\count0=#1\relax
\setbox0=\hbox{%
- \XeTeXpdffile "\pdffile" page #1%
+ \XeTeXpdffile "\pdffile" page #1 media\relax
}%
\pdfpagewidth=#4bp\relax
\advance\pdfpagewidth by -#2bp\relax
@@ -643,6 +801,25 @@ else { # XeTeX
}%
}%
}
+\def\pageclip #1 [#2 #3 #4 #5][#6 #7 #8 #9]{%
+ \page {#1} [#2 #3 #4 #5]%
+}
+\def\pageinclude#1{%
+ \setbox0=\hbox{%
+ \XeTeXpdffile "\pdffile" page #1 media\relax
+ }%
+ \pdfpagewidth=\wd0\relax
+ \pdfpageheight=\ht0\relax
+ \advance\pdfpageheight by \dp0\relax
+ \shipout\hbox{%
+ \kern-1in%
+ \vbox{%
+ \kern-1in%
+ \ht0=\pdfpageheight
+ \box0 %
+ }%
+ }%
+}
END_TMP_HEAD
}
@@ -696,10 +873,19 @@ $gs_pipe .= "|";
open(GS, $gs_pipe) or
die "$Error Cannot call ghostscript ($::opt_gscmd)!\n";
my $bb = ($::opt_hires) ? "%%HiResBoundingBox" : "%%BoundingBox";
+my $previous_line = 'Previous line';
+# Ghostscript workaround for buggy ports that prints
+# the bounding box data twice on STDERR.
while (<GS>) {
print $_ if $::opt_verbose;
- next unless
- /^$bb:\s*(-?[\.\d]+) (-?[\.\d]+) (-?[\.\d]+) (-?[\.\d]+)/o;
+ if (/^$bb:\s*(-?[\.\d]+) (-?[\.\d]+) (-?[\.\d]+) (-?[\.\d]+)/o) {
+ }
+ else {
+ $previous_line = $_;
+ next;
+ }
+ next if $previous_line eq $_;
+ $previous_line = $_;
$page++;
@bbox = getbbox($page, $1, $2, $3, $4);
@@ -775,13 +961,14 @@ if ($::opt_tex eq 'pdftex') {
$texname = 'pdfTeX';
}
elsif ($::opt_tex eq 'luatex') {
- $cmd =$::opt_luatexcmd;
+ $cmd = $::opt_luatexcmd;
$texname = 'LuaTeX';
}
else {
$cmd = $::opt_xetexcmd;
$texname = 'XeTeX';
}
+$cmd = "\"$cmd\"" if $Win and $cmd =~ /\s/;
$cmd .= ' -no-shell-escape';
if ($::opt_initex) {
$cmd .= ' --ini --etex';
@@ -804,6 +991,21 @@ if ($?) {
die "$Error $texname run failed!\n";
}
+### Check pdf version of temp file
+if ($::opt_pdfversion) {
+ open(PDF, '+<', "$tmp.pdf") or die "!!! Error: Cannot open `$tmp.pdf'!\n";
+ my $header;
+ read PDF, $header, 9 or die "!!! Error: Cannot read header of `$tmp.pdf'!\n";
+ $header =~ /^%PDF-1\.(\d)\s$/ or die "!!! Error: Cannot find header of `$tmp.pdf'!\n";
+ if ($1 ne $::opt_pdfversion) {
+ seek PDF, 7, 0 or die "!!! Error: Cannot seek in `$tmp.pdf'!\n";
+ print PDF $::opt_pdfversion or die "!!! Error: Cannot write in `$tmp.pdf'!\n";
+ print "* PDF version correction in output file: 1.$::opt_pdfversion\n"
+ if $::opt_debug;
+ }
+ close(PDF);
+}
+
### Move temp file to output
if (!rename("$tmp.pdf", $outputfile)) {
use File::Copy;