- writing a 2 or 4 channel image to a JPEG will now write that image as
[imager.git] / t / t101jpeg.t
CommitLineData
66614d6e
TC
1#!perl -w
2use strict;
20adc63d 3use Imager qw(:all);
6e4af7d4
TC
4use Test::More tests => 94;
5use Imager::Test qw(is_color_close3);
20adc63d
TC
6
7init_log("testout/t101jpeg.log",1);
8
66614d6e
TC
9my $green=i_color_new(0,255,0,255);
10my $blue=i_color_new(0,0,255,255);
11my $red=i_color_new(255,0,0,255);
20adc63d 12
66614d6e
TC
13my $img=Imager::ImgRaw::new(150,150,3);
14my $cmpimg=Imager::ImgRaw::new(150,150,3);
20adc63d
TC
15
16i_box_filled($img,70,25,130,125,$green);
17i_box_filled($img,20,25,80,125,$blue);
18i_arc($img,75,75,30,0,361,$red);
19i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
20
21i_has_format("jpeg") && print "# has jpeg\n";
22if (!i_has_format("jpeg")) {
66614d6e
TC
23 # previously we'd crash if we tried to save/read an image via the OO
24 # interface when there was no jpeg support
25 SKIP:
26 {
27 my $im = Imager->new;
28 ok(!$im->read(file=>"testimg/base.jpg"), "should fail to read jpeg");
29 cmp_ok($im->errstr, '=~', qr/format 'jpeg' not supported/, "check no jpeg message");
30 $im = Imager->new(xsize=>2, ysize=>2);
31 ok(!$im->write(file=>"testout/nojpeg.jpg"), "should fail to write jpeg");
f245645a
TC
32 cmp_ok($im->errstr, '=~', qr/format 'jpeg' not supported/, "check no jpeg message");
33 ok(!grep($_ eq 'jpeg', Imager->read_types), "check jpeg not in read types");
34 ok(!grep($_ eq 'jpeg', Imager->write_types), "check jpeg not in write types");
6e4af7d4 35 skip("no jpeg support", 88);
cf692b64 36 }
20adc63d 37} else {
e2cb7e23 38 open(FH,">testout/t101.jpg") || die "cannot open testout/t101.jpg for writing\n";
20adc63d 39 binmode(FH);
66614d6e
TC
40 my $IO = Imager::io_new_fd(fileno(FH));
41 ok(i_writejpeg_wiol($img,$IO,30), "write jpeg low level");
20adc63d
TC
42 close(FH);
43
dd55acc8 44 open(FH, "testout/t101.jpg") || die "cannot open testout/t101.jpg\n";
20adc63d 45 binmode(FH);
dd55acc8
AMH
46 $IO = Imager::io_new_fd(fileno(FH));
47 ($cmpimg,undef) = i_readjpeg_wiol($IO);
20adc63d
TC
48 close(FH);
49
cf692b64
TC
50 my $diff = sqrt(i_img_diff($img,$cmpimg))/150*150;
51 print "# jpeg average mean square pixel difference: ",$diff,"\n";
66614d6e 52 ok($cmpimg, "read jpeg low level");
cf692b64 53
66614d6e 54 ok($diff < 10000, "difference between original and jpeg within bounds");
cf692b64 55
47911724 56 Imager::i_log_entry("Starting 4\n", 1);
cf692b64 57 my $imoo = Imager->new;
66614d6e 58 ok($imoo->read(file=>'testout/t101.jpg'), "read jpeg OO");
6d54291b 59
66614d6e 60 ok($imoo->write(file=>'testout/t101_oo.jpg'), "write jpeg OO");
47911724 61 Imager::i_log_entry("Starting 5\n", 1);
cf692b64 62 my $oocmp = Imager->new;
66614d6e 63 ok($oocmp->read(file=>'testout/t101_oo.jpg'), "read jpeg OO for comparison");
cf692b64
TC
64
65 $diff = sqrt(i_img_diff($imoo->{IMG},$oocmp->{IMG}))/150*150;
66 print "# OO image difference $diff\n";
66614d6e 67 ok($diff < 10000, "difference between original and jpeg within bounds");
f873cb01
TC
68
69 # write failure test
70 open FH, "< testout/t101.jpg" or die "Cannot open testout/t101.jpg: $!";
71 binmode FH;
66614d6e 72 ok(!$imoo->write(fd=>fileno(FH), type=>'jpeg'), 'failure handling');
f873cb01
TC
73 close FH;
74 print "# ",$imoo->errstr,"\n";
2c2c832a
TC
75
76 # check that the i_format tag is set
77 my @fmt = $imoo->tags(name=>'i_format');
66614d6e 78 is($fmt[0], 'jpeg', 'i_format tag');
77157728
TC
79
80 { # check file limits are checked
81 my $limit_file = "testout/t101.jpg";
82 ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
83 my $im = Imager->new;
84 ok(!$im->read(file=>$limit_file),
85 "should fail read due to size limits");
86 print "# ",$im->errstr,"\n";
87 like($im->errstr, qr/image width/, "check message");
88
89 ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
90 ok(!$im->read(file=>$limit_file),
91 "should fail read due to size limits");
92 print "# ",$im->errstr,"\n";
93 like($im->errstr, qr/image height/, "check message");
94
95 ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
96 ok($im->read(file=>$limit_file),
97 "should succeed - just inside width limit");
98 ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
99 ok($im->read(file=>$limit_file),
100 "should succeed - just inside height limit");
101
102 # 150 x 150 x 3 channel image uses 67500 bytes
103 ok(Imager->set_file_limits(reset=>1, bytes=>67499),
104 "set bytes limit 67499");
105 ok(!$im->read(file=>$limit_file),
106 "should fail - too many bytes");
107 print "# ",$im->errstr,"\n";
108 like($im->errstr, qr/storage size/, "check error message");
109 ok(Imager->set_file_limits(reset=>1, bytes=>67500),
110 "set bytes limit 67500");
111 ok($im->read(file=>$limit_file),
112 "should succeed - just inside bytes limit");
113 Imager->set_file_limits(reset=>1);
114 }
f7450478
TC
115
116 SKIP:
117 {
118 # we don't test them all
119 my %expected_tags =
120 (
121 exif_date_time_original => "2005:11:25 00:00:00",
122 exif_flash => 0,
123 exif_image_description => "Imager Development Notes",
124 exif_make => "Canon",
125 exif_model => "CanoScan LiDE 35",
126 exif_resolution_unit => 2,
127 exif_resolution_unit_name => "inches",
128 exif_user_comment => " Part of notes from reworking i_arc() and friends.",
129 exif_white_balance => 0,
130 exif_white_balance_name => "Auto white balance",
131 );
132
133 # exif tests
134 Imager::i_exif_enabled()
135 or skip("no exif support", scalar keys %expected_tags);
136
137 my $im = Imager->new;
138 $im->read(file=>"testimg/exiftest.jpg")
139 or skip("Could not read test image:".$im->errstr, scalar keys %expected_tags);
140
141 for my $key (keys %expected_tags) {
142 is($expected_tags{$key}, $im->tags(name => $key),
143 "test value of exif tag $key");
144 }
145 }
6d54291b
TC
146
147 {
148 # tests that the density values are set and read correctly
149 # tests jpeg_comment too
150 my @density_tests =
151 (
152 [ 't101cm100.jpg',
153 {
154 jpeg_density_unit => 2,
155 i_xres => 254,
156 i_yres => 254
157 },
158 {
159 jpeg_density_unit => 2,
160 i_xres => 254,
161 i_yres => 254,
162 i_aspect_only => undef,
163 },
164 ],
165 [
166 't101xonly.jpg',
167 {
168 i_xres => 100,
169 },
170 {
171 i_xres => 100,
172 i_yres => 100,
173 jpeg_density_unit => 1,
174 i_aspect_only => undef,
175 },
176 ],
177 [
178 't101yonly.jpg',
179 {
180 i_yres => 100,
181 },
182 {
183 i_xres => 100,
184 i_yres => 100,
185 jpeg_density_unit => 1,
186 i_aspect_only => undef,
187 },
188 ],
189 [
190 't101asponly.jpg',
191 {
192 i_xres => 50,
193 i_yres => 100,
194 i_aspect_only => 1,
195 },
196 {
197 i_xres => 50,
198 i_yres => 100,
199 i_aspect_only => 1,
200 jpeg_density_unit => 0,
201 },
202 ],
203 [
204 't101com.jpg',
205 {
206 jpeg_comment => 'test comment'
207 },
208 ],
209 );
210
211 print "# test density tags\n";
212 # I don't care about the content
213 my $base_im = Imager->new(xsize => 10, ysize => 10);
214 for my $test (@density_tests) {
215 my ($filename, $out_tags, $expect_tags) = @$test;
216 $expect_tags ||= $out_tags;
217
218 my $work = $base_im->copy;
219 for my $key (keys %$out_tags) {
220 $work->addtag(name => $key, value => $out_tags->{$key});
221 }
222
223 ok($work->write(file=>"testout/$filename", type=>'jpeg'),
224 "save $filename");
225
226 my $check = Imager->new;
227 ok($check->read(file=> "testout/$filename"),
228 "read $filename");
229
230 my %tags;
231 for my $key (keys %$expect_tags) {
232 $tags{$key} = $check->tags(name=>$key);
233 }
234 is_deeply($expect_tags, \%tags, "check tags for $filename");
235 }
236 }
41cdb347
TC
237
238 { # Issue # 17981
239 # the test image has a zero-length user_comment field
240 # the code would originally attempt to convert '\0' to ' '
241 # for the first 8 bytes, even if the string was less than
242 # 8 bytes long
243 my $im = Imager->new;
244 ok($im->read(file => 'testimg/209_yonge.jpg', type=>'jpeg'),
245 "test read of image with invalid exif_user_comment");
246 is($im->tags(name=>'exif_user_comment'), '',
247 "check exif_user_comment set correctly");
248 }
24ae6325
TC
249
250 { # test parseiptc handling no IPTC data correctly
251 my $saw_warn;
252 local $SIG{__WARN__} =
253 sub {
254 ++$saw_warn;
255 print "# @_\n";
256 };
257 my $im = Imager->new;
258 ok($im->read(file => 'testout/t101.jpg', type=>'jpeg'),
259 "read jpeg with no IPTC data");
260 ok(!defined $im->{IPTCRAW}, "no iptc data");
261 my %iptc = $im->parseiptc;
262 ok(!$saw_warn, "should be no warnings");
263 }
0389bf49
TC
264
265 { # Issue # 18397
266 # attempting to write a 4 channel image to a bufchain would
267 # cause a seg fault.
268 # it should fail still
6e4af7d4
TC
269 # overridden by # 29876
270 # give 4/2 channel images a background color when saving to JPEG
271 my $im = Imager->new(xsize => 16, ysize => 16, channels => 4);
272 $im->box(filled => 1, xmin => 8, color => '#FFE0C0');
0389bf49 273 my $data;
6e4af7d4
TC
274 ok($im->write(data => \$data, type => 'jpeg'),
275 "should write with a black background");
276 my $imread = Imager->new;
277 ok($imread->read(data => $data, type => 'jpeg'), 'read it back');
278 is_color_close3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0, 4,
279 "check it's black");
280 is_color_close3($imread->getpixel('x' => 15, 'y' => 9), 255, 224, 192, 4,
281 "check filled area filled");
282
283 # write with a red background
284 $data = '';
285 ok($im->write(data => \$data, type => 'jpeg', i_background => '#FF0000'),
286 "write with red background");
287 ok($imread->read(data => $data, type => 'jpeg'), "read it back");
288 is_color_close3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0, 4,
289 "check it's red");
290 is_color_close3($imread->getpixel('x' => 15, 'y' => 9), 255, 224, 192, 4,
291 "check filled area filled");
0389bf49 292 }
0e457de9
TC
293 SKIP:
294 { # Issue # 18496
295 # If a jpeg with EXIF data containing an (invalid) IFD entry with a
296 # type of zero is read then Imager crashes with a Floating point
297 # exception
298 # testimg/zerojpeg.jpg was manually modified from exiftest.jpg to
299 # reproduce the problem.
300 Imager::i_exif_enabled()
301 or skip("no exif support", 1);
302 my $im = Imager->new;
303 ok($im->read(file=>'testimg/zerotype.jpg'), "shouldn't crash");
304 }
9792933e
TC
305
306 SKIP:
307 { # code coverage - make sure wiol_skip_input_data is called
308 open BASEDATA, "< testimg/exiftest.jpg"
309 or skip "can't open base data", 1;
310 binmode BASEDATA;
311 my $data = do { local $/; <BASEDATA> };
312 close BASEDATA;
313
314 substr($data, 3, 1) eq "\xE1"
315 or skip "base data isn't as expected", 1;
316 # inserting a lot of marker data here means we take the branch in
317 # wiol_skip_input_data that refills the buffer
318 my $marker = "\xFF\xE9"; # APP9 marker
319 $marker .= pack("n", 8192) . "x" x 8190;
320 $marker x= 10; # make it take up a lot of space
321 substr($data, 2, 0) = $marker;
322 my $im = Imager->new;
323 ok($im->read(data => $data), "read with a skip of data");
324 }
325
326 SKIP:
327 { # code coverage - take the branch that provides a fake EOI
328 open BASEDATA, "< testimg/exiftest.jpg"
329 or skip "can't open base data", 1;
330 binmode BASEDATA;
331 my $data = do { local $/; <BASEDATA> };
332 close BASEDATA;
333 substr($data, -1000) = '';
334
335 my $im = Imager->new;
336 ok($im->read(data => $data), "read with image data truncated");
337 }
338
339 { # code coverage - make sure wiol_empty_output_buffer is called
340 my $im = Imager->new(xsize => 1000, ysize => 1000);
341 for my $x (0 .. 999) {
342 $im->line(x1 => $x, y1 => 0, x2 => $x, y2 => 999,
343 color => Imager::Color->new(rand 256, rand 256, rand 256));
344 }
345 my $data;
346 ok($im->write(data => \$data, type=>'jpeg', jpegquality => 100),
347 "write big file to ensure wiol_empty_output_buffer is called");
348
349 # code coverage - write failure path in wiol_empty_output_buffer
350 ok(!$im->write(callback => sub { return },
351 type => 'jpeg', jpegquality => 100),
352 "fail to write")
353 and print "# ", $im->errstr, "\n";
354 }
355
356 { # code coverage - virtual image branch in i_writejpeg_wiol()
357 my $im = $imoo->copy;
358 my $immask = $im->masked;
359 ok($immask, "made a virtual image (via masked)");
360 ok($immask->virtual, "check it's virtual");
361 my $mask_data;
362 ok($immask->write(data => \$mask_data, type => 'jpeg'),
363 "write masked version");
364 my $base_data;
365 ok($im->write(data => \$base_data, type=>'jpeg'),
366 "write normal version");
367 is($base_data, $mask_data, "check the data written matches");
368 }
369
370 SKIP:
371 { # code coverage - IPTC data
372 # this is dummy data
373 my $iptc = "\x04\x04" .
374 "\034\002x My Caption"
375 . "\034\002P Tony Cook"
376 . "\034\002i Dummy Headline!"
377 . "\034\002n No Credit Given";
378
379 my $app13 = "\xFF\xED" . pack("n", 2 + length $iptc) . $iptc;
380
381 open BASEDATA, "< testimg/exiftest.jpg"
382 or skip "can't open base data", 1;
383 binmode BASEDATA;
384 my $data = do { local $/; <BASEDATA> };
385 close BASEDATA;
386 substr($data, 2, 0) = $app13;
387
388 my $im = Imager->new;
389 ok($im->read(data => $data), "read with app13 data");
390 my %iptc = $im->parseiptc;
391 is($iptc{caption}, 'My Caption', 'check iptc caption');
392 is($iptc{photogr}, 'Tony Cook', 'check iptc photogr');
393 is($iptc{headln}, 'Dummy Headline!', 'check iptc headln');
394 is($iptc{credit}, 'No Credit Given', 'check iptc credit');
395 }
02ea5e47
TC
396
397 { # handling of CMYK jpeg
398 # http://rt.cpan.org/Ticket/Display.html?id=20416
399 my $im = Imager->new;
400 ok($im->read(file => 'testimg/scmyk.jpg'), 'read a CMYK jpeg');
401 is($im->getchannels, 3, "check channel count");
402 my $col = $im->getpixel(x => 0, 'y' => 0);
403 ok($col, "got the 'black' pixel");
404 # this is jpeg, so we can't compare colors exactly
405 # older versions returned this pixel at a light color, but
406 # it's black in the image
407 my ($r, $g, $b) = $col->rgba;
408 cmp_ok($r, '<', 10, 'black - red low');
409 cmp_ok($g, '<', 10, 'black - green low');
410 cmp_ok($b, '<', 10, 'black - blue low');
411 $col = $im->getpixel(x => 15, 'y' => 0);
412 ok($col, "got the dark blue");
413 ($r, $g, $b) = $col->rgba;
414 cmp_ok($r, '<', 10, 'dark blue - red low');
415 cmp_ok($g, '<', 10, 'dark blue - green low');
416 cmp_ok($b, '>', 110, 'dark blue - blue middle (bottom)');
417 cmp_ok($b, '<', 130, 'dark blue - blue middle (top)');
418 $col = $im->getpixel(x => 0, 'y' => 15);
419 ok($col, "got the red");
420 ($r, $g, $b) = $col->rgba;
421 cmp_ok($r, '>', 245, 'red - red high');
422 cmp_ok($g, '<', 10, 'red - green low');
423 cmp_ok($b, '<', 10, 'red - blue low');
424 }
f245645a
TC
425
426 {
427 ok(grep($_ eq 'jpeg', Imager->read_types), "check jpeg in read types");
428 ok(grep($_ eq 'jpeg', Imager->write_types), "check jpeg in write types");
429 }
f873cb01
TC
430}
431