2 # some of this is tested in t01introvert.t too
4 use Test::More tests => 126;
5 BEGIN { use_ok("Imager"); }
7 use Imager::Test qw(image_bounds_checks test_image is_color3);
11 my $img = Imager->new(xsize=>50, ysize=>50, type=>'paletted');
13 ok($img, "paletted image created");
15 is($img->type, 'paletted', "got a paletted image");
17 my $black = Imager::Color->new(0,0,0);
18 my $red = Imager::Color->new(255,0,0);
19 my $green = Imager::Color->new(0,255,0);
20 my $blue = Imager::Color->new(0,0,255);
22 my $white = Imager::Color->new(255,255,255);
25 my $blacki = $img->addcolors(colors=>[ $black, $red, $green, $blue ]);
27 print "# blacki $blacki\n";
28 ok(defined $blacki && $blacki == 0, "we got the first color");
30 ok($img->colorcount() == 4, "should have 4 colors");
31 my ($redi, $greeni, $bluei) = 1..3;
33 my @all = $img->getcolors;
34 ok(@all == 4, "all colors is 4");
35 coloreq($all[0], $black, "first black");
36 coloreq($all[1], $red, "then red");
37 coloreq($all[2], $green, "then green");
38 coloreq($all[3], $blue, "and finally blue");
40 # keep this as an assignment, checking for scalar context
41 # we don't want the last color, otherwise if the behaviour changes to
42 # get all up to the last (count defaulting to size-index) we'd get a
44 my $one_color = $img->getcolors(start=>$redi);
45 ok($one_color->isa('Imager::Color'), "check scalar context");
46 coloreq($one_color, $red, "and that it's what we want");
48 # make sure we can find colors
49 ok(!defined($img->findcolor(color=>$white)),
50 "shouldn't be able to find white");
51 ok($img->findcolor(color=>$black) == $blacki, "find black");
52 ok($img->findcolor(color=>$red) == $redi, "find red");
53 ok($img->findcolor(color=>$green) == $greeni, "find green");
54 ok($img->findcolor(color=>$blue) == $bluei, "find blue");
56 # various failure tests for setcolors
57 ok(!defined($img->setcolors(start=>-1, colors=>[$white])),
58 "expect failure: low index");
59 ok(!defined($img->setcolors(start=>1, colors=>[])),
60 "expect failure: no colors");
61 ok(!defined($img->setcolors(start=>5, colors=>[$white])),
62 "expect failure: high index");
64 # set the green index to white
65 ok($img->setcolors(start => $greeni, colors => [$white]),
68 coloreq(scalar($img->getcolors(start=>$greeni)), $white,
69 "make sure it was set");
70 ok($img->findcolor(color=>$white) == $greeni, "and that we can find it");
71 ok(!defined($img->findcolor(color=>$green)), "and can't find the old color");
74 ok(scalar($img->setcolors(start=>$redi, colors=>[ $green, $red])),
76 coloreq(scalar($img->getcolors(start=>$redi)), $green, "first of multiple");
77 coloreq(scalar($img->getcolors(start=>$greeni)), $red, "second of multiple");
80 $img->setcolors(start=>$red, colors=>[$red, $green]);
82 # draw on the image, make sure it stays paletted when it should
83 ok($img->box(color=>$red, filled=>1), "fill with red");
84 is($img->type, 'paletted', "paletted after fill");
85 ok($img->box(color=>$green, filled=>1, xmin=>10, ymin=>10,
86 xmax=>40, ymax=>40), "green box");
87 is($img->type, 'paletted', 'still paletted after box');
88 # an AA line will almost certainly convert the image to RGB, don't use
90 ok($img->line(color=>$blue, x1=>10, y1=>10, x2=>40, y2=>40),
92 is($img->type, 'paletted', 'still paletted after line');
94 # draw with white - should convert to direct
95 ok($img->box(color=>$white, filled=>1, xmin=>20, ymin=>20,
96 xmax=>30, ymax=>30), "white box");
97 is($img->type, 'direct', "now it should be direct");
99 # various attempted to make a paletted image from our now direct image
100 my $palimg = $img->to_paletted;
101 ok($palimg, "we got an image");
102 # they should be the same pixel for pixel
103 ok(Imager::i_img_diff($img->{IMG}, $palimg->{IMG}) == 0, "same pixels");
105 # strange case: no color picking, and no colors
106 # this was causing a segmentation fault
107 $palimg = $img->to_paletted(colors=>[ ], make_colors=>'none');
108 ok(!defined $palimg, "to paletted with an empty palette is an error");
109 print "# ",$img->errstr,"\n";
110 ok(scalar($img->errstr =~ /no colors available for translation/),
111 "and got the correct msg");
113 ok(!Imager->new(xsize=>1, ysize=>-1, type=>'paletted'),
114 "fail on -ve height");
115 cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/,
116 "and correct error message");
117 ok(!Imager->new(xsize=>-1, ysize=>1, type=>'paletted'),
118 "fail on -ve width");
119 cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/,
120 "and correct error message");
121 ok(!Imager->new(xsize=>-1, ysize=>-1, type=>'paletted'),
122 "fail on -ve width/height");
123 cmp_ok(Imager->errstr, '=~', qr/Image sizes must be positive/,
124 "and correct error message");
126 ok(!Imager->new(xsize=>1, ysize=>1, type=>'paletted', channels=>0),
127 "fail on 0 channels");
128 cmp_ok(Imager->errstr, '=~', qr/Channels must be positive and <= 4/,
129 "and correct error message");
130 ok(!Imager->new(xsize=>1, ysize=>1, type=>'paletted', channels=>5),
131 "fail on 5 channels");
132 cmp_ok(Imager->errstr, '=~', qr/Channels must be positive and <= 4/,
133 "and correct error message");
136 # https://rt.cpan.org/Ticket/Display.html?id=8213
137 # check for handling of memory allocation of very large images
138 # only test this on 32-bit machines - on a 64-bit machine it may
139 # result in trying to allocate 4Gb of memory, which is unfriendly at
140 # least and may result in running out of memory, causing a different
145 skip("don't want to allocate 4Gb", 10)
146 unless $Config{intsize} == 4;
148 my $uint_range = 256 ** $Config{intsize};
149 my $dim1 = int(sqrt($uint_range))+1;
151 my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, type=>'paletted');
152 is($im_b, undef, "integer overflow check - 1 channel");
154 $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, type=>'paletted');
155 ok($im_b, "but same width ok");
156 $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, type=>'paletted');
157 ok($im_b, "but same height ok");
158 cmp_ok(Imager->errstr, '=~', qr/integer overflow/,
159 "check the error message");
161 # do a similar test with a 3 channel image, so we're sure we catch
162 # the same case where the third dimension causes the overflow
163 # for paletted images the third dimension can't cause an overflow
164 # but make sure we didn't anything too dumb in the checks
167 $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, type=>'paletted');
168 is($im_b, undef, "integer overflow check - 3 channel");
170 $im_b = Imager->new(xsize=>$dim3, ysize=>1, channels=>3, type=>'paletted');
171 ok($im_b, "but same width ok");
172 $im_b = Imager->new(xsize=>1, ysize=>$dim3, channels=>3, type=>'paletted');
173 ok($im_b, "but same height ok");
175 cmp_ok(Imager->errstr, '=~', qr/integer overflow/,
176 "check the error message");
178 # test the scanline allocation check
179 # divide by 2 to get int range, by 3 so that the image (one byte/pixel)
180 # doesn't integer overflow, but the scanline of i_color (4/pixel) does
181 my $dim4 = $uint_range / 2 / 3;
182 my $im_o = Imager->new(xsize=>$dim4, ysize=>1, channels=>3, type=>'paletted');
183 is($im_o, undef, "integer overflow check - scanline size");
184 cmp_ok(Imager->errstr, '=~',
185 qr/integer overflow calculating scanline allocation/,
186 "check error message");
190 { # http://rt.cpan.org/NoAuth/Bug.html?id=9672
192 local $SIG{__WARN__} =
195 my $printed = $warning;
197 $printed =~ s/\n/\n\#/g;
198 print "# ",$printed, "\n";
200 my $img = Imager->new(xsize=>10, ysize=>10);
202 cmp_ok($warning, '=~', 'void', "correct warning");
203 cmp_ok($warning, '=~', 't023palette\\.t', "correct file");
206 { # http://rt.cpan.org/NoAuth/Bug.html?id=12676
207 # setcolors() has a fencepost error
208 my $img = Imager->new(xsize=>10, ysize=>10, type=>'paletted');
210 is($img->addcolors(colors=>[ $black, $red ]), "0 but true",
212 ok($img->setcolors(start=>1, colors=>[ $green ]), "set the last color");
213 ok(!$img->setcolors(start=>2, colors=>[ $black ]),
214 "set after the last color");
217 { # https://rt.cpan.org/Ticket/Display.html?id=20056
218 # added named color support to addcolor/setcolor
219 my $img = Imager->new(xsize => 10, ysize => 10, type => 'paletted');
220 is($img->addcolors(colors => [ qw/000000 FF0000/ ]), "0 but true",
221 "add colors as strings instead of objects");
222 my @colors = $img->getcolors;
223 iscolor($colors[0], $black, "check first color");
224 iscolor($colors[1], $red, "check second color");
225 ok($img->setcolors(colors => [ qw/00FF00 0000FF/ ]),
226 "setcolors as strings instead of objects");
227 @colors = $img->getcolors;
228 iscolor($colors[0], $green, "check first color");
229 iscolor($colors[1], $blue, "check second color");
231 # make sure we handle bad colors correctly
232 is($img->colorcount, 2, "start from a known state");
233 is($img->addcolors(colors => [ 'XXFGXFXGXFX' ]), undef,
234 "fail to add unknown color");
235 is($img->errstr, 'No color named XXFGXFXGXFX found', 'check error message');
236 is($img->setcolors(colors => [ 'XXFGXFXGXFXZ' ]), undef,
237 "fail to set to unknown color");
238 is($img->errstr, 'No color named XXFGXFXGXFXZ found', 'check error message');
241 { # https://rt.cpan.org/Ticket/Display.html?id=20338
242 # OO interface to i_glin/i_plin
243 my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted');
244 is($im->addcolors(colors => [ "#000", "#F00", "#0F0", "#00F" ]), "0 but true",
245 "add some test colors")
246 or print "# ", $im->errstr, "\n";
247 # set a pixel to check
248 $im->setpixel(x => 1, 'y' => 0, color => "#0F0");
249 is_deeply([ $im->getscanline('y' => 0, type=>'index') ],
250 [ 0, 2, (0) x 8 ], "getscanline index in list context");
251 isbin($im->getscanline('y' => 0, type=>'index'),
252 "\x00\x02" . "\x00" x 8,
253 "getscanline index in scalar context");
254 is($im->setscanline('y' => 0, pixels => [ 1, 2, 0, 3 ], type => 'index'),
255 4, "setscanline with list");
256 is($im->setscanline('y' => 0, x => 4, pixels => pack("C*", 3, 2, 1, 0, 3),
258 5, "setscanline with pv");
259 is_deeply([ $im->getscanline(type => 'index', 'y' => 0) ],
260 [ 1, 2, 0, 3, 3, 2, 1, 0, 3, 0 ],
262 eval { # should croak on OOR index
263 $im->setscanline('y' => 1, pixels => [ 255 ], type=>'index');
265 ok($@, "croak on setscanline() to invalid index");
266 eval { # same again with pv
267 $im->setscanline('y' => 1, pixels => "\xFF", type => 'index');
269 ok($@, "croak on setscanline() with pv to invalid index");
273 print "# make_colors => mono\n";
274 # test mono make_colors
275 my $imrgb = Imager->new(xsize => 10, ysize => 10);
276 $imrgb->setpixel(x => 0, 'y' => 0, color => '#FFF');
277 $imrgb->setpixel(x => 1, 'y' => 0, color => '#FF0');
278 $imrgb->setpixel(x => 2, 'y' => 0, color => '#000');
279 my $mono = $imrgb->to_paletted(make_colors => 'mono',
280 translate => 'closest');
281 is($mono->type, 'paletted', "check we get right image type");
282 is($mono->colorcount, 2, "only 2 colors");
283 my ($is_mono, $ziw) = $mono->is_bilevel;
284 ok($is_mono, "check monochrome check true");
285 is($ziw, 0, "check ziw false");
286 my @colors = $mono->getcolors;
287 iscolor($colors[0], $black, "check first entry");
288 iscolor($colors[1], $white, "check second entry");
289 my @pixels = $mono->getscanline(x => 0, 'y' => 0, width => 3, type=>'index');
290 is($pixels[0], 1, "check white pixel");
291 is($pixels[1], 1, "check yellow pixel");
292 is($pixels[2], 0, "check black pixel");
295 { # check for the various mono images we accept
296 my $mono_8_bw_3 = Imager->new(xsize => 2, ysize => 2, channels => 3,
298 ok($mono_8_bw_3->addcolors(colors => [ qw/000000 FFFFFF/ ]),
299 "mono8bw3 - add colors");
300 ok($mono_8_bw_3->is_bilevel, "it's mono");
301 is(($mono_8_bw_3->is_bilevel)[1], 0, 'zero not white');
303 my $mono_8_wb_3 = Imager->new(xsize => 2, ysize => 2, channels => 3,
305 ok($mono_8_wb_3->addcolors(colors => [ qw/FFFFFF 000000/ ]),
306 "mono8wb3 - add colors");
307 ok($mono_8_wb_3->is_bilevel, "it's mono");
308 is(($mono_8_wb_3->is_bilevel)[1], 1, 'zero is white');
310 my $mono_8_bw_1 = Imager->new(xsize => 2, ysize => 2, channels => 1,
312 ok($mono_8_bw_1->addcolors(colors => [ qw/000000 FFFFFF/ ]),
313 "mono8bw - add colors");
314 ok($mono_8_bw_1->is_bilevel, "it's mono");
315 is(($mono_8_bw_1->is_bilevel)[1], 0, 'zero not white');
317 my $mono_8_wb_1 = Imager->new(xsize => 2, ysize => 2, channels => 1,
319 ok($mono_8_wb_1->addcolors(colors => [ qw/FFFFFF 000000/ ]),
320 "mono8wb - add colors");
321 ok($mono_8_wb_1->is_bilevel, "it's mono");
322 is(($mono_8_wb_1->is_bilevel)[1], 1, 'zero is white');
325 { # check bounds checking
326 my $im = Imager->new(xsize => 10, ysize => 10, type=>'paletted');
327 ok($im->addcolors(colors => [ $black ]), "add color of pixel bounds check writes");
329 image_bounds_checks($im);
332 { # test colors array returns colors
334 my $im = test_image();
336 my $imp = $im->to_paletted(colors => \@colors,
337 make_colors => 'webmap',
338 translate => 'closest');
339 ok($imp, "made paletted");
340 is(@colors, 216, "should be 216 colors in the webmap");
341 is_color3($colors[0], 0, 0, 0, "first should be 000000");
342 is_color3($colors[1], 0, 0, 0x33, "second should be 000033");
343 is_color3($colors[8], 0, 0x33, 0x66, "9th should be 003366");
347 my ($c1, $c2, $msg) = @_;
349 my $builder = Test::Builder->new;
352 if (!$builder->ok($c1[0] == $c2[0] && $c1[1] == $c2[1] && $c1[2] == $c2[2],
354 $builder->diag(<<DIAG);
356 expected color: [ @c2 ]
362 my ($got, $expected, $msg) = @_;
364 my $builder = Test::Builder->new;
365 if (!$builder->ok($got eq $expected, $msg)) {
366 (my $got_dec = $got) =~ s/([^ -~])/sprintf("\\x%02x", ord $1)/ge;
367 (my $exp_dec = $expected) =~ s/([^ -~])/sprintf("\\x%02x", ord $1)/ge;
368 $builder->diag(<<DIAG);
376 my ($left, $right, $comment) = @_;
378 my ($rl, $gl, $bl, $al) = $left->rgba;
379 my ($rr, $gr, $br, $ar) = $right->rgba;
381 print "# comparing color($rl,$gl,$bl,$al) with ($rr,$gr,$br,$ar)\n";
382 ok($rl == $rr && $gl == $gr && $bl == $br && $al == $ar,