re-work gif tests to move no gif available tests to a separate file
[imager.git] / t / t105gif.t
CommitLineData
bf9dd17c 1#!perl -w
336f5078 2
1660561c
TC
3=pod
4
5IF THIS TEST CRASHES
6
7Giflib/libungif have a long history of bugs, so if this script crashes
8and you aren't running version 4.1.4 of giflib or libungif then
9UPGRADE.
10
11=cut
12
bf9dd17c 13use strict;
d75cf895 14$|=1;
ce523fda 15use Test::More;
efdb8061 16use Imager qw(:all);
ce523fda 17use Imager::Test qw(is_color3 test_image test_image_raw);
8927ff88 18
66614d6e
TC
19use Carp 'confess';
20$SIG{__DIE__} = sub { confess @_ };
efdb8061 21
feba68a3
TC
22my $buggy_giflib_file = "buggy_giflib.txt";
23
efdb8061
TC
24init_log("testout/t105gif.log",1);
25
ce523fda
TC
26i_has_format("gif")
27 or plan skip_all => "no gif support";
28
29plan tests => 145;
30
bf9dd17c
TC
31my $green=i_color_new(0,255,0,255);
32my $blue=i_color_new(0,0,255,255);
33my $red=i_color_new(255,0,0,255);
efdb8061 34
ce523fda 35my $img=test_image_raw;
efdb8061 36
ce523fda
TC
37my $gifver = Imager::i_giflib_version();
38diag("giflib version (from header) $gifver");
efdb8061 39
ce523fda
TC
40open(FH,">testout/t105.gif") || die "Cannot open testout/t105.gif\n";
41binmode(FH);
42ok(i_writegifmc($img,fileno(FH),6), "write low") or
43 die "Cannot write testout/t105.gif\n";
44close(FH);
45
46open(FH,"testout/t105.gif") || die "Cannot open testout/t105.gif\n";
47binmode(FH);
48ok($img=i_readgif(fileno(FH)), "read low")
49 or die "Cannot read testout/t105.gif\n";
50close(FH);
efdb8061 51
ce523fda
TC
52open(FH,"testout/t105.gif") || die "Cannot open testout/t105.gif\n";
53binmode(FH);
54($img, my $palette)=i_readgif(fileno(FH));
55ok($img, "read palette") or die "Cannot read testout/t105.gif\n";
56close(FH);
57
58$palette=''; # just to skip a warning.
59
60# check that reading interlaced/non-interlaced versions of
61# the same GIF produce the same image
62# I could replace this with code that used Imager's built-in
63# image comparison code, but I know this code revealed the error
64open(FH, "<testimg/scalei.gif") || die "Cannot open testimg/scalei.gif";
65binmode FH;
66my ($imgi) = i_readgif(fileno(FH));
67ok($imgi, "read interlaced") or die "Cannot read testimg/scalei.gif";
68close FH;
69open FH, "<testimg/scale.gif" or die "Cannot open testimg/scale.gif";
70binmode FH;
71my ($imgni) = i_readgif(fileno(FH));
72ok($imgni, "read normal") or die "Cannot read testimg/scale.gif";
73close FH;
74
75open FH, ">testout/t105i.ppm" or die "Cannot create testout/t105i.ppm";
76binmode FH;
77my $IO = Imager::io_new_fd( fileno(FH) );
78i_writeppm_wiol($imgi, $IO)
79 or die "Cannot write testout/t105i.ppm";
80close FH;
81
82open FH, ">testout/t105ni.ppm" or die "Cannot create testout/t105ni.ppm";
83binmode FH;
84$IO = Imager::io_new_fd( fileno(FH) );
85i_writeppm_wiol($imgni, $IO)
86 or die "Cannot write testout/t105ni.ppm";
87close FH;
88
89# compare them
90open FH, "<testout/t105i.ppm" or die "Cannot open testout/t105i.ppm";
91my $datai = do { local $/; <FH> };
92close FH;
93
94open FH, "<testout/t105ni.ppm" or die "Cannot open testout/t105ni.ppm";
95my $datani = do { local $/; <FH> };
96close FH;
97is($datai, $datani, "images match");
66614d6e
TC
98
99SKIP:
100{
ce523fda
TC
101 skip("giflib3 doesn't support callbacks", 4) unless $gifver >= 4.0;
102 # reading with a callback
103 # various sizes to make sure the buffering works
104 # requested size
105 open FH, "<testimg/scale.gif" or die "Cannot open testimg/scale.gif";
106 binmode FH;
107 # no callback version in giflib3, so don't overwrite a good image
108 my $img2 = i_readgif_callback(sub { my $tmp; read(FH, $tmp, $_[0]) and $tmp });
109 close FH;
110 ok($img, "reading with a callback");
111
112 ok(test_readgif_cb(1), "read callback 1 char buffer");
113 ok(test_readgif_cb(512), "read callback 512 char buffer");
114 ok(test_readgif_cb(1024), "read callback 1024 char buffer");
115}
116open FH, ">testout/t105_mc.gif" or die "Cannot open testout/t105_mc.gif";
117binmode FH;
118ok(i_writegifmc($img, fileno(FH), 7), "writegifmc");
119close(FH);
120
121# new writegif_gen
122# test webmap, custom errdiff map
123# (looks fairly awful)
124open FH, ">testout/t105_gen.gif" or die $!;
125binmode FH;
126ok(i_writegif_gen(fileno(FH), { make_colors=>'webmap',
127 translate=>'errdiff',
128 errdiff=>'custom',
129 errdiff_width=>2,
130 errdiff_height=>2,
131 errdiff_map=>[0, 1, 1, 0]}, $img),
66614d6e 132 "webmap, custom errdif map");
ce523fda
TC
133close FH;
134
135print "# the following tests are fairly slow\n";
136
137# test animation, mc_addi, error diffusion, ordered transparency
138my @imgs;
139my $sortagreen = i_color_new(0, 255, 0, 63);
140for my $i (0..4) {
141 my $im = Imager::ImgRaw::new(200, 200, 4);
142 _add_tags($im, gif_delay=>50, gif_disposal=>2);
143 for my $j (0..$i-1) {
144 my $fill = i_color_new(0, 128, 0, 255 * ($i-$j)/$i);
145 i_box_filled($im, 0, $j*40, 199, $j*40+40, $fill);
146 }
147 i_box_filled($im, 0, $i*40, 199, 199, $blue);
148 push(@imgs, $im);
149}
150my @gif_delays = (50) x 5;
151my @gif_disposal = (2) x 5;
152open FH, ">testout/t105_anim.gif" or die $!;
153binmode FH;
154ok(i_writegif_gen(fileno(FH), { make_colors=>'addi',
155 translate=>'closest',
156 gif_delays=>\@gif_delays,
157 gif_disposal=>\@gif_disposal,
158 gif_positions=> [ map [ $_*10, $_*10 ], 0..4 ],
159 gif_user_input=>[ 1, 0, 1, 0, 1 ],
160 transp=>'ordered',
161 'tr_orddith'=>'dot8'}, @imgs),
162 "write anim gif");
163close FH;
164
165my $can_write_callback = 0;
166unlink $buggy_giflib_file;
167SKIP:
168{
169 skip("giflib3 doesn't support callbacks", 1) unless $gifver >= 4.0;
170 ++$can_write_callback;
171 my $good = ext_test(14, <<'ENDOFCODE');
8927ff88
TC
172use Imager qw(:all);
173use Imager::Test qw(test_image_raw);
174my $timg = test_image_raw();
65931431
TC
175my @gif_delays = (50) x 5;
176my @gif_disposal = (2) x 5;
177my @imgs = ($timg) x 5;
178open FH, "> testout/t105_anim_cb.gif" or die $!;
179binmode FH;
180i_writegif_callback(sub {
181 print FH $_[0]
182 },
183 -1, # max buffering
184 { make_colors=>'webmap',
185 translate=>'closest',
186 gif_delays=>\@gif_delays,
187 gif_disposal=>\@gif_disposal,
188 #transp=>'ordered',
189 tr_orddith=>'dot8'}, @imgs)
190 or die "Cannot write anim gif";
191close FH;
192print "ok 14\n";
193exit;
194ENDOFCODE
ce523fda
TC
195 unless ($good) {
196 $can_write_callback = 0;
197 fail("see $buggy_giflib_file");
198 print STDERR "\nprobable buggy giflib - skipping tests that depend on a good giflib\n";
199 print STDERR "see $buggy_giflib_file for more information\n";
200 open FLAG, "> $buggy_giflib_file" or die;
201 print FLAG <<EOS;
feba68a3
TC
202This file is created by t105gif.t when test 14 fails.
203
f1967c11
TC
204This failure usually indicates you\'re using the original versions
205of giflib 4.1.0 - 4.1.3, which have a few bugs that Imager tickles.
feba68a3
TC
206
207You can apply the patch from:
208
209http://www.develop-help.com/imager/giflib.patch
210
211or you can just install Imager as is, if you only need to write GIFs to
212files or file descriptors (such as sockets).
213
f1967c11
TC
214One hunk of this patch is rejected (correctly) with giflib 4.1.3,
215since one bug that the patch fixes is fixed in 4.1.3.
216
217If you don't feel comfortable with that apply the patch file that
218belongs to the following patch entry on sourceforge:
219
220https://sourceforge.net/tracker/index.php?func=detail&aid=981255&group_id=102202&atid=631306
221
feba68a3
TC
222In previous versions of Imager only this test was careful about catching
223the error, we now skip any tests that crashed or failed when the buggy
224giflib was present.
efdb8061 225EOS
ce523fda
TC
226 }
227}
228@imgs = ();
229my $c = i_color_new(0,0,0,0);
230for my $g (0..3) {
231 my $im = Imager::ImgRaw::new(200, 200, 3);
232 _add_tags($im, gif_local_map=>1, gif_delay=>150, gif_loop=>10);
233 for my $x (0 .. 39) {
234 for my $y (0 .. 39) {
235 $c->set($x * 6, $y * 6, 32*$g+$x+$y, 255);
236 i_box_filled($im, $x*5, $y*5, $x*5+4, $y*5+4, $c);
efdb8061 237 }
ce523fda
TC
238 }
239 push(@imgs, $im);
240}
241# test giflib with multiple palettes
242# (it was meant to test the NS loop extension too, but that's broken)
243# this looks better with make_colors=>'addi', translate=>'errdiff'
244# this test aims to overload the palette for each image, so the
245# output looks moderately horrible
246open FH, ">testout/t105_mult_pall.gif" or die "Cannot create file: $!";
247binmode FH;
248ok(i_writegif_gen(fileno(FH), { #make_colors=>'webmap',
249 translate=>'giflib',
250 }, @imgs), "write multiple palettes")
251 or print "# ", join(":", map $_->[1], Imager::i_errors()),"\n";
252close FH;
efdb8061 253
ce523fda
TC
254# regression test: giflib doesn't like 1 colour images
255my $img1 = Imager::ImgRaw::new(100, 100, 3);
256i_box_filled($img1, 0, 0, 100, 100, $red);
257open FH, ">testout/t105_onecol.gif" or die $!;
258binmode FH;
259ok(i_writegif_gen(fileno(FH), { translate=>'giflib'}, $img1),
260 "single colour write regression");
261close FH;
43a881d3 262
ce523fda
TC
263# transparency test
264# previously it was harder do write transparent images
265# tests the improvements
266my $timg = Imager::ImgRaw::new(20, 20, 4);
267my $trans = i_color_new(255, 0, 0, 127);
268i_box_filled($timg, 0, 0, 20, 20, $green);
269i_box_filled($timg, 2, 2, 18, 18, $trans);
270open FH, ">testout/t105_trans.gif" or die $!;
271binmode FH;
272ok(i_writegif_gen(fileno(FH), { make_colors=>'addi',
273 translate=>'closest',
274 transp=>'ordered',
275 }, $timg), "write transparent");
276close FH;
66614d6e 277
ce523fda
TC
278# some error handling tests
279# open a file handle for read and try to save to it
280# is this idea portable?
281# whether or not it is, giflib segfaults on this <sigh>
282#open FH, "<testout/t105_trans.gif" or die $!;
283#binmode FH; # habit, I suppose
284#if (i_writegif_gen(fileno(FH), {}, $timg)) {
285# # this is meant to _fail_
286# print "not ok 18 # writing to read-only should fail";
287#}
288#else {
289# print "ok 18 # ",Imager::_error_as_msg(),"\n";
290#}
291#close FH;
292
293# try to read a file of the wrong format - the script will do
294open FH, "<t/t105gif.t"
295 or die "Cannot open this script!: $!";
296binmode FH;
297ok(!i_readgif(fileno(FH)),
298 "read test script as gif should fail ". Imager::_error_as_msg());
299close FH;
300
301# try to save no images :)
302open FH, ">testout/t105_none.gif"
303 or die "Cannot open testout/t105_none.gif: $!";
304binmode FH;
305if (ok(!i_writegif_gen(fileno(FH), {}, "hello"), "shouldn't be able to write a string as a gif")) {
306 print "# ",Imager::_error_as_msg(),"\n";
307}
308
309# try to read a truncated gif (no image descriptors)
310read_failure('testimg/trimgdesc.gif');
311# file truncated just after the image descriptor tag
312read_failure('testimg/trmiddesc.gif');
313# image has no colour map
314read_failure('testimg/nocmap.gif');
315
316SKIP:
317{
318 skip("see $buggy_giflib_file", 18) if -e $buggy_giflib_file;
319 # image has a local colour map
320 open FH, "< testimg/loccmap.gif"
321 or die "Cannot open testimg/loccmap.gif: $!";
322 binmode FH;
323 ok(i_readgif(fileno(FH)), "read an image with only a local colour map");
324 close FH;
325
326 # image has global and local colour maps
327 open FH, "< testimg/screen2.gif"
328 or die "Cannot open testimg/screen2.gif: $!";
329 binmode FH;
330 my $ims = i_readgif(fileno(FH));
331 unless (ok($ims, "read an image with global and local colour map")) {
332 print "# ",Imager::_error_as_msg(),"\n";
333 }
334 close FH;
335
336 open FH, "< testimg/expected.gif"
337 or die "Cannot open testimg/expected.gif: $!";
338 binmode FH;
339 my $ime = i_readgif(fileno(FH));
340 close FH;
341 ok($ime, "reading testimg/expected.gif");
342 SKIP:
343 {
344 skip("could not read one or both of expected.gif or loccamp.gif", 1)
66614d6e 345 unless $ims and $ime;
ce523fda
TC
346 unless (is(i_img_diff($ime, $ims), 0,
347 "compare loccmap and expected")) {
348 # save the bad one
349 open FH, "> testout/t105_screen2.gif"
350 or die "Cannot create testout/t105_screen.gif: $!";
feba68a3 351 binmode FH;
ce523fda
TC
352 i_writegifmc($ims, fileno(FH), 7)
353 or print "# could not save t105_screen.gif\n";
feba68a3 354 close FH;
9d540150 355 }
ce523fda
TC
356 }
357
358 # test reading a multi-image file into multiple images
359 open FH, "< testimg/screen2.gif"
360 or die "Cannot open testimg/screen2.gif: $!";
361 binmode FH;
362 @imgs = Imager::i_readgif_multi(fileno(FH));
363 ok(@imgs, "read multi-image file into multiple images");
364 close FH;
365 is(@imgs, 2, "should be 2 images");
366 my $paletted = 1;
367 for my $img (@imgs) {
368 unless (Imager::i_img_type($img) == 1) {
369 $paletted = 0;
370 last;
97c4effc 371 }
ce523fda
TC
372 }
373 ok($paletted, "both images should be paletted");
374 is(Imager::i_colorcount($imgs[0]), 4, "4 colours in first image");
375 is(Imager::i_colorcount($imgs[1]), 2, "2 colours in second image");
376 ok(Imager::i_tags_find($imgs[0], "gif_left", 0),
377 "gif_left tag should be there");
378 my @tags = map {[ Imager::i_tags_get($imgs[1], $_) ]} 0..Imager::i_tags_count($imgs[1])-1;
379 my ($left) = grep $_->[0] eq 'gif_left', @tags;
380 ok($left && $left->[1] == 3, "check gif_left value");
381
382 # screen3.gif was saved with
383 open FH, "< testimg/screen3.gif"
384 or die "Cannot open testimg/screen3.gif: $!";
385 binmode FH;
386 @imgs = Imager::i_readgif_multi(fileno(FH));
387 ok(@imgs, "read screen3.gif");
388 close FH;
389 eval {
390 require 'Data/Dumper.pm';
391 Data::Dumper->import();
392 };
393 unless ($@) {
394 # build a big map of all tags for all images
395 @tags =
396 map {
397 my $im = $_;
398 [
399 map { join ",", map { defined() ? $_ : "undef" } Imager::i_tags_get($im, $_) }
400 0..Imager::i_tags_count($_)-1
401 ]
402 } @imgs;
403 my $dump = Dumper(\@tags);
404 $dump =~ s/^/# /mg;
405 print "# tags from gif\n", $dump;
406 }
407
408 # at this point @imgs should contain only paletted images
409 ok(Imager::i_img_type($imgs[0]) == 1, "imgs[0] paletted");
410 ok(Imager::i_img_type($imgs[1]) == 1, "imgs[1] paletted");
411
412 # see how we go saving it
413 open FH, ">testout/t105_pal.gif" or die $!;
414 binmode FH;
415 ok(i_writegif_gen(fileno(FH), { make_colors=>'addi',
416 translate=>'closest',
417 transp=>'ordered',
418 }, @imgs), "write from paletted");
419 close FH;
420
421 # make sure nothing bad happened
422 open FH, "< testout/t105_pal.gif" or die $!;
423 binmode FH;
424 ok((my @imgs2 = Imager::i_readgif_multi(fileno(FH))) == 2,
425 "re-reading saved paletted images");
426 ok(i_img_diff($imgs[0], $imgs2[0]) == 0, "imgs[0] mismatch");
427 ok(i_img_diff($imgs[1], $imgs2[1]) == 0, "imgs[1] mismatch");
428}
18accb2a 429
ce523fda
TC
430# test that the OO interface warns when we supply old options
431{
432 my @warns;
433 local $SIG{__WARN__} = sub { push(@warns, "@_") };
434
435 my $ooim = Imager->new;
436 ok($ooim->read(file=>"testout/t105.gif"), "read into object");
437 ok($ooim->write(file=>"testout/t105_warn.gif", interlace=>1),
438 "save from object")
439 or print "# ", $ooim->errstr, "\n";
440 ok(grep(/Obsolete .* interlace .* gif_interlace/, @warns),
441 "check for warning");
442 init(warn_obsolete=>0);
443 @warns = ();
444 ok($ooim->write(file=>"testout/t105_warn.gif", interlace=>1),
445 "save from object");
446 ok(!grep(/Obsolete .* interlace .* gif_interlace/, @warns),
447 "check for warning");
448}
1501d9b3 449
ce523fda
TC
450# test that we get greyscale from 1 channel images
451# we check for each makemap, and for each translate
452print "# test writes of grayscale images - ticket #365\n";
453my $ooim = Imager->new(xsize=>50, ysize=>50, channels=>1);
454for (my $y = 0; $y < 50; $y += 10) {
455 $ooim->box(box=>[ 0, $y, 49, $y+9], color=>NC($y*5,0,0), filled=>1);
456}
457my $ooim3 = $ooim->convert(preset=>'rgb');
458#$ooim3->write(file=>'testout/t105gray.ppm');
459my %maxerror = ( mediancut => 51000,
460 addi => 0,
461 closest => 0,
462 perturb => 0,
463 errdiff => 0 );
464for my $makemap (qw(mediancut addi)) {
465 print "# make_colors => $makemap\n";
466 ok( $ooim->write(file=>"testout/t105gray-$makemap.gif",
467 make_colors=>$makemap,
468 gifquant=>'gen'),
469 "writing gif with makemap $makemap");
470 my $im2 = Imager->new;
471 if (ok($im2->read(file=>"testout/t105gray-$makemap.gif"),
472 "reading written grayscale gif")) {
473 my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG});
474 ok($diff <= $maxerror{$makemap}, "comparing images $diff");
475 #$im2->write(file=>"testout/t105gray-$makemap.ppm");
476 }
477 else {
478 SKIP: { skip("could not get test image", 1); }
479 }
480}
481for my $translate (qw(closest perturb errdiff)) {
482 print "# translate => $translate\n";
483 my @colors = map NC($_*50, $_*50, $_*50), 0..4;
484 ok($ooim->write(file=>"testout/t105gray-$translate.gif",
485 translate=>$translate,
486 make_colors=>'none',
487 colors=>\@colors,
488 gifquant=>'gen'),
489 "writing gif with translate $translate");
490 my $im2 = Imager->new;
491 if (ok($im2->read(file=>"testout/t105gray-$translate.gif"),
492 "reading written grayscale gif")) {
493 my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG});
494 ok($diff <= $maxerror{$translate}, "comparing images $diff");
495 #$im2->write(file=>"testout/t105gray-$translate.ppm");
496 }
497 else {
498 SKIP: { skip("could not load test image", 1) }
499 }
8c68bf11 500 }
77157728 501
ce523fda
TC
502# try to write an image with no colors - should error
503ok(!$ooim->write(file=>"testout/t105nocolors.gif",
504 make_colors=>'none',
505 colors=>[], gifquant=>'gen'),
506 "write with no colors");
507
508# try to write multiple with no colors, with separate maps
509# I don't see a way to test this, since we don't have a mechanism
510# to give the second image different quant options, we can't trigger
511# a failure just for the second image
512
513# check that the i_format tag is set for both multiple and single
514# image reads
515{
516 my @anim = Imager->read_multi(file=>"testout/t105_anim.gif");
517 ok(@anim == 5, "check we got all the images");
518 for my $frame (@anim) {
519 my ($type) = $frame->tags(name=>'i_format');
520 is($type, 'gif', "check i_format for animation frame");
77157728 521 }
ce523fda
TC
522
523 my $im = Imager->new;
524 ok($im->read(file=>"testout/t105.gif"), "read some gif");
525 my ($type) = $im->tags(name=>'i_format');
526 is($type, 'gif', 'check i_format for single image read');
527}
f1adece7 528
ce523fda
TC
529{ # check file limits are checked
530 my $limit_file = "testout/t105.gif";
531 ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
532 my $im = Imager->new;
533 ok(!$im->read(file=>$limit_file),
534 "should fail read due to size limits");
535 print "# ",$im->errstr,"\n";
536 like($im->errstr, qr/image width/, "check message");
537
538 ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
539 ok(!$im->read(file=>$limit_file),
540 "should fail read due to size limits");
541 print "# ",$im->errstr,"\n";
542 like($im->errstr, qr/image height/, "check message");
543
544 ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
545 ok($im->read(file=>$limit_file),
546 "should succeed - just inside width limit");
547 ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
548 ok($im->read(file=>$limit_file),
549 "should succeed - just inside height limit");
550
551 # 150 x 150 x 3 channel image uses 67500 bytes
552 ok(Imager->set_file_limits(reset=>1, bytes=>67499),
553 "set bytes limit 67499");
554 ok(!$im->read(file=>$limit_file),
555 "should fail - too many bytes");
556 print "# ",$im->errstr,"\n";
557 like($im->errstr, qr/storage size/, "check error message");
558 ok(Imager->set_file_limits(reset=>1, bytes=>67500),
559 "set bytes limit 67500");
560 ok($im->read(file=>$limit_file),
561 "should succeed - just inside bytes limit");
562 Imager->set_file_limits(reset=>1);
563}
564
565{
566 print "# test OO interface reading of consolidated images\n";
567 my $im = Imager->new;
568 ok($im->read(file=>'testimg/screen2.gif', gif_consolidate=>1),
569 "read image to consolidate");
570 my $expected = Imager->new;
571 ok($expected->read(file=>'testimg/expected.gif'),
572 "read expected via OO");
573 is(i_img_diff($im->{IMG}, $expected->{IMG}), 0,
574 "compare them");
575
576 # check the default read doesn't match
577 ok($im->read(file=>'testimg/screen2.gif'),
578 "read same image without consolidate");
579 isnt(i_img_diff($im->{IMG}, $expected->{IMG}), 0,
f1adece7 580 "compare them - shouldn't include the overlayed second image");
ce523fda
TC
581}
582{
583 print "# test the reading of single pages\n";
584 # build a test file
585 my $test_file = 'testout/t105_multi_sing.gif';
586 my $im1 = Imager->new(xsize=>100, ysize=>100);
587 $im1->box(filled=>1, color=>$blue);
588 $im1->addtag(name=>'gif_left', value=>10);
589 $im1->addtag(name=>'gif_top', value=>15);
590 $im1->addtag(name=>'gif_comment', value=>'First page');
591 my $im2 = Imager->new(xsize=>50, ysize=>50);
592 $im2->box(filled=>1, color=>$red);
593 $im2->addtag(name=>'gif_left', value=>30);
594 $im2->addtag(name=>'gif_top', value=>25);
595 $im2->addtag(name=>'gif_comment', value=>'Second page');
596 my $im3 = Imager->new(xsize=>25, ysize=>25);
597 $im3->box(filled=>1, color=>$green);
598 $im3->addtag(name=>'gif_left', value=>35);
599 $im3->addtag(name=>'gif_top', value=>45);
600 # don't set comment for $im3
601 ok(Imager->write_multi({ file=> $test_file}, $im1, $im2, $im3),
602 "write test file for single page reads");
603
604 my $res = Imager->new;
605 # check we get the first image
606 ok($res->read(file=>$test_file), "read default (first) page");
607 is(i_img_diff($im1->{IMG}, $res->{IMG}), 0, "compare against first");
608 # check tags
609 is($res->tags(name=>'gif_left'), 10, "gif_left");
610 is($res->tags(name=>'gif_top'), 15, "gif_top");
611 is($res->tags(name=>'gif_comment'), 'First page', "gif_comment");
612
613 # get the second image
614 ok($res->read(file=>$test_file, page=>1), "read second page")
615 or print "# ",$res->errstr, "\n";
616 is(i_img_diff($im2->{IMG}, $res->{IMG}), 0, "compare against second");
617 # check tags
618 is($res->tags(name=>'gif_left'), 30, "gif_left");
619 is($res->tags(name=>'gif_top'), 25, "gif_top");
620 is($res->tags(name=>'gif_comment'), 'Second page', "gif_comment");
621
622 # get the third image
623 ok($res->read(file=>$test_file, page=>2), "read third page")
624 or print "# ",$res->errstr, "\n";
625 is(i_img_diff($im3->{IMG}, $res->{IMG}), 0, "compare against third");
626 is($res->tags(name=>'gif_left'), 35, "gif_left");
627 is($res->tags(name=>'gif_top'), 45, "gif_top");
628 is($res->tags(name=>'gif_comment'), undef, 'gif_comment undef');
629
630 # try to read a fourth page
f1adece7 631 ok(!$res->read(file=>$test_file, page=>3), "fail reading fourth page");
ce523fda
TC
632 cmp_ok($res->errstr, "=~", 'page 3 not found',
633 "check error message");
634}
c50cfe78 635SKIP:
ce523fda
TC
636{
637 skip("gif_loop not supported on giflib before 4.1", 6)
638 unless $gifver >= 4.1;
639 # testing writing the loop extension
640 my $im1 = Imager->new(xsize => 100, ysize => 100);
641 $im1->box(filled => 1, color => '#FF0000');
642 my $im2 = Imager->new(xsize => 100, ysize => 100);
643 $im2->box(filled => 1, color => '#00FF00');
644 ok(Imager->write_multi({
645 gif_loop => 5,
646 gif_delay => 50,
647 file => 'testout/t105loop.gif'
648 }, $im1, $im2),
649 "write with loop extension");
650
651 my @im = Imager->read_multi(file => 'testout/t105loop.gif');
652 is(@im, 2, "read loop images back");
653 is($im[0]->tags(name => 'gif_loop'), 5, "first loop read back");
654 is($im[1]->tags(name => 'gif_loop'), 5, "second loop read back");
655 is($im[0]->tags(name => 'gif_delay'), 50, "first delay read back");
656 is($im[1]->tags(name => 'gif_delay'), 50, "second delay read back");
657}
658SKIP:
659{ # check graphic control extension and ns loop tags are read correctly
660 print "# check GCE and netscape loop extension tag values\n";
661 my @im = Imager->read_multi(file => 'testimg/screen3.gif');
662 is(@im, 2, "read 2 images from screen3.gif")
663 or skip("Could not load testimg/screen3.gif:".Imager->errstr, 11);
664 is($im[0]->tags(name => 'gif_delay'), 50, "0 - gif_delay");
665 is($im[0]->tags(name => 'gif_disposal'), 2, "0 - gif_disposal");
666 is($im[0]->tags(name => 'gif_trans_index'), undef, "0 - gif_trans_index");
667 is($im[0]->tags(name => 'gif_user_input'), 0, "0 - gif_user_input");
668 is($im[0]->tags(name => 'gif_loop'), 0, "0 - gif_loop");
669 is($im[1]->tags(name => 'gif_delay'), 50, "1 - gif_delay");
670 is($im[1]->tags(name => 'gif_disposal'), 2, "1 - gif_disposal");
671 is($im[1]->tags(name => 'gif_trans_index'), 7, "1 - gif_trans_index");
672 is($im[1]->tags(name => 'gif_trans_color'), 'color(255,255,255,0)',
673 "1 - gif_trans_index");
674 is($im[1]->tags(name => 'gif_user_input'), 0, "1 - gif_user_input");
675 is($im[1]->tags(name => 'gif_loop'), 0, "1 - gif_loop");
676}
bcff4dd9 677
ce523fda
TC
678{
679 # manually modified from a small gif, this had the palette
680 # size changed to half the size, leaving an index out of range
681 my $im = Imager->new;
682 ok($im->read(file => 'testimg/badindex.gif', type => 'gif'),
683 "read bad index gif")
684 or print "# ", $im->errstr, "\n";
685 my @indexes = $im->getscanline('y' => 0, type => 'index');
686 is_deeply(\@indexes, [ 0..4 ], "check for correct indexes");
687 is($im->colorcount, 5, "check the palette was adjusted");
688 is_color3($im->getpixel('y' => 0, x => 4), 0, 0, 0,
689 "check it was black added");
690 is($im->tags(name => 'gif_colormap_size'), 4, 'color map size tag');
691}
f245645a 692
ce523fda
TC
693{
694 ok(grep($_ eq 'gif', Imager->read_types), "check gif in read types");
695 ok(grep($_ eq 'gif', Imager->write_types), "check gif in write types");
696}
43b2b326 697
ce523fda
TC
698{
699 # check screen tags handled correctly note the screen size
700 # supplied is larger than the box covered by the images
701 my $im1 = Imager->new(xsize => 10, ysize => 8);
702 $im1->settag(name => 'gif_top', value => 4);
703 $im1->settag(name => 'gif_screen_width', value => 18);
704 $im1->settag(name => 'gif_screen_height', value => 16);
705 my $im2 = Imager->new(xsize => 7, ysize => 10);
706 $im2->settag(name => 'gif_left', value => 3);
707 my @im = ( $im1, $im2 );
708
709 my $data;
710 ok(Imager->write_multi({ data => \$data, type => 'gif' }, @im),
711 "write with screen settings")
712 or print "# ", Imager->errstr, "\n";
713 my @result = Imager->read_multi(data => $data);
714 is(@result, 2, "got 2 images back");
715 is($result[0]->tags(name => 'gif_screen_width'), 18,
716 "check result screen width");
717 is($result[0]->tags(name => 'gif_screen_height'), 16,
718 "check result screen height");
719 is($result[0]->tags(name => 'gif_left'), 0,
720 "check first gif_left");
721 is($result[0]->tags(name => 'gif_top'), 4,
722 "check first gif_top");
723 is($result[1]->tags(name => 'gif_left'), 3,
724 "check second gif_left");
725 is($result[1]->tags(name => 'gif_top'), 0,
726 "check second gif_top");
727}
5c0d0ddf 728
ce523fda
TC
729{ # test colors array returns colors
730 my $data;
731 my $im = test_image();
732 my @colors;
733 ok($im->write(data => \$data,
734 colors => \@colors,
735 make_colors => 'webmap',
736 translate => 'closest',
737 gifquant => 'gen',
738 type => 'gif'),
739 "write using webmap to check color table");
740 is(@colors, 216, "should be 216 colors in the webmap");
741 is_color3($colors[0], 0, 0, 0, "first should be 000000");
742 is_color3($colors[1], 0, 0, 0x33, "second should be 000033");
743 is_color3($colors[8], 0, 0x33, 0x66, "9th should be 003366");
bf9dd17c
TC
744}
745
efdb8061
TC
746sub test_readgif_cb {
747 my ($size) = @_;
748
749 open FH, "<testimg/scale.gif" or die "Cannot open testimg/scale.gif";
750 binmode FH;
751 my $img = i_readgif_callback(sub { my $tmp; read(FH, $tmp, $size) and $tmp });
752 close FH;
753 return $img;
754}
e6172a17
TC
755
756# tests for reading bad gif files
757sub read_failure {
66614d6e 758 my ($filename) = @_;
e6172a17
TC
759
760 open FH, "< $filename"
761 or die "Cannot open $filename: $!";
762 binmode FH;
763 my ($result, $map) = i_readgif(fileno(FH));
66614d6e 764 ok(!$result, "attempt to read invalid image $filename ".Imager::_error_as_msg());
e6172a17
TC
765 close FH;
766}
767
97c4effc
TC
768sub _clear_tags {
769 my (@imgs) = @_;
770
771 for my $img (@imgs) {
772 $img->deltag(code=>0);
773 }
774}
775
776sub _add_tags {
777 my ($img, %tags) = @_;
778
779 for my $key (keys %tags) {
780 Imager::i_tags_add($img, $key, 0, $tags{$key}, 0);
781 }
782}
65931431
TC
783
784sub ext_test {
785 my ($testnum, $code, $count, $name) = @_;
786
787 $count ||= 1;
788 $name ||= "gif$testnum";
789
790 # build our code
791 my $script = "testout/$name.pl";
792 if (open SCRIPT, "> $script") {
793 print SCRIPT <<'PROLOG';
794#!perl -w
795if (lc $^O eq 'mswin32') {
796 # avoid the dialog box that window's pops up on a GPF
797 # if you want to debug this stuff, I suggest you comment out the
798 # following
799 eval {
800 require Win32API::File;
801 Win32API::File::SetErrorMode( Win32API::File::SEM_NOGPFAULTERRORBOX());
802 };
803}
804PROLOG
805
806 print SCRIPT $code;
807 close SCRIPT;
808
809 my $perl = $^X;
810 $perl = qq/"$perl"/ if $perl =~ / /;
811
812 print "# script: $script\n";
813 my $cmd = "$perl -Mblib $script";
814 print "# command: $cmd\n";
815
816 my $ok = 1;
817 my @out = `$cmd`; # should work on DOS and Win32
65931431
TC
818 my $found = 0;
819 for (@out) {
66614d6e
TC
820 if (/^not ok\s+(?:\d+\s*)?#(.*)/ || /^not ok/) {
821 my $msg = $1 || '';
822 ok(0, $msg);
65931431
TC
823 $ok = 0;
824 ++$found;
825 }
66614d6e
TC
826 elsif (/^ok\s+(?:\d+\s*)?#(.*)/ || /^ok/) {
827 my $msg = $1 || '';
828 ok(1, $msg);
65931431
TC
829 ++$found;
830 }
831 }
832 unless ($count == $found) {
833 print "# didn't see enough ok/not ok\n";
834 $ok = 0;
835 }
836 return $ok;
837 }
838 else {
66614d6e 839 return skip("could not create test script $script: $!");
65931431
TC
840 return 0;
841 }
842}