5 use vars qw(@ISA @EXPORT_OK $VERSION);
35 sub diff_text_with_nul {
36 my ($desc, $text1, $text2, @params) = @_;
38 my $builder = Test::Builder->new;
41 my $imbase = Imager->new(xsize => 100, ysize => 100);
42 my $imcopy = Imager->new(xsize => 100, ysize => 100);
44 $builder->ok($imbase->string(x => 5, 'y' => 50, size => 20,
46 @params), "$desc - draw text1");
47 $builder->ok($imcopy->string(x => 5, 'y' => 50, size => 20,
49 @params), "$desc - draw text2");
50 $builder->isnt_num(Imager::i_img_diff($imbase->{IMG}, $imcopy->{IMG}), 0,
51 "$desc - check result different");
54 sub is_color3($$$$$) {
55 my ($color, $red, $green, $blue, $comment) = @_;
57 my $builder = Test::Builder->new;
59 unless (defined $color) {
60 $builder->ok(0, $comment);
61 $builder->diag("color is undef");
64 unless ($color->can('rgba')) {
65 $builder->ok(0, $comment);
66 $builder->diag("color is not a color object");
70 my ($cr, $cg, $cb) = $color->rgba;
71 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue, $comment)) {
84 sub is_color_close3($$$$$$) {
85 my ($color, $red, $green, $blue, $tolerance, $comment) = @_;
87 my $builder = Test::Builder->new;
89 unless (defined $color) {
90 $builder->ok(0, $comment);
91 $builder->diag("color is undef");
94 unless ($color->can('rgba')) {
95 $builder->ok(0, $comment);
96 $builder->diag("color is not a color object");
100 my ($cr, $cg, $cb) = $color->rgba;
101 unless ($builder->ok(abs($cr - $red) <= $tolerance
102 && abs($cg - $green) <= $tolerance
103 && abs($cb - $blue) <= $tolerance, $comment)) {
104 $builder->diag(<<END_DIAG);
105 Color out of tolerance ($tolerance):
106 Red: expected $red vs received $cr
107 Green: expected $green vs received $cg
108 Blue: expected $blue vs received $cb
116 sub is_color4($$$$$$) {
117 my ($color, $red, $green, $blue, $alpha, $comment) = @_;
119 my $builder = Test::Builder->new;
121 unless (defined $color) {
122 $builder->ok(0, $comment);
123 $builder->diag("color is undef");
126 unless ($color->can('rgba')) {
127 $builder->ok(0, $comment);
128 $builder->diag("color is not a color object");
132 my ($cr, $cg, $cb, $ca) = $color->rgba;
133 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue
134 && $ca == $alpha, $comment)) {
135 $builder->diag(<<END_DIAG);
148 sub is_fcolor4($$$$$$;$) {
149 my ($color, $red, $green, $blue, $alpha, $comment_or_diff, $comment_or_undef) = @_;
150 my ($comment, $mindiff);
151 if (defined $comment_or_undef) {
152 ( $mindiff, $comment ) = ( $comment_or_diff, $comment_or_undef )
155 ( $mindiff, $comment ) = ( 0.001, $comment_or_diff )
158 my $builder = Test::Builder->new;
160 unless (defined $color) {
161 $builder->ok(0, $comment);
162 $builder->diag("color is undef");
165 unless ($color->can('rgba')) {
166 $builder->ok(0, $comment);
167 $builder->diag("color is not a color object");
171 my ($cr, $cg, $cb, $ca) = $color->rgba;
172 unless ($builder->ok(abs($cr - $red) <= $mindiff
173 && abs($cg - $green) <= $mindiff
174 && abs($cb - $blue) <= $mindiff
175 && abs($ca - $alpha) <= $mindiff, $comment)) {
176 $builder->diag(<<END_DIAG);
189 sub is_fcolor1($$$;$) {
190 my ($color, $grey, $comment_or_diff, $comment_or_undef) = @_;
191 my ($comment, $mindiff);
192 if (defined $comment_or_undef) {
193 ( $mindiff, $comment ) = ( $comment_or_diff, $comment_or_undef )
196 ( $mindiff, $comment ) = ( 0.001, $comment_or_diff )
199 my $builder = Test::Builder->new;
201 unless (defined $color) {
202 $builder->ok(0, $comment);
203 $builder->diag("color is undef");
206 unless ($color->can('rgba')) {
207 $builder->ok(0, $comment);
208 $builder->diag("color is not a color object");
212 my ($cgrey) = $color->rgba;
213 unless ($builder->ok(abs($cgrey - $grey) <= $mindiff, $comment)) {
216 Gray: $cgrey vs $grey
224 sub is_fcolor3($$$$$;$) {
225 my ($color, $red, $green, $blue, $comment_or_diff, $comment_or_undef) = @_;
226 my ($comment, $mindiff);
227 if (defined $comment_or_undef) {
228 ( $mindiff, $comment ) = ( $comment_or_diff, $comment_or_undef )
231 ( $mindiff, $comment ) = ( 0.001, $comment_or_diff )
234 my $builder = Test::Builder->new;
236 unless (defined $color) {
237 $builder->ok(0, $comment);
238 $builder->diag("color is undef");
241 unless ($color->can('rgba')) {
242 $builder->ok(0, $comment);
243 $builder->diag("color is not a color object");
247 my ($cr, $cg, $cb) = $color->rgba;
248 unless ($builder->ok(abs($cr - $red) <= $mindiff
249 && abs($cg - $green) <= $mindiff
250 && abs($cb - $blue) <= $mindiff, $comment)) {
251 $builder->diag(<<END_DIAG);
264 my ($color, $grey, $comment) = @_;
266 my $builder = Test::Builder->new;
268 unless (defined $color) {
269 $builder->ok(0, $comment);
270 $builder->diag("color is undef");
273 unless ($color->can('rgba')) {
274 $builder->ok(0, $comment);
275 $builder->diag("color is not a color object");
279 my ($cgrey) = $color->rgba;
280 unless ($builder->ok($cgrey == $grey, $comment)) {
281 $builder->diag(<<END_DIAG);
283 Grey: $grey vs $cgrey
292 my $green=Imager::i_color_new(0,255,0,255);
293 my $blue=Imager::i_color_new(0,0,255,255);
294 my $red=Imager::i_color_new(255,0,0,255);
296 my $img=Imager::ImgRaw::new(150,150,3);
298 Imager::i_box_filled($img,70,25,130,125,$green);
299 Imager::i_box_filled($img,20,25,80,125,$blue);
300 Imager::i_arc($img,75,75,30,0,361,$red);
301 Imager::i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
307 my $green = Imager::Color->new(0, 255, 0, 255);
308 my $blue = Imager::Color->new(0, 0, 255, 255);
309 my $red = Imager::Color->new(255, 0, 0, 255);
310 my $img = Imager->new(xsize => 150, ysize => 150);
311 $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]);
312 $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]);
313 $img->arc(x => 75, y => 75, r => 30, color => $red);
314 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
320 my $green = Imager::Color->new(0, 255, 0, 255);
321 my $blue = Imager::Color->new(0, 0, 255, 255);
322 my $red = Imager::Color->new(255, 0, 0, 255);
323 my $img = Imager->new(xsize => 150, ysize => 150, bits => 16);
324 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
325 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
326 $img->arc(x => 75, y => 75, r => 30, color => $red);
327 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
332 sub test_image_double {
333 my $green = Imager::Color->new(0, 255, 0, 255);
334 my $blue = Imager::Color->new(0, 0, 255, 255);
335 my $red = Imager::Color->new(255, 0, 0, 255);
336 my $img = Imager->new(xsize => 150, ysize => 150, bits => 'double');
337 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
338 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
339 $img->arc(x => 75, y => 75, r => 30, color => $red);
340 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
345 sub _low_image_diff_check {
346 my ($left, $right, $comment) = @_;
348 my $builder = Test::Builder->new;
350 unless (defined $left) {
351 $builder->ok(0, $comment);
352 $builder->diag("left is undef");
355 unless (defined $right) {
356 $builder->ok(0, $comment);
357 $builder->diag("right is undef");
360 unless ($left->{IMG}) {
361 $builder->ok(0, $comment);
362 $builder->diag("left image has no low level object");
365 unless ($right->{IMG}) {
366 $builder->ok(0, $comment);
367 $builder->diag("right image has no low level object");
370 unless ($left->getwidth == $right->getwidth) {
371 $builder->ok(0, $comment);
372 $builder->diag("left width " . $left->getwidth . " vs right width "
376 unless ($left->getheight == $right->getheight) {
377 $builder->ok(0, $comment);
378 $builder->diag("left height " . $left->getheight . " vs right height "
379 . $right->getheight);
382 unless ($left->getchannels == $right->getchannels) {
383 $builder->ok(0, $comment);
384 $builder->diag("left channels " . $left->getchannels . " vs right channels "
385 . $right->getchannels);
392 sub is_image_similar($$$$) {
393 my ($left, $right, $limit, $comment) = @_;
396 local $Test::Builder::Level = $Test::Builder::Level + 1;
398 _low_image_diff_check($left, $right, $comment)
402 my $builder = Test::Builder->new;
404 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
405 if ($diff > $limit) {
406 $builder->ok(0, $comment);
407 $builder->diag("image data difference > $limit - $diff");
410 # find the first mismatch
412 for my $y (0 .. $left->getheight()-1) {
413 for my $x (0.. $left->getwidth()-1) {
414 my @lsamples = $left->getsamples(x => $x, y => $y, width => 1);
415 my @rsamples = $right->getsamples(x => $x, y => $y, width => 1);
416 if ("@lsamples" ne "@rsamples") {
417 $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples");
427 return $builder->ok(1, $comment);
431 my ($left, $right, $comment) = @_;
433 local $Test::Builder::Level = $Test::Builder::Level + 1;
435 return is_image_similar($left, $right, 0, $comment);
439 my ($left, $right, $comment) = @_;
442 local $Test::Builder::Level = $Test::Builder::Level + 1;
444 _low_image_diff_check($left, $right, $comment)
448 my $builder = Test::Builder->new;
450 my $diff = Imager::i_img_diffd($left->{IMG}, $right->{IMG});
452 $builder->ok(0, $comment);
453 $builder->diag("image data difference: $diff");
455 # find the first mismatch
457 for my $y (0 .. $left->getheight()-1) {
458 for my $x (0.. $left->getwidth()-1) {
459 my @lsamples = $left->getsamples(x => $x, y => $y, width => 1);
460 my @rsamples = $right->getsamples(x => $x, y => $y, width => 1);
461 if ("@lsamples" ne "@rsamples") {
462 $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples");
471 return $builder->ok(1, $comment);
475 my ($left, $right, $comment) = @_;
477 my $builder = Test::Builder->new;
479 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
481 return $builder->ok($diff, "$comment");
484 sub image_bounds_checks {
487 my $builder = Test::Builder->new;
489 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0)');
490 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0)');
491 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1)');
492 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10)');
493 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0) float');
494 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0) float');
495 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1) float');
496 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10) float');
497 my $black = Imager::Color->new(0, 0, 0);
498 require Imager::Color::Float;
499 my $blackf = Imager::Color::Float->new(0, 0, 0);
500 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $black), 'bounds check set (-1, 0)');
501 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $black), 'bounds check set (10, 0)');
502 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $black), 'bounds check set (0, -1)');
503 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $black), 'bounds check set (0, 10)');
504 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $blackf), 'bounds check set (-1, 0) float');
505 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $blackf), 'bounds check set (10, 0) float');
506 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $blackf), 'bounds check set (0, -1) float');
507 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $blackf), 'bounds check set (0, 10) float');
510 sub test_colorf_gpix {
511 my ($im, $x, $y, $expected, $epsilon, $comment) = @_;
513 my $builder = Test::Builder->new;
515 defined $comment or $comment = '';
517 my $c = Imager::i_gpixf($im, $x, $y);
519 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
522 unless ($builder->ok(colorf_cmp($c, $expected, $epsilon) == 0,
523 "$comment - got right color ($x, $y)")) {
525 my @exp = $expected->rgba;
526 $builder->diag(<<EOS);
527 # got: ($c[0], $c[1], $c[2])
528 # expected: ($exp[0], $exp[1], $exp[2])
534 sub test_color_gpix {
535 my ($im, $x, $y, $expected, $comment) = @_;
537 my $builder = Test::Builder->new;
539 defined $comment or $comment = '';
540 my $c = Imager::i_get_pixel($im, $x, $y);
542 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
545 unless ($builder->ok(color_cmp($c, $expected) == 0,
546 "got right color ($x, $y)")) {
548 my @exp = $expected->rgba;
549 $builder->diag(<<EOS);
550 # got: ($c[0], $c[1], $c[2])
551 # expected: ($exp[0], $exp[1], $exp[2])
559 sub test_colorf_glin {
560 my ($im, $x, $y, $pels, $comment) = @_;
562 my $builder = Test::Builder->new;
564 my @got = Imager::i_glinf($im, $x, $x+@$pels, $y);
566 or return $builder->is_num(scalar(@got), scalar(@$pels), "$comment - pixels retrieved");
568 return $builder->ok(!grep(colorf_cmp($pels->[$_], $got[$_], 0.005), 0..$#got),
569 "$comment - check colors ($x, $y)");
573 my ($c1, $c2, $epsilon) = @_;
575 defined $epsilon or $epsilon = 0;
580 # print "# (",join(",", @s1[0..2]),") <=> (",join(",", @s2[0..2]),")\n";
581 return abs($s1[0]-$s2[0]) >= $epsilon && $s1[0] <=> $s2[0]
582 || abs($s1[1]-$s2[1]) >= $epsilon && $s1[1] <=> $s2[1]
583 || abs($s1[2]-$s2[2]) >= $epsilon && $s1[2] <=> $s2[2];
592 return $s1[0] <=> $s2[0]
594 || $s1[2] <=> $s2[2];
597 # these test the action of the channel mask on the image supplied
598 # which should be an OO image.
600 my ($im, $epsilon) = @_;
602 my $builder = Test::Builder->new;
604 defined $epsilon or $epsilon = 0;
606 # we want to check all four of ppix() and plin(), ppix() and plinf()
607 # basic test procedure:
608 # first using default/all 1s mask, set to white
609 # make sure we got white
610 # set mask to skip a channel, set to grey
611 # make sure only the right channels set
613 print "# channel mask tests\n";
615 my $white = Imager::NC(255, 255, 255);
616 my $grey = Imager::NC(128, 128, 128);
617 my $white_grey = Imager::NC(128, 255, 128);
619 print "# with ppix\n";
620 $builder->ok($im->setmask(mask=>~0), "set to default mask");
621 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$white), "set to white all channels");
622 test_color_gpix($im->{IMG}, 0, 0, $white, "ppix");
623 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
624 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$grey), "set to grey, no channel 2");
625 test_color_gpix($im->{IMG}, 0, 0, $white_grey, "ppix masked");
627 print "# with plin\n";
628 $builder->ok($im->setmask(mask=>~0), "set to default mask");
629 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels => [$white]),
630 "set to white all channels");
631 test_color_gpix($im->{IMG}, 0, 1, $white, "plin");
632 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
633 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels=>[$grey]),
634 "set to grey, no channel 2");
635 test_color_gpix($im->{IMG}, 0, 1, $white_grey, "plin masked");
638 my $whitef = Imager::NCF(1.0, 1.0, 1.0);
639 my $greyf = Imager::NCF(0.5, 0.5, 0.5);
640 my $white_greyf = Imager::NCF(0.5, 1.0, 0.5);
642 print "# with ppixf\n";
643 $builder->ok($im->setmask(mask=>~0), "set to default mask");
644 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$whitef), "set to white all channels");
645 test_colorf_gpix($im->{IMG}, 0, 2, $whitef, $epsilon, "ppixf");
646 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
647 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$greyf), "set to grey, no channel 2");
648 test_colorf_gpix($im->{IMG}, 0, 2, $white_greyf, $epsilon, "ppixf masked");
650 print "# with plinf\n";
651 $builder->ok($im->setmask(mask=>~0), "set to default mask");
652 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels => [$whitef]),
653 "set to white all channels");
654 test_colorf_gpix($im->{IMG}, 0, 3, $whitef, $epsilon, "plinf");
655 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
656 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels=>[$greyf]),
657 "set to grey, no channel 2");
658 test_colorf_gpix($im->{IMG}, 0, 3, $white_greyf, $epsilon, "plinf masked");
668 Imager::Test - common functions used in testing Imager
672 use Imager::Test 'diff_text_with_nul';
673 diff_text_with_nul($test_name, $text1, $text2, @string_options);
677 This is a repository of functions used in testing Imager.
679 Some functions will only be useful in testing Imager itself, while
680 others should be useful in testing modules that use Imager.
682 No functions are exported by default.
686 =head2 Test functions
692 =item is_color1($color, $grey, $comment)
694 Tests if the first channel of $color matches $grey.
696 =item is_color3($color, $red, $green, $blue, $comment)
698 Tests if $color matches the given ($red, $green, $blue)
700 =item is_color4($color, $red, $green, $blue, $alpha, $comment)
702 Tests if $color matches the given ($red, $green, $blue, $alpha)
704 =item is_fcolor1($fcolor, $grey, $comment)
706 =item is_fcolor1($fcolor, $grey, $epsilon, $comment)
708 Tests if $fcolor's first channel is within $epsilon of ($grey). For
709 the first form $epsilon is taken as 0.001.
711 =item is_fcolor3($fcolor, $red, $green, $blue, $comment)
713 =item is_fcolor3($fcolor, $red, $green, $blue, $epsilon, $comment)
715 Tests if $fcolor's channels are within $epsilon of ($red, $green,
716 $blue). For the first form $epsilon is taken as 0.001.
718 =item is_fcolor4($fcolor, $red, $green, $blue, $alpha, $comment)
720 =item is_fcolor4($fcolor, $red, $green, $blue, $alpha, $epsilon, $comment)
722 Tests if $fcolor's channels are within $epsilon of ($red, $green,
723 $blue, $alpha). For the first form $epsilon is taken as 0.001.
725 =item is_image($im1, $im2, $comment)
727 Tests if the 2 images have the same content. Both images must be
728 defined, have the same width, height, channels and the same color in
729 each pixel. The color comparison is done at 8-bits per pixel. The
730 color representation such as direct vs paletted, bits per sample are
731 not checked. Equivalent to is_image_similar($im1, $im2, 0, $comment).
733 =item is_imaged($im, $im2, $comment)
735 Tests if the two images have the same content at the double/sample
738 =item is_image_similar($im1, $im2, $maxdiff, $comment)
740 Tests if the 2 images have similar content. Both images must be
741 defined, have the same width, height and channels. The cum of the
742 squares of the differences of each sample are calculated and must be
743 less than or equal to I<$maxdiff> for the test to pass. The color
744 comparison is done at 8-bits per pixel. The color representation such
745 as direct vs paletted, bits per sample are not checked.
747 =item isnt_image($im1, $im2, $comment)
749 Tests that the two images are different. For regressions tests where
750 something (like text output of "0") produced no change, but should
751 have produced a change.
753 =item test_colorf_gpix($im, $x, $y, $expected, $epsilon, $comment)
755 Retrieves the pixel ($x,$y) from the low-level image $im and compares
756 it to the floating point color $expected, with a tolerance of epsilon.
758 =item test_color_gpix($im, $x, $y, $expected, $comment)
760 Retrieves the pixel ($x,$y) from the low-level image $im and compares
761 it to the floating point color $expected.
763 =item test_colorf_glin($im, $x, $y, $pels, $comment)
765 Retrieves the floating point pixels ($x, $y)-[$x+@$pels, $y] from the
766 low level image $im and compares them against @$pels.
768 =item is_color_close3($color, $red, $green, $blue, $tolerance, $comment)
770 Tests if $color's first three channels are within $tolerance of ($red,
775 =head2 Test suite functions
777 Functions that perform one or more tests, typically used to test
778 various parts of Imager's implementation.
782 =item image_bounds_checks($im)
784 Attempts to write to various pixel positions outside the edge of the
785 image to ensure that it fails in those locations.
787 Any new image type should pass these tests. Does 16 separate tests.
789 =item mask_tests($im, $epsilon)
791 Perform a standard set of mask tests on the OO image $im. Does 24
794 =item diff_text_with_nul($test_name, $text1, $text2, @options)
796 Creates 2 test images and writes $text1 to the first image and $text2
797 to the second image with the string() method. Each call adds 3
798 C<ok>/C<not ok> to the output of the test script.
800 Extra options that should be supplied include the font and either a
801 color or channel parameter.
803 This was explicitly created for regression tests on #21770.
807 =head2 Helper functions
811 =item test_image_raw()
813 Returns a 150x150x3 Imager::ImgRaw test image.
817 Returns a 150x150x3 8-bit/sample OO test image.
819 =item test_image_16()
821 Returns a 150x150x3 16-bit/sample OO test image.
823 =item test_image_double()
825 Returns a 150x150x3 double/sample OO test image.
827 =item color_cmp($c1, $c2)
829 Performs an ordering of 3-channel colors (like <=>).
831 =item colorf_cmp($c1, $c2)
833 Performs an ordering of 3-channel floating point colors (like <=>).
839 Tony Cook <tony@develop-help.com>