/usr/bin/rewritepdf is in libcam-pdf-perl 1.60-3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | #!/usr/bin/perl -w
package main;
use warnings;
use strict;
use CAM::PDF;
use Getopt::Long;
use Pod::Usage;
our $VERSION = '1.60';
my %opts = (
decode => 0,
cleanse => 0,
clearannots => 0,
filters => [],
newprefs => 0,
prefs => [],
newpass => 0,
pass => [],
decrypt => 0,
newversion => 0,
verbose => 0,
order => 0,
help => 0,
version => 0,
# temporary variables
looking => q{},
state => 0,
otherargs => [],
);
Getopt::Long::Configure('bundling');
GetOptions('1|2|3|4|5|6|7|8|9' => sub {$opts{newversion} = '1'.$_[0]},
'c|cleanse' => \$opts{cleanse},
'd|decode' => \$opts{decode},
'f|filter=s' => \@{$opts{filters}},
'C|clearannots' => \$opts{clearannots},
'X|decrypt' => \$opts{decrypt},
'p|pass' => sub { @{$opts{pass}}=(); $opts{looking}='pass'; $opts{state}=2; $opts{newpass}=1; },
'P|prefs' => sub { @{$opts{prefs}}=(); $opts{looking}='prefs'; $opts{state}=4; $opts{newprefs}=1; },
'v|verbose' => \$opts{verbose},
'o|order' => \$opts{order},
'h|help' => \$opts{help},
'V|version' => \$opts{version},
'<>' => sub {
if ($opts{looking})
{
push @{$opts{$opts{looking}}}, $_[0];
if (--$opts{state} == 0)
{
$opts{looking} = q{};
}
}
else
{
push @{$opts{otherargs}}, $_[0];
}
},
) or pod2usage(1);
if ($opts{help})
{
pod2usage(-exitstatus => 0, -verbose => 2);
}
if ($opts{version})
{
print "CAM::PDF v$CAM::PDF::VERSION\n";
exit 0;
}
local @ARGV = @{$opts{otherargs}};
if (@ARGV < 1)
{
pod2usage(1);
}
my $infile = shift;
my $outfile = shift || q{-};
my $opass = shift;
my $upass = shift || $opass;
my $doc = CAM::PDF->new($infile, $opass, $upass) || die "$CAM::PDF::errstr\n";
if (!$doc->canModify())
{
die "This PDF forbids modification\n";
}
if ($opts{newversion})
{
$doc->{pdfversion} = $opts{newversion};
}
if ($opts{decode} || @{$opts{filters}} > 0)
{
foreach my $objnode (keys %{$doc->{xref}})
{
if ($opts{decode})
{
$doc->decodeObject($objnode);
}
foreach my $filtername (@{$opts{filters}})
{
$doc->encodeObject($objnode, $filtername);
}
}
}
if ($opts{newprefs} || $opts{newpass})
{
my @p = $doc->getPrefs();
if ($opts{newpass})
{
$p[0] = $opts{pass}->[0];
$p[1] = $opts{pass}->[1];
}
if ($opts{newprefs})
{
$p[2] = $opts{prefs}->[0];
$p[3] = $opts{prefs}->[1];
$p[4] = $opts{prefs}->[2];
$p[5] = $opts{prefs}->[3];
}
$doc->setPrefs(@p);
}
if ($opts{decrypt})
{
$doc->cacheObjects();
$doc->{crypt}->{noop} = 1;
if ($doc->{crypt}->{EncryptBlock})
{
$doc->deleteObject($doc->{crypt}->{EncryptBlock});
delete $doc->{trailer}->{Encrypt};
delete $doc->{crypt}->{EncryptBlock};
}
}
if ($opts{clearannots})
{
$doc->clearAnnotations();
}
if ($opts{cleanse})
{
$doc->cleanse();
}
if ($opts{order})
{
$doc->preserveOrder();
}
$doc->cleanoutput($outfile);
__END__
=for stopwords rewritepdf.pl unprotecting passworded
=head1 NAME
rewritepdf.pl - Rebuild a PDF file
=head1 SYNOPSIS
rewritepdf.pl [options] infile.pdf [outfile.pdf] [password(s)]\n";
Options:
-c --cleanse seek and destroy unreferenced metadata in the document
-C --clearannots remove all annotations (including forms)
-d --decode uncompress any encoded elements
-f --filter=name compress all elements with this filter (can use more than once)
-X --decrypt remove encryption from the document
-o --order preserve the internal PDF ordering for output
-v --verbose print diagnostic messages
-h --help verbose help message
-V --version print CAM::PDF version
-p --pass opass upass set a new owner and user password
-P --prefs print modify copy add set boolean permissions for the document
The optional password arguments are needed to open password-protected
PDF files. Here's an example of password-protecting and then
unprotecting it in sequence:
rewritepdf.pl --pass SecretPass SecretPass orig.pdf passworded.pdf
rewritepdf.pl --decrypt passworded.pdf unprotected.pdf SecretPass
If you want to prevent people from being able to perform the latter
step, then tighten your permissions:
rewritepdf.pl -p Secret Secret -P 1 0 0 0 orig.pdf passworded.pdf
which means that users can print the passworded PDF, but not change
it, copy-and-paste from it, or append to it.
=head1 DESCRIPTION
Read and write a PDF document, and possibly modify it along the way.
The C<--cleanse> option could possibly break some PDFs which use
undocumented or poorly documented PDF features. Namely, some PDFs
implicitly store their C<FontDescriptor> objects just before their Font
objects, without explicitly referring to the former. Cleansing
removes the former, causing Acrobat Reader to choke.
We recommend that you avoid the C<--decode> and C<--filter> options, as
we're not sure they work right any longer.
=head1 SEE ALSO
CAM::PDF
=head1 AUTHOR
See L<CAM::PDF>
=cut
|