- add smoke test for nearest_color filter
- added integer overflow checks to many memory allocation calls
- added experimental EXIF decoding when reading JPEG files.
+- read/write i_xres, i_yres, i_aspect only tage with JPEG files,
+ and read/write jpeg_density_unit (+_name) tag
+- save the jpeg_comment tag when writing
=================================================================
if (map[i].tag == entry->tag) {
int len = entry->type == ift_ascii ? entry->size - 1 : entry->size;
i_tags_add(&im->tags, map[i].name, 0,
- tiff->base + entry->offset, len, 0);
+ (char const *)(tiff->base + entry->offset), len, 0);
break;
}
}
markerp = markerp->next;
}
+ if (cinfo.saw_JFIF_marker) {
+ double xres = cinfo.X_density;
+ double yres = cinfo.Y_density;
+
+ i_tags_addn(&im->tags, "jpeg_density_unit", 0, cinfo.density_unit);
+ switch (cinfo.density_unit) {
+ case 0: /* values are just the aspect ratio */
+ i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
+ i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "none", -1, 0);
+ break;
+
+ case 1: /* per inch */
+ i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "inch", -1, 0);
+ break;
+
+ case 2: /* per cm */
+ i_tags_add(&im->tags, "jpeg_density_unit_name", 0, "centimeter", -1, 0);
+ xres *= 2.54;
+ yres *= 2.54;
+ break;
+ }
+ i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
+ i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
+ }
+
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
*itlength=tlength;
i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
JSAMPLE *image_buffer;
int quality;
+ int got_xres, got_yres, aspect_only, resunit;
+ double xres, yres;
+ int comment_entry;
struct jpeg_compress_struct cinfo;
struct my_error_mgr jerr;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */
+ 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))
+ aspect_only = 0;
+ if (!i_tags_get_int(&im->tags, "jpeg_density_unit", 0, &resunit))
+ resunit = 1; /* per inch */
+ if (resunit < 0 || resunit > 2) /* default to inch if invalid */
+ resunit = 1;
+ if (got_xres || got_yres) {
+ if (!got_xres)
+ xres = yres;
+ else if (!got_yres)
+ yres = xres;
+ if (aspect_only)
+ resunit = 0; /* standard tags override format tags */
+ if (resunit == 2) {
+ /* convert to per cm */
+ xres /= 2.54;
+ yres /= 2.54;
+ }
+ cinfo.density_unit = resunit;
+ cinfo.X_density = (int)(xres + 0.5);
+ cinfo.Y_density = (int)(yres + 0.5);
+ }
+
jpeg_start_compress(&cinfo, TRUE);
+ if (i_tags_find(&im->tags, "jpeg_comment", 0, &comment_entry)) {
+ jpeg_write_marker(&cinfo, JPEG_COM, im->tags.tags[comment_entry].data,
+ im->tags.tags[comment_entry].size);
+ }
+
row_stride = im->xsize * im->channels; /* JSAMPLEs per row in image_buffer */
if (!im->virtual && im->type == i_direct_type && im->bits == i_8_bits) {
$img->read(file=>'foo.jpg') or die $img->errstr;
-JPEG does not support the spatial resolution tags.
+The following tags are set in a JPEG image when read, and can be set
+to control output:
+
+=over
+
+=item jpeg_density_unit
+
+The value of the density unit field in the JFIF header. This is
+ignored on writing if the 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.
+
+=item 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 jpeg_density_unit is unknown then this
+tag isn't set.
+
+=item jpeg_comment
+
+Text comment.
+
+=back
+
+JPEG supports the spatial resolution tags C<i_xres>, C<i_yres> and
+C<i_aspect_only>.
If an APP1 block containing EXIF information is found, then any of the
following tags can be set:
the i_aspect_only tag is non-zero.
The C<i_xres> and C<i_yres> tags are expressed in pixels per inch no
-matter tha value of this tag, they will be converted to/from the value
+matter the value of this tag, they will be converted to/from the value
stored in the TIFF file.
=item tiff_resolutionunit_name
use strict;
use lib 't';
use Imager qw(:all);
-use Test::More tests => 34;
+use Test::More tests => 49;
init_log("testout/t101jpeg.log",1);
Imager::log_entry("Starting 4\n", 1);
my $imoo = Imager->new;
ok($imoo->read(file=>'testout/t101.jpg'), "read jpeg OO");
+
ok($imoo->write(file=>'testout/t101_oo.jpg'), "write jpeg OO");
Imager::log_entry("Starting 5\n", 1);
my $oocmp = Imager->new;
"test value of exif tag $key");
}
}
+
+ {
+ # tests that the density values are set and read correctly
+ # tests jpeg_comment too
+ my @density_tests =
+ (
+ [ 't101cm100.jpg',
+ {
+ jpeg_density_unit => 2,
+ i_xres => 254,
+ i_yres => 254
+ },
+ {
+ jpeg_density_unit => 2,
+ i_xres => 254,
+ i_yres => 254,
+ i_aspect_only => undef,
+ },
+ ],
+ [
+ 't101xonly.jpg',
+ {
+ i_xres => 100,
+ },
+ {
+ i_xres => 100,
+ i_yres => 100,
+ jpeg_density_unit => 1,
+ i_aspect_only => undef,
+ },
+ ],
+ [
+ 't101yonly.jpg',
+ {
+ i_yres => 100,
+ },
+ {
+ i_xres => 100,
+ i_yres => 100,
+ jpeg_density_unit => 1,
+ i_aspect_only => undef,
+ },
+ ],
+ [
+ 't101asponly.jpg',
+ {
+ i_xres => 50,
+ i_yres => 100,
+ i_aspect_only => 1,
+ },
+ {
+ i_xres => 50,
+ i_yres => 100,
+ i_aspect_only => 1,
+ jpeg_density_unit => 0,
+ },
+ ],
+ [
+ 't101com.jpg',
+ {
+ jpeg_comment => 'test comment'
+ },
+ ],
+ );
+
+ print "# test density tags\n";
+ # I don't care about the content
+ my $base_im = Imager->new(xsize => 10, ysize => 10);
+ for my $test (@density_tests) {
+ my ($filename, $out_tags, $expect_tags) = @$test;
+ $expect_tags ||= $out_tags;
+
+ my $work = $base_im->copy;
+ for my $key (keys %$out_tags) {
+ $work->addtag(name => $key, value => $out_tags->{$key});
+ }
+
+ ok($work->write(file=>"testout/$filename", type=>'jpeg'),
+ "save $filename");
+
+ my $check = Imager->new;
+ ok($check->read(file=> "testout/$filename"),
+ "read $filename");
+
+ my %tags;
+ for my $key (keys %$expect_tags) {
+ $tags{$key} = $check->tags(name=>$key);
+ }
+ is_deeply($expect_tags, \%tags, "check tags for $filename");
+ }
+ }
}