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 )