progressive JPEG support
authorTony Cook <tony@develop-help.com>
Wed, 8 Jun 2011 12:25:45 +0000 (22:25 +1000)
committerTony Cook <tony@develop-help.com>
Wed, 8 Jun 2011 12:25:45 +0000 (22:25 +1000)
Changes
JPEG/Changes
JPEG/imjpeg.c
JPEG/t/t10jpeg.t
lib/Imager/Files.pod

diff --git a/Changes b/Changes
index 0d1d522..1511f27 100644 (file)
--- a/Changes
+++ b/Changes
@@ -6,6 +6,9 @@ Imager 0.84 (** update GIF, TIFF, W32, PNG, JPEG, FT2 versions!)
  - Imager no longer inherits from Exporter (unless you're running an
    old, old perl.
 
  - Imager no longer inherits from Exporter (unless you're running an
    old, old perl.
 
+ - Imager can now write progressive JPEGs (it could always read them).
+   https://rt.cpan.org/Ticket/Display.html?id=68691
+
 Bug fixes:
 
  - re-work, document and test Imager's logging facility.
 Bug fixes:
 
  - re-work, document and test Imager's logging facility.
index 5274b6a..f8bfd45 100644 (file)
@@ -1,3 +1,8 @@
+Imager-File-JPEG 0.79
+=====================
+
+ - add progressive support
+
 Imager-File-JPEG 0.78
 =====================
 
 Imager-File-JPEG 0.78
 =====================
 
index 318965b..6854cb5 100644 (file)
@@ -543,6 +543,14 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
     i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
   }
 
     i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
   }
 
+  /* I originally used jpeg_has_multiple_scans() here, but that can
+   * return true for non-progressive files too.  The progressive_mode
+   * member is available at least as far back as 6b and does the right
+   * thing.
+   */
+  i_tags_setn(&im->tags, "jpeg_progressive", 
+             cinfo.progressive_mode ? 1 : 0);
+
   (void) jpeg_finish_decompress(&cinfo);
   jpeg_destroy_decompress(&cinfo);
   *itlength=tlength;
   (void) jpeg_finish_decompress(&cinfo);
   jpeg_destroy_decompress(&cinfo);
   *itlength=tlength;
@@ -567,6 +575,7 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   double xres, yres;
   int comment_entry;
   int want_channels = im->channels;
   double xres, yres;
   int comment_entry;
   int want_channels = im->channels;
+  int progressive = 0;
 
   struct jpeg_compress_struct cinfo;
   struct my_error_mgr jerr;
 
   struct jpeg_compress_struct cinfo;
   struct my_error_mgr jerr;
@@ -618,6 +627,12 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
   jpeg_set_defaults(&cinfo);
   jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
 
   jpeg_set_defaults(&cinfo);
   jpeg_set_quality(&cinfo, quality, TRUE);  /* limit to baseline-JPEG values */
 
+  if (!i_tags_get_int(&im->tags, "jpeg_progressive", 0, &progressive))
+    progressive = 0;
+  if (progressive) {
+    jpeg_simple_progression(&cinfo);
+  }
+
   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
   if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
   if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
index 1512666..2ca080c 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use Imager qw(:all);
 use Test::More;
 use strict;
 use Imager qw(:all);
 use Test::More;
-use Imager::Test qw(is_color_close3 test_image_raw);
+use Imager::Test qw(is_color_close3 test_image_raw test_image is_image);
 
 -d "testout" or mkdir "testout";
 
 
 -d "testout" or mkdir "testout";
 
@@ -11,7 +11,7 @@ init_log("testout/t101jpeg.log",1);
 $Imager::formats{"jpeg"}
   or plan skip_all => "no jpeg support";
 
 $Imager::formats{"jpeg"}
   or plan skip_all => "no jpeg support";
 
-plan tests => 94;
+plan tests => 101;
 
 my $green=i_color_new(0,255,0,255);
 my $blue=i_color_new(0,0,255,255);
 
 my $green=i_color_new(0,255,0,255);
 my $blue=i_color_new(0,0,255,255);
@@ -408,4 +408,27 @@ SKIP:
   ok(grep($_ eq 'jpeg', Imager->write_types), "check jpeg in write types");
 }
 
   ok(grep($_ eq 'jpeg', Imager->write_types), "check jpeg in write types");
 }
 
+{ # progressive JPEG
+  # https://rt.cpan.org/Ticket/Display.html?id=68691
+  my $im = test_image();
+  my $progim = $im->copy;
 
 
+  ok($progim->write(file => "testout/t10prog.jpg", type => "jpeg",
+                   jpeg_progressive => 1),
+     "write progressive jpeg");
+
+  my $rdprog = Imager->new(file => "testout/t10prog.jpg");
+  ok($rdprog, "read progressive jpeg");
+  my @prog = $rdprog->tags(name => "jpeg_progressive");
+  is($prog[0], 1, "check progressive flag set on read");
+
+  my $data;
+  ok($im->write(data => \$data, type => "jpeg"), 
+     "save as non-progressive to compare");
+  my $norm = Imager->new(data => $data);
+  ok($norm, "read non-progressive file");
+  my @nonprog = $norm->tags(name => "jpeg_progressive");
+  is($nonprog[0], 0, "check progressive flag 0 for non prog file");
+
+  is_image($rdprog, $norm, "prog vs norm should be the same image");
+}
index dcb1be5..45faceb 100644 (file)
@@ -496,26 +496,32 @@ to control output:
 
 =over
 
 
 =over
 
-=item C<jpeg_density_unit>
+=item *
 
 
-The value of the density unit field in the C<JFIF> header.  This is
-ignored on writing if the C<i_aspect_only> tag is non-zero.
+C<jpeg_density_unit> - The value of the density unit field in the
+C<JFIF> header.  This is ignored on writing if the C<i_aspect_only>
+tag is non-zero.
 
 The C<i_xres> and C<i_yres> tags are expressed in pixels per inch no
 matter the value of this tag, they will be converted to/from the value
 stored in the JPEG file.
 
 
 The C<i_xres> and C<i_yres> tags are expressed in pixels per inch no
 matter the value of this tag, they will be converted to/from the value
 stored in the JPEG file.
 
-=item C<jpeg_density_unit_name>
+=item *
 
 
-This is set when reading a JPEG file to the name of the unit given by
-C<jpeg_density_unit>.  Possible results include C<inch>,
-C<centimeter>, C<none> (the C<i_aspect_only> tag is also set reading
-these files).  If the value of C<jpeg_density_unit> is unknown then
-this tag isn't set.
+C<jpeg_density_unit_name> - This is set when reading a JPEG file to
+the name of the unit given by C<jpeg_density_unit>.  Possible results
+include C<inch>, C<centimeter>, C<none> (the C<i_aspect_only> tag is
+also set reading these files).  If the value of C<jpeg_density_unit>
+is unknown then this tag isn't set.
 
 
-=item C<jpeg_comment>
+=item *
+
+C<jpeg_comment> - Text comment.
+
+=item *
 
 
-Text comment.
+C<jpeg_progressive> - Whether the JPEG file is a progressive
+file. (Imager 0.84)
 
 =back
 
 
 =back