5 use vars qw(@ISA @EXPORT_OK);
7 @EXPORT_OK = qw(diff_text_with_nul
8 test_image_raw test_image_16 test_image test_image_double
9 is_color3 is_color1 is_color4 is_color_close3
11 is_image is_image_similar
12 image_bounds_checks mask_tests
13 test_colorf_gpix test_color_gpix test_colorf_glin);
15 sub diff_text_with_nul {
16 my ($desc, $text1, $text2, @params) = @_;
18 my $builder = Test::Builder->new;
21 my $imbase = Imager->new(xsize => 100, ysize => 100);
22 my $imcopy = Imager->new(xsize => 100, ysize => 100);
24 $builder->ok($imbase->string(x => 5, 'y' => 50, size => 20,
26 @params), "$desc - draw text1");
27 $builder->ok($imcopy->string(x => 5, 'y' => 50, size => 20,
29 @params), "$desc - draw text2");
30 $builder->isnt_num(Imager::i_img_diff($imbase->{IMG}, $imcopy->{IMG}), 0,
31 "$desc - check result different");
34 sub is_color3($$$$$) {
35 my ($color, $red, $green, $blue, $comment) = @_;
37 my $builder = Test::Builder->new;
39 unless (defined $color) {
40 $builder->ok(0, $comment);
41 $builder->diag("color is undef");
44 unless ($color->can('rgba')) {
45 $builder->ok(0, $comment);
46 $builder->diag("color is not a color object");
50 my ($cr, $cg, $cb) = $color->rgba;
51 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue, $comment)) {
52 $builder->diag(<<END_DIAG);
64 sub is_color_close3($$$$$$) {
65 my ($color, $red, $green, $blue, $tolerance, $comment) = @_;
67 my $builder = Test::Builder->new;
69 unless (defined $color) {
70 $builder->ok(0, $comment);
71 $builder->diag("color is undef");
74 unless ($color->can('rgba')) {
75 $builder->ok(0, $comment);
76 $builder->diag("color is not a color object");
80 my ($cr, $cg, $cb) = $color->rgba;
81 unless ($builder->ok(abs($cr - $red) <= $tolerance
82 && abs($cg - $green) <= $tolerance
83 && abs($cb - $blue) <= $tolerance, $comment)) {
84 $builder->diag(<<END_DIAG);
85 Color out of tolerance ($tolerance):
86 Red: expected $red vs received $cr
87 Green: expected $green vs received $cg
88 Blue: expected $blue vs received $cb
96 sub is_color4($$$$$$) {
97 my ($color, $red, $green, $blue, $alpha, $comment) = @_;
99 my $builder = Test::Builder->new;
101 unless (defined $color) {
102 $builder->ok(0, $comment);
103 $builder->diag("color is undef");
106 unless ($color->can('rgba')) {
107 $builder->ok(0, $comment);
108 $builder->diag("color is not a color object");
112 my ($cr, $cg, $cb, $ca) = $color->rgba;
113 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue
114 && $ca == $alpha, $comment)) {
115 $builder->diag(<<END_DIAG);
128 sub is_fcolor4($$$$$$;$) {
129 my ($color, $red, $green, $blue, $alpha, $comment_or_diff, $comment_or_undef) = @_;
130 my ($comment, $mindiff);
131 if (defined $comment_or_undef) {
132 ( $mindiff, $comment ) = ( $comment_or_diff, $comment_or_undef )
135 ( $mindiff, $comment ) = ( 0.001, $comment_or_diff )
138 my $builder = Test::Builder->new;
140 unless (defined $color) {
141 $builder->ok(0, $comment);
142 $builder->diag("color is undef");
145 unless ($color->can('rgba')) {
146 $builder->ok(0, $comment);
147 $builder->diag("color is not a color object");
151 my ($cr, $cg, $cb, $ca) = $color->rgba;
152 unless ($builder->ok(abs($cr - $red) <= $mindiff
153 && abs($cg - $green) <= $mindiff
154 && abs($cb - $blue) <= $mindiff
155 && abs($ca - $alpha) <= $mindiff, $comment)) {
156 $builder->diag(<<END_DIAG);
170 my ($color, $grey, $comment) = @_;
172 my $builder = Test::Builder->new;
174 unless (defined $color) {
175 $builder->ok(0, $comment);
176 $builder->diag("color is undef");
179 unless ($color->can('rgba')) {
180 $builder->ok(0, $comment);
181 $builder->diag("color is not a color object");
185 my ($cgrey) = $color->rgba;
186 unless ($builder->ok($cgrey == $grey, $comment)) {
187 $builder->diag(<<END_DIAG);
189 Grey: $grey vs $cgrey
198 my $green=Imager::i_color_new(0,255,0,255);
199 my $blue=Imager::i_color_new(0,0,255,255);
200 my $red=Imager::i_color_new(255,0,0,255);
202 my $img=Imager::ImgRaw::new(150,150,3);
204 Imager::i_box_filled($img,70,25,130,125,$green);
205 Imager::i_box_filled($img,20,25,80,125,$blue);
206 Imager::i_arc($img,75,75,30,0,361,$red);
207 Imager::i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
213 my $green = Imager::Color->new(0, 255, 0, 255);
214 my $blue = Imager::Color->new(0, 0, 255, 255);
215 my $red = Imager::Color->new(255, 0, 0, 255);
216 my $img = Imager->new(xsize => 150, ysize => 150);
217 $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]);
218 $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]);
219 $img->arc(x => 75, y => 75, r => 30, color => $red);
220 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
226 my $green = Imager::Color->new(0, 255, 0, 255);
227 my $blue = Imager::Color->new(0, 0, 255, 255);
228 my $red = Imager::Color->new(255, 0, 0, 255);
229 my $img = Imager->new(xsize => 150, ysize => 150, bits => 16);
230 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
231 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
232 $img->arc(x => 75, y => 75, r => 30, color => $red);
233 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
238 sub test_image_double {
239 my $green = Imager::Color->new(0, 255, 0, 255);
240 my $blue = Imager::Color->new(0, 0, 255, 255);
241 my $red = Imager::Color->new(255, 0, 0, 255);
242 my $img = Imager->new(xsize => 150, ysize => 150, bits => 'double');
243 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
244 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
245 $img->arc(x => 75, y => 75, r => 30, color => $red);
246 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
251 sub is_image_similar($$$$) {
252 my ($left, $right, $limit, $comment) = @_;
254 my $builder = Test::Builder->new;
256 unless (defined $left) {
257 $builder->ok(0, $comment);
258 $builder->diag("left is undef");
261 unless (defined $right) {
262 $builder->ok(0, $comment);
263 $builder->diag("right is undef");
266 unless ($left->{IMG}) {
267 $builder->ok(0, $comment);
268 $builder->diag("left image has no low level object");
271 unless ($right->{IMG}) {
272 $builder->ok(0, $comment);
273 $builder->diag("right image has no low level object");
276 unless ($left->getwidth == $right->getwidth) {
277 $builder->ok(0, $comment);
278 $builder->diag("left width " . $left->getwidth . " vs right width "
282 unless ($left->getheight == $right->getheight) {
283 $builder->ok(0, $comment);
284 $builder->diag("left height " . $left->getheight . " vs right height "
285 . $right->getheight);
288 unless ($left->getchannels == $right->getchannels) {
289 $builder->ok(0, $comment);
290 $builder->diag("left channels " . $left->getchannels . " vs right channels "
291 . $right->getchannels);
294 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
295 if ($diff > $limit) {
296 $builder->ok(0, $comment);
297 $builder->diag("image data difference > $limit - $diff");
300 # find the first mismatch
302 for my $y (0 .. $left->getheight()-1) {
303 for my $x (0.. $left->getwidth()-1) {
304 my @lsamples = $left->getsamples(x => $x, y => $y, width => 1);
305 my @rsamples = $right->getsamples(x => $x, y => $y, width => 1);
306 if ("@lsamples" ne "@rsamples") {
307 $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples");
317 return $builder->ok(1, $comment);
321 my ($left, $right, $comment) = @_;
323 local $Test::Builder::Level = $Test::Builder::Level + 1;
325 return is_image_similar($left, $right, 0, $comment);
328 sub image_bounds_checks {
331 my $builder = Test::Builder->new;
333 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0)');
334 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0)');
335 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1)');
336 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10)');
337 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0) float');
338 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0) float');
339 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1) float');
340 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10) float');
341 my $black = Imager::Color->new(0, 0, 0);
342 require Imager::Color::Float;
343 my $blackf = Imager::Color::Float->new(0, 0, 0);
344 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $black), 'bounds check set (-1, 0)');
345 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $black), 'bounds check set (10, 0)');
346 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $black), 'bounds check set (0, -1)');
347 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $black), 'bounds check set (0, 10)');
348 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $blackf), 'bounds check set (-1, 0) float');
349 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $blackf), 'bounds check set (10, 0) float');
350 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $blackf), 'bounds check set (0, -1) float');
351 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $blackf), 'bounds check set (0, 10) float');
354 sub test_colorf_gpix {
355 my ($im, $x, $y, $expected, $epsilon, $comment) = @_;
357 my $builder = Test::Builder->new;
359 defined $comment or $comment = '';
361 my $c = Imager::i_gpixf($im, $x, $y);
363 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
366 unless ($builder->ok(_colorf_cmp($c, $expected, $epsilon) == 0,
367 "$comment - got right color ($x, $y)")) {
368 print "# got: (", join(",", ($c->rgba)[0,1,2]), ")\n";
369 print "# expected: (", join(",", ($expected->rgba)[0,1,2]), ")\n";
375 sub test_color_gpix {
376 my ($im, $x, $y, $expected, $comment) = @_;
378 my $builder = Test::Builder->new;
380 defined $comment or $comment = '';
381 my $c = Imager::i_get_pixel($im, $x, $y);
383 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
386 unless ($builder->ok(_color_cmp($c, $expected) == 0,
387 "got right color ($x, $y)")) {
388 print "# got: (", join(",", ($c->rgba)[0,1,2]), ")\n";
389 print "# expected: (", join(",", ($expected->rgba)[0,1,2]), ")\n";
396 sub test_colorf_glin {
397 my ($im, $x, $y, $pels, $comment) = @_;
399 my $builder = Test::Builder->new;
401 my @got = Imager::i_glinf($im, $x, $x+@$pels, $y);
403 or return $builder->is_num(scalar(@got), scalar(@$pels), "$comment - pixels retrieved");
405 return $builder->ok(!grep(_colorf_cmp($pels->[$_], $got[$_], 0.005), 0..$#got),
406 "$comment - check colors ($x, $y)");
410 my ($c1, $c2, $epsilon) = @_;
412 defined $epsilon or $epsilon = 0;
417 # print "# (",join(",", @s1[0..2]),") <=> (",join(",", @s2[0..2]),")\n";
418 return abs($s1[0]-$s2[0]) >= $epsilon && $s1[0] <=> $s2[0]
419 || abs($s1[1]-$s2[1]) >= $epsilon && $s1[1] <=> $s2[1]
420 || abs($s1[2]-$s2[2]) >= $epsilon && $s1[2] <=> $s2[2];
429 return $s1[0] <=> $s2[0]
431 || $s1[2] <=> $s2[2];
434 # these test the action of the channel mask on the image supplied
435 # which should be an OO image.
437 my ($im, $epsilon) = @_;
439 my $builder = Test::Builder->new;
441 defined $epsilon or $epsilon = 0;
443 # we want to check all four of ppix() and plin(), ppix() and plinf()
444 # basic test procedure:
445 # first using default/all 1s mask, set to white
446 # make sure we got white
447 # set mask to skip a channel, set to grey
448 # make sure only the right channels set
450 print "# channel mask tests\n";
452 my $white = Imager::NC(255, 255, 255);
453 my $grey = Imager::NC(128, 128, 128);
454 my $white_grey = Imager::NC(128, 255, 128);
456 print "# with ppix\n";
457 $builder->ok($im->setmask(mask=>~0), "set to default mask");
458 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$white), "set to white all channels");
459 test_color_gpix($im->{IMG}, 0, 0, $white, "ppix");
460 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
461 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$grey), "set to grey, no channel 2");
462 test_color_gpix($im->{IMG}, 0, 0, $white_grey, "ppix masked");
464 print "# with plin\n";
465 $builder->ok($im->setmask(mask=>~0), "set to default mask");
466 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels => [$white]),
467 "set to white all channels");
468 test_color_gpix($im->{IMG}, 0, 1, $white, "plin");
469 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
470 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels=>[$grey]),
471 "set to grey, no channel 2");
472 test_color_gpix($im->{IMG}, 0, 1, $white_grey, "plin masked");
475 my $whitef = Imager::NCF(1.0, 1.0, 1.0);
476 my $greyf = Imager::NCF(0.5, 0.5, 0.5);
477 my $white_greyf = Imager::NCF(0.5, 1.0, 0.5);
479 print "# with ppixf\n";
480 $builder->ok($im->setmask(mask=>~0), "set to default mask");
481 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$whitef), "set to white all channels");
482 test_colorf_gpix($im->{IMG}, 0, 2, $whitef, $epsilon, "ppixf");
483 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
484 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$greyf), "set to grey, no channel 2");
485 test_colorf_gpix($im->{IMG}, 0, 2, $white_greyf, $epsilon, "ppixf masked");
487 print "# with plinf\n";
488 $builder->ok($im->setmask(mask=>~0), "set to default mask");
489 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels => [$whitef]),
490 "set to white all channels");
491 test_colorf_gpix($im->{IMG}, 0, 3, $whitef, $epsilon, "plinf");
492 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
493 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels=>[$greyf]),
494 "set to grey, no channel 2");
495 test_colorf_gpix($im->{IMG}, 0, 3, $white_greyf, $epsilon, "plinf masked");
505 Imager::Test - common functions used in testing Imager
509 use Imager::Test 'diff_text_with_nul';
510 diff_text_with_nul($test_name, $text1, $text2, @string_options);
514 This is a repository of functions used in testing Imager.
516 Some functions will only be useful in testing Imager itself, while
517 others should be useful in testing modules that use Imager.
519 No functions are exported by default.
525 =item is_color3($color, $red, $blue, $green, $comment)
527 Tests is $color matches the given ($red, $blue, $green)
529 =item is_image($im1, $im2, $comment)
531 Tests if the 2 images have the same content. Both images must be
532 defined, have the same width, height, channels and the same color in
533 each pixel. The color comparison is done at 8-bits per pixel. The
534 color representation such as direct vs paletted, bits per sample are
535 not checked. Equivalent to is_image_similar($im1, $im2, 0, $comment).
537 =item is_image_similar($im1, $im2, $maxdiff, $comment)
539 Tests if the 2 images have similar content. Both images must be
540 defined, have the same width, height and channels. The cum of the
541 squares of the differences of each sample are calculated and must be
542 less than or equal to I<$maxdiff> for the test to pass. The color
543 comparison is done at 8-bits per pixel. The color representation such
544 as direct vs paletted, bits per sample are not checked.
546 =item test_image_raw()
548 Returns a 150x150x3 Imager::ImgRaw test image.
552 Returns a 150x150x3 8-bit/sample OO test image.
554 =item test_image_16()
556 Returns a 150x150x3 16-bit/sample OO test image.
558 =item test_image_double()
560 Returns a 150x150x3 double/sample OO test image.
562 =item diff_text_with_nul($test_name, $text1, $text2, @options)
564 Creates 2 test images and writes $text1 to the first image and $text2
565 to the second image with the string() method. Each call adds 3 ok/not
566 ok to the output of the test script.
568 Extra options that should be supplied include the font and either a
569 color or channel parameter.
571 This was explicitly created for regression tests on #21770.
573 =item image_bounds_checks($im)
575 Attempts to write to various pixel positions outside the edge of the
576 image to ensure that it fails in those locations.
578 Any new image type should pass these tests. Does 16 separate tests.
580 =item test_colorf_gpix($im, $x, $y, $expected, $epsilon, $comment)
582 Retrieves the pixel ($x,$y) from the low-level image $im and compares
583 it to the floating point color $expected, with a tolerance of epsilon.
585 =item test_color_gpix($im, $x, $y, $expected, $comment)
587 Retrieves the pixel ($x,$y) from the low-level image $im and compares
588 it to the floating point color $expected.
590 =item test_colorf_glin($im, $x, $y, $pels, $comment)
592 Retrieves the floating point pixels ($x, $y)-[$x+@$pels, $y] from the
593 low level image $im and compares them against @$pels.
595 =item mask_tests($im, $epsilon)
597 Perform a standard set of mask tests on the OO image $im.
603 Tony Cook <tony@develop-help.com>