]>
Commit | Line | Data |
---|---|---|
352c64ed TC |
1 | #!perl -w |
2 | use strict; | |
37a9be8e TC |
3 | use Imager qw(:all); |
4 | use Test::More; | |
6d5c85a2 | 5 | use Imager::Test qw(test_image_raw test_image); |
1cdc4cbd | 6 | |
38eab175 TC |
7 | my $debug_writes = 1; |
8 | ||
1d7e3124 TC |
9 | -d "testout" or mkdir "testout"; |
10 | ||
9e35eed7 | 11 | init_log("testout/t102png.log",1); |
1cdc4cbd | 12 | |
1d7e3124 | 13 | $Imager::formats{"png"} |
3a64cddb | 14 | or plan skip_all => "No png support"; |
37a9be8e | 15 | |
38eab175 | 16 | plan tests => 39; |
1cdc4cbd | 17 | |
352c64ed TC |
18 | my $green = i_color_new(0, 255, 0, 255); |
19 | my $blue = i_color_new(0, 0, 255, 255); | |
20 | my $red = i_color_new(255, 0, 0, 255); | |
1cdc4cbd | 21 | |
37a9be8e | 22 | my $img = test_image_raw(); |
1cdc4cbd TC |
23 | |
24 | my $timg = Imager::ImgRaw::new(20, 20, 4); | |
25 | my $trans = i_color_new(255, 0, 0, 127); | |
26 | i_box_filled($timg, 0, 0, 20, 20, $green); | |
27 | i_box_filled($timg, 2, 2, 18, 18, $trans); | |
28 | ||
37a9be8e TC |
29 | Imager::i_tags_add($img, "i_xres", 0, "300", 0); |
30 | Imager::i_tags_add($img, "i_yres", 0, undef, 200); | |
31 | # the following confuses the GIMP | |
32 | #Imager::i_tags_add($img, "i_aspect_only", 0, undef, 1); | |
33 | open(FH,">testout/t102.png") || die "cannot open testout/t102.png for writing\n"; | |
34 | binmode(FH); | |
35 | my $IO = Imager::io_new_fd(fileno(FH)); | |
1d7e3124 | 36 | ok(Imager::File::PNG::i_writepng_wiol($img, $IO), "write"); |
37a9be8e TC |
37 | close(FH); |
38 | ||
39 | open(FH,"testout/t102.png") || die "cannot open testout/t102.png\n"; | |
40 | binmode(FH); | |
41 | $IO = Imager::io_new_fd(fileno(FH)); | |
1d7e3124 | 42 | my $cmpimg = Imager::File::PNG::i_readpng_wiol($IO); |
37a9be8e TC |
43 | close(FH); |
44 | ok($cmpimg, "read png"); | |
45 | ||
46 | print "# png average mean square pixel difference: ",sqrt(i_img_diff($img,$cmpimg))/150*150,"\n"; | |
47 | is(i_img_diff($img, $cmpimg), 0, "compare saved and original images"); | |
48 | ||
49 | my %tags = map { Imager::i_tags_get($cmpimg, $_) } | |
50 | 0..Imager::i_tags_count($cmpimg) - 1; | |
51 | ok(abs($tags{i_xres} - 300) < 1, "i_xres: $tags{i_xres}"); | |
52 | ok(abs($tags{i_yres} - 200) < 1, "i_yres: $tags{i_yres}"); | |
53 | is($tags{i_format}, "png", "i_format: $tags{i_format}"); | |
54 | ||
55 | open FH, "> testout/t102_trans.png" | |
56 | or die "Cannot open testout/t102_trans.png: $!"; | |
57 | binmode FH; | |
58 | $IO = Imager::io_new_fd(fileno(FH)); | |
1d7e3124 | 59 | ok(Imager::File::PNG::i_writepng_wiol($timg, $IO), "write tranparent"); |
37a9be8e TC |
60 | close FH; |
61 | ||
62 | open FH,"testout/t102_trans.png" | |
63 | or die "cannot open testout/t102_trans.png\n"; | |
64 | binmode(FH); | |
65 | $IO = Imager::io_new_fd(fileno(FH)); | |
1d7e3124 | 66 | $cmpimg = Imager::File::PNG::i_readpng_wiol($IO); |
37a9be8e TC |
67 | ok($cmpimg, "read transparent"); |
68 | close(FH); | |
69 | ||
70 | print "# png average mean square pixel difference: ",sqrt(i_img_diff($timg,$cmpimg))/150*150,"\n"; | |
71 | is(i_img_diff($timg, $cmpimg), 0, "compare saved and original transparent"); | |
72 | ||
73 | # REGRESSION TEST | |
74 | # png.c 1.1 would produce an incorrect image when loading images with | |
75 | # less than 8 bits/pixel with a transparent palette entry | |
76 | open FH, "< testimg/palette.png" | |
77 | or die "cannot open testimg/palette.png: $!\n"; | |
78 | binmode FH; | |
79 | $IO = Imager::io_new_fd(fileno(FH)); | |
80 | # 1.1 may segfault here (it does with libefence) | |
1d7e3124 | 81 | my $pimg = Imager::File::PNG::i_readpng_wiol($IO); |
37a9be8e TC |
82 | ok($pimg, "read transparent paletted image"); |
83 | close FH; | |
84 | ||
85 | open FH, "< testimg/palette_out.png" | |
86 | or die "cannot open testimg/palette_out.png: $!\n"; | |
87 | binmode FH; | |
88 | $IO = Imager::io_new_fd(fileno(FH)); | |
1d7e3124 | 89 | my $poimg = Imager::File::PNG::i_readpng_wiol($IO); |
37a9be8e TC |
90 | ok($poimg, "read palette_out image"); |
91 | close FH; | |
92 | if (!is(i_img_diff($pimg, $poimg), 0, "images the same")) { | |
93 | print <<EOS; | |
d8bbe40d TC |
94 | # this tests a bug in Imager's png.c v1.1 |
95 | # if also tickles a bug in libpng before 1.0.5, so you may need to | |
96 | # upgrade libpng | |
97 | EOS | |
37a9be8e TC |
98 | } |
99 | ||
100 | { # check file limits are checked | |
101 | my $limit_file = "testout/t102.png"; | |
102 | ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149"); | |
103 | my $im = Imager->new; | |
104 | ok(!$im->read(file=>$limit_file), | |
105 | "should fail read due to size limits"); | |
106 | print "# ",$im->errstr,"\n"; | |
107 | like($im->errstr, qr/image width/, "check message"); | |
108 | ||
109 | ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149"); | |
110 | ok(!$im->read(file=>$limit_file), | |
111 | "should fail read due to size limits"); | |
112 | print "# ",$im->errstr,"\n"; | |
113 | like($im->errstr, qr/image height/, "check message"); | |
114 | ||
115 | ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150"); | |
116 | ok($im->read(file=>$limit_file), | |
117 | "should succeed - just inside width limit"); | |
118 | ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150"); | |
119 | ok($im->read(file=>$limit_file), | |
120 | "should succeed - just inside height limit"); | |
121 | ||
122 | # 150 x 150 x 3 channel image uses 67500 bytes | |
123 | ok(Imager->set_file_limits(reset=>1, bytes=>67499), | |
124 | "set bytes limit 67499"); | |
125 | ok(!$im->read(file=>$limit_file), | |
77157728 | 126 | "should fail - too many bytes"); |
37a9be8e | 127 | print "# ",$im->errstr,"\n"; |
77157728 | 128 | like($im->errstr, qr/storage size/, "check error message"); |
37a9be8e TC |
129 | ok(Imager->set_file_limits(reset=>1, bytes=>67500), |
130 | "set bytes limit 67500"); | |
131 | ok($im->read(file=>$limit_file), | |
132 | "should succeed - just inside bytes limit"); | |
133 | Imager->set_file_limits(reset=>1); | |
134 | } | |
e7ff1cf7 | 135 | |
37a9be8e TC |
136 | { # check if the read_multi fallback works |
137 | my @imgs = Imager->read_multi(file => 'testout/t102.png'); | |
138 | is(@imgs, 1, "check the image was loaded"); | |
139 | is(i_img_diff($img, $imgs[0]), 0, "check image matches"); | |
140 | ||
141 | # check the write_multi fallback | |
142 | ok(Imager->write_multi({ file => 'testout/t102m.png', type => 'png' }, | |
143 | @imgs), | |
144 | 'test write_multi() callback'); | |
145 | ||
146 | # check that we fail if we actually write 2 | |
147 | ok(!Imager->write_multi({ file => 'testout/t102m.png', type => 'png' }, | |
e7ff1cf7 | 148 | @imgs, @imgs), |
37a9be8e TC |
149 | 'test write_multi() callback failure'); |
150 | } | |
f245645a | 151 | |
6d5c85a2 TC |
152 | { # check close failures are handled correctly |
153 | my $im = test_image(); | |
154 | my $fail_close = sub { | |
155 | Imager::i_push_error(0, "synthetic close failure"); | |
156 | return 0; | |
157 | }; | |
158 | ok(!$im->write(type => "png", callback => sub { 1 }, | |
159 | closecb => $fail_close), | |
160 | "check failing close fails"); | |
161 | like($im->errstr, qr/synthetic close failure/, | |
162 | "check error message"); | |
163 | } | |
164 | ||
37a9be8e TC |
165 | { |
166 | ok(grep($_ eq 'png', Imager->read_types), "check png in read types"); | |
167 | ok(grep($_ eq 'png', Imager->write_types), "check png in write types"); | |
1cdc4cbd | 168 | } |
37a9be8e | 169 | |
38eab175 TC |
170 | { # read error reporting |
171 | my $im = Imager->new; | |
172 | ok(!$im->read(file => "testimg/badcrc.png", type => "png"), | |
173 | "read png with bad CRC chunk should fail"); | |
174 | is($im->errstr, "IHDR: CRC error", "check error message"); | |
175 | } | |
176 | ||
177 | { # write error reporting | |
178 | my $im = test_image(); | |
179 | ok(!$im->write(type => "png", callback => limited_write(1), buffered => 0), | |
180 | "write limited to 1 byte should fail"); | |
181 | is($im->errstr, "Write error on an iolayer source.: limit reached", | |
182 | "check error message"); | |
183 | } | |
184 | ||
185 | sub limited_write { | |
186 | my ($limit) = @_; | |
187 | ||
188 | return | |
189 | sub { | |
190 | my ($data) = @_; | |
191 | $limit -= length $data; | |
192 | if ($limit >= 0) { | |
193 | print "# write of ", length $data, " bytes successful ($limit left)\n" if $debug_writes; | |
194 | return 1; | |
195 | } | |
196 | else { | |
197 | print "# write of ", length $data, " bytes failed\n"; | |
198 | Imager::i_push_error(0, "limit reached"); | |
199 | return; | |
200 | } | |
201 | }; | |
202 | } |