From f9152a93cb623da8acf2cf9ff929625c83d180e7 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Mon, 31 Mar 2014 23:00:01 +1100 Subject: [PATCH] [rt #94292] add jpeg_optimize to enable optimized Huffman tables 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 | 2 +- JPEG/imjpeg.c | 4 ++++ JPEG/t/t10jpeg.t | 21 ++++++++++++++++++++- lib/Imager/Files.pod | 12 ++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/JPEG/JPEG.pm b/JPEG/JPEG.pm index 9546596d..97dd9cf9 100644 --- a/JPEG/JPEG.pm +++ b/JPEG/JPEG.pm @@ -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); diff --git a/JPEG/imjpeg.c b/JPEG/imjpeg.c index b1c97d20..dcb0ed63 100644 --- a/JPEG/imjpeg.c +++ b/JPEG/imjpeg.c @@ -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); diff --git a/JPEG/t/t10jpeg.t b/JPEG/t/t10jpeg.t index 61c54dc5..3408f068 100644 --- a/JPEG/t/t10jpeg.t +++ b/JPEG/t/t10jpeg.t @@ -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 { diff --git a/lib/Imager/Files.pod b/lib/Imager/Files.pod index 91e79f2e..5dc8aa10 100644 --- a/lib/Imager/Files.pod +++ b/lib/Imager/Files.pod @@ -647,6 +647,18 @@ file. (Imager 0.84) JPEG supports the spatial resolution tags C, C and C. +You can also set the following tags when writing to an image, they are +not set in the image when reading: + +=over + +C - 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 block containing EXIF information is found, then any of the -- 2.39.5