CAM-PDF
view release on metacpan or search on metacpan
bin/crunchjpgs.pl view on Meta::CPAN
my $isjpg = _isjpg($im);
if ((!$isjpg) && $opts{justjpgs})
{
_inform('Not a jpeg', $opts{verbose});
}
else
{
my $oldsize = $doc->getValue($im->{Length});
if (!$oldsize)
{
die "PDF error: Failed to get size of image\n";
}
$oldtotsize += $oldsize;
my $tmpl = CAM::PDF->new($opts{template}) || die "$CAM::PDF::errstr\n";
# Get a handle on the needed data bits from the template
my $media_array = $tmpl->getValue($tmpl->getPage(1)->{MediaBox});
my $rawpage = $tmpl->getPageContent(1);
$media_array->[2]->{value} = $w;
$media_array->[3]->{value} = $h;
my $page = $rawpage;
$page =~ s/xxx/$w/igxms;
$page =~ s/yyy/$h/igxms;
$tmpl->setPageContent(1, $page);
$tmpl->replaceObject(9, $doc, $objnum, 1);
my $ofile = "/tmp/crunchjpg.$$";
$tmpl->cleanoutput($ofile);
my $cmd = ('convert ' .
($opts{scale} && $w > $opts{scalemin} && $h > $opts{scalemin} ?
"-scale '$opts{scale}' " : q{}) .
"-quality $opts{quality} " .
'-density 72x72 ' .
"-page ${w}x$h " .
"pdf:$ofile jpg:- | " .
'convert jpg:- pdf:- |');
_inform($cmd, $opts{Verbose});
# TODO: this should use IPC::Open3 or the like
open my $pipe, $cmd ## no critic (ProhibitTwoArgOpen)
or die "Failed to convert object $objnum to a jpg and back\n";
my $content = do { local $RS = undef; <$pipe>; };
close $pipe
or die "Failed to convert object $objnum to a jpg and back\n";
my $jpg = CAM::PDF->new($content) || die "$CAM::PDF::errstr\n";
my $jpgim = $jpg->getObjValue(8);
my $jpgsize = $jpg->getValue($jpgim->{Length});
if ($jpgsize < $oldsize) {
$doc->replaceObject($objnum, $jpg, 8, 1);
$newtotsize += $jpgsize;
my $percent = sprintf '%.1f', 100 * ($oldsize - $jpgsize) / $oldsize;
_inform("\tcompressed $oldsize -> $jpgsize ($percent%)", $opts{verbose});
$doneobjs{$objnum} = 1;
$rimages++;
} else {
_inform("\tskipped $oldsize -> $jpgsize", $opts{verbose});
}
}
}
}
}
_inform("Crunched $rimages of $nimages images", $opts{verbose});
$doc->cleanoutput($outfile);
my $newcontentsize = $doc->{contentlength};
if ($opts{verbose})
{
my $contentpercent = sprintf '%.1f', $oldcontentsize ? 100 * ($oldcontentsize - $newcontentsize) / $oldcontentsize : 0;
my $totpercent = sprintf '%.1f', $oldtotsize ? 100 * ($oldtotsize - $newtotsize) / $oldtotsize : 0;
_inform('Compression summary:', 1);
_inform(" Document: $oldcontentsize -> $newcontentsize ($contentpercent%)", 1);
_inform(" Images: $oldtotsize -> $newtotsize ($totpercent%)", 1);
}
sub _isjpg
{
my $im = shift;
return if (!$im->{Filter});
my $f = $im->{Filter};
my @names = $f->{type} eq 'array' ? @{$f->{value}} : $f;
for my $e (@names)
{
my $name = $doc->getValue($e);
if (ref $name)
{
$name = $name->{value};
}
#warn "Checking $name\n";
if ($name eq 'DCTDecode')
{
return 1;
}
}
return;
}
sub _inform
{
my $str = shift;
my $verbose = shift;
if ($verbose)
{
print STDERR $str, "\n";
}
return;
}
__END__
=for stopwords crunchjpgs.pl ImageMagick JPG rescaling
=head1 NAME
crunchjpgs.pl - Compress all JPG images in a PDF
=head1 SYNOPSIS
crunchjpgs.pl [options] infile.pdf [outfile.pdf]
Options:
-j --justjpgs make script skip non-JPGs
-q --quality select JPG output quality (default 50)
-s --scale=num select a rescaling factor for the JPGs (default 100%)
-m --scalemin=size don't scale JPGs smaller than this pixel size (width or height)
-O --only=imnum only change the specified images (can be used mutliple times)
-S --skip=imnum don't change the specified images (can be used mutliple times)
-o --order preserve the internal PDF ordering for output
--veryverbose increases the verbosity
-v --verbose print diagnostic messages
-h --help verbose help message
( run in 2.562 seconds using v1.01-cache-2.11-cpan-a49fcb8fa48 )