[rt #94292] add jpeg_optimize to enable optimized Huffman tables
authorTony Cook <tony@develop-help.com>
Mon, 31 Mar 2014 12:00:01 +0000 (23:00 +1100)
committerTony Cook <tony@develop-help.com>
Mon, 31 Mar 2014 12:00:01 +0000 (23:00 +1100)
This can significantly reduce file size, but uses more memory and time.

For one sample image (mostly sky), this reduced the file size from
445930 bytes to 272933 bytes, with a 12% increase in CPU usage.

JPEG/JPEG.pm
JPEG/imjpeg.c
JPEG/t/t10jpeg.t
lib/Imager/Files.pod

index 9546596..97dd9cf 100644 (file)
@@ -4,7 +4,7 @@ use Imager;
 use vars qw($VERSION @ISA);
 
 BEGIN {
-  $VERSION = "0.88";
+  $VERSION = "0.89";
 
   require XSLoader;
   XSLoader::load('Imager::File::JPEG', $VERSION);
index b1c97d2..dcb0ed6 100644 (file)
@@ -566,6 +566,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   int comment_entry;
   int want_channels = im->channels;
   int progressive = 0;
+  int optimize = 0;
 
   struct jpeg_compress_struct cinfo;
   struct my_error_mgr jerr;
@@ -627,6 +628,9 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   if (progressive) {
     jpeg_simple_progression(&cinfo);
   }
+  if (!i_tags_get_int(&im->tags, "jpeg_optimize", 0, &optimize))
+    optimize = 0;
+  cinfo.optimize_coding = optimize;
 
   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
index 61c54dc..3408f06 100644 (file)
@@ -11,7 +11,7 @@ init_log("testout/t101jpeg.log",1);
 $Imager::formats{"jpeg"}
   or plan skip_all => "no jpeg support";
 
-plan tests => 103;
+plan tests => 109;
 
 print STDERR "libjpeg version: ", Imager::File::JPEG::i_libjpeg_version(), "\n";
 
@@ -438,6 +438,25 @@ SKIP:
   is_image($rdprog, $norm, "prog vs norm should be the same image");
 }
 
+SKIP:
+{ # optimize coding
+  my $im = test_image();
+  my $base;
+  ok($im->write(data => \$base, type => "jpeg"), "save without optimize");
+  my $opt;
+  ok($im->write(data => \$opt, type => "jpeg", jpeg_optimize => 1),
+     "save with optimize");
+  cmp_ok(length $opt, '<', length $base, "check optimized is smaller");
+  my $im_base = Imager->new(data => $base, filetype => "jpeg");
+  ok($im_base, "read unoptimized back");
+  my $im_opt = Imager->new(data => $opt, filetype => "jpeg");
+  ok($im_opt, "read optimized back");
+  $im_base && $im_opt
+    or skip "couldn't read one back", 1;
+  is_image($im_opt, $im_base,
+          "optimization should only change huffman compression, not quality");
+}
+
 { # check close failures are handled correctly
   my $im = test_image();
   my $fail_close = sub {
index 91e79f2..5dc8aa1 100644 (file)
@@ -647,6 +647,18 @@ file. (Imager 0.84)
 JPEG supports the spatial resolution tags C<i_xres>, C<i_yres> and
 C<i_aspect_only>.
 
+You can also set the following tags when writing to an image, they are
+not set in the image when reading:
+
+=over
+
+C<jpeg_optimize> - set to a non-zero integer to compute optimal
+Huffman coding tables for the image.  This will increase memory usage
+and processing time (about 12% in my simple tests) but can
+significantly reduce file size without a loss of quality.
+
+=back
+
 =for stopwords EXIF
 
 If an C<APP1> block containing EXIF information is found, then any of the