5 use vars qw(@ISA @EXPORT_OK);
30 sub diff_text_with_nul {
31 my ($desc, $text1, $text2, @params) = @_;
33 my $builder = Test::Builder->new;
36 my $imbase = Imager->new(xsize => 100, ysize => 100);
37 my $imcopy = Imager->new(xsize => 100, ysize => 100);
39 $builder->ok($imbase->string(x => 5, 'y' => 50, size => 20,
41 @params), "$desc - draw text1");
42 $builder->ok($imcopy->string(x => 5, 'y' => 50, size => 20,
44 @params), "$desc - draw text2");
45 $builder->isnt_num(Imager::i_img_diff($imbase->{IMG}, $imcopy->{IMG}), 0,
46 "$desc - check result different");
49 sub is_color3($$$$$) {
50 my ($color, $red, $green, $blue, $comment) = @_;
52 my $builder = Test::Builder->new;
54 unless (defined $color) {
55 $builder->ok(0, $comment);
56 $builder->diag("color is undef");
59 unless ($color->can('rgba')) {
60 $builder->ok(0, $comment);
61 $builder->diag("color is not a color object");
65 my ($cr, $cg, $cb) = $color->rgba;
66 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue, $comment)) {
67 $builder->diag(<<END_DIAG);
79 sub is_color_close3($$$$$$) {
80 my ($color, $red, $green, $blue, $tolerance, $comment) = @_;
82 my $builder = Test::Builder->new;
84 unless (defined $color) {
85 $builder->ok(0, $comment);
86 $builder->diag("color is undef");
89 unless ($color->can('rgba')) {
90 $builder->ok(0, $comment);
91 $builder->diag("color is not a color object");
95 my ($cr, $cg, $cb) = $color->rgba;
96 unless ($builder->ok(abs($cr - $red) <= $tolerance
97 && abs($cg - $green) <= $tolerance
98 && abs($cb - $blue) <= $tolerance, $comment)) {
99 $builder->diag(<<END_DIAG);
100 Color out of tolerance ($tolerance):
101 Red: expected $red vs received $cr
102 Green: expected $green vs received $cg
103 Blue: expected $blue vs received $cb
111 sub is_color4($$$$$$) {
112 my ($color, $red, $green, $blue, $alpha, $comment) = @_;
114 my $builder = Test::Builder->new;
116 unless (defined $color) {
117 $builder->ok(0, $comment);
118 $builder->diag("color is undef");
121 unless ($color->can('rgba')) {
122 $builder->ok(0, $comment);
123 $builder->diag("color is not a color object");
127 my ($cr, $cg, $cb, $ca) = $color->rgba;
128 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue
129 && $ca == $alpha, $comment)) {
130 $builder->diag(<<END_DIAG);
143 sub is_fcolor4($$$$$$;$) {
144 my ($color, $red, $green, $blue, $alpha, $comment_or_diff, $comment_or_undef) = @_;
145 my ($comment, $mindiff);
146 if (defined $comment_or_undef) {
147 ( $mindiff, $comment ) = ( $comment_or_diff, $comment_or_undef )
150 ( $mindiff, $comment ) = ( 0.001, $comment_or_diff )
153 my $builder = Test::Builder->new;
155 unless (defined $color) {
156 $builder->ok(0, $comment);
157 $builder->diag("color is undef");
160 unless ($color->can('rgba')) {
161 $builder->ok(0, $comment);
162 $builder->diag("color is not a color object");
166 my ($cr, $cg, $cb, $ca) = $color->rgba;
167 unless ($builder->ok(abs($cr - $red) <= $mindiff
168 && abs($cg - $green) <= $mindiff
169 && abs($cb - $blue) <= $mindiff
170 && abs($ca - $alpha) <= $mindiff, $comment)) {
171 $builder->diag(<<END_DIAG);
185 my ($color, $grey, $comment) = @_;
187 my $builder = Test::Builder->new;
189 unless (defined $color) {
190 $builder->ok(0, $comment);
191 $builder->diag("color is undef");
194 unless ($color->can('rgba')) {
195 $builder->ok(0, $comment);
196 $builder->diag("color is not a color object");
200 my ($cgrey) = $color->rgba;
201 unless ($builder->ok($cgrey == $grey, $comment)) {
202 $builder->diag(<<END_DIAG);
204 Grey: $grey vs $cgrey
213 my $green=Imager::i_color_new(0,255,0,255);
214 my $blue=Imager::i_color_new(0,0,255,255);
215 my $red=Imager::i_color_new(255,0,0,255);
217 my $img=Imager::ImgRaw::new(150,150,3);
219 Imager::i_box_filled($img,70,25,130,125,$green);
220 Imager::i_box_filled($img,20,25,80,125,$blue);
221 Imager::i_arc($img,75,75,30,0,361,$red);
222 Imager::i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
228 my $green = Imager::Color->new(0, 255, 0, 255);
229 my $blue = Imager::Color->new(0, 0, 255, 255);
230 my $red = Imager::Color->new(255, 0, 0, 255);
231 my $img = Imager->new(xsize => 150, ysize => 150);
232 $img->box(filled => 1, color => $green, box => [ 70, 24, 130, 124 ]);
233 $img->box(filled => 1, color => $blue, box => [ 20, 26, 80, 126 ]);
234 $img->arc(x => 75, y => 75, r => 30, color => $red);
235 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
241 my $green = Imager::Color->new(0, 255, 0, 255);
242 my $blue = Imager::Color->new(0, 0, 255, 255);
243 my $red = Imager::Color->new(255, 0, 0, 255);
244 my $img = Imager->new(xsize => 150, ysize => 150, bits => 16);
245 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
246 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
247 $img->arc(x => 75, y => 75, r => 30, color => $red);
248 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
253 sub test_image_double {
254 my $green = Imager::Color->new(0, 255, 0, 255);
255 my $blue = Imager::Color->new(0, 0, 255, 255);
256 my $red = Imager::Color->new(255, 0, 0, 255);
257 my $img = Imager->new(xsize => 150, ysize => 150, bits => 'double');
258 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
259 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
260 $img->arc(x => 75, y => 75, r => 30, color => $red);
261 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
266 sub _low_image_diff_check {
267 my ($left, $right, $comment) = @_;
269 my $builder = Test::Builder->new;
271 unless (defined $left) {
272 $builder->ok(0, $comment);
273 $builder->diag("left is undef");
276 unless (defined $right) {
277 $builder->ok(0, $comment);
278 $builder->diag("right is undef");
281 unless ($left->{IMG}) {
282 $builder->ok(0, $comment);
283 $builder->diag("left image has no low level object");
286 unless ($right->{IMG}) {
287 $builder->ok(0, $comment);
288 $builder->diag("right image has no low level object");
291 unless ($left->getwidth == $right->getwidth) {
292 $builder->ok(0, $comment);
293 $builder->diag("left width " . $left->getwidth . " vs right width "
297 unless ($left->getheight == $right->getheight) {
298 $builder->ok(0, $comment);
299 $builder->diag("left height " . $left->getheight . " vs right height "
300 . $right->getheight);
303 unless ($left->getchannels == $right->getchannels) {
304 $builder->ok(0, $comment);
305 $builder->diag("left channels " . $left->getchannels . " vs right channels "
306 . $right->getchannels);
313 sub is_image_similar($$$$) {
314 my ($left, $right, $limit, $comment) = @_;
317 local $Test::Builder::Level = $Test::Builder::Level + 1;
319 _low_image_diff_check($left, $right, $comment)
323 my $builder = Test::Builder->new;
325 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
326 if ($diff > $limit) {
327 $builder->ok(0, $comment);
328 $builder->diag("image data difference > $limit - $diff");
331 # find the first mismatch
333 for my $y (0 .. $left->getheight()-1) {
334 for my $x (0.. $left->getwidth()-1) {
335 my @lsamples = $left->getsamples(x => $x, y => $y, width => 1);
336 my @rsamples = $right->getsamples(x => $x, y => $y, width => 1);
337 if ("@lsamples" ne "@rsamples") {
338 $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples");
348 return $builder->ok(1, $comment);
352 my ($left, $right, $comment) = @_;
354 local $Test::Builder::Level = $Test::Builder::Level + 1;
356 return is_image_similar($left, $right, 0, $comment);
360 my ($left, $right, $comment) = @_;
363 local $Test::Builder::Level = $Test::Builder::Level + 1;
365 _low_image_diff_check($left, $right, $comment)
369 my $builder = Test::Builder->new;
371 my $diff = Imager::i_img_diffd($left->{IMG}, $right->{IMG});
373 $builder->ok(0, $comment);
374 $builder->diag("image data difference: $diff");
376 # find the first mismatch
378 for my $y (0 .. $left->getheight()-1) {
379 for my $x (0.. $left->getwidth()-1) {
380 my @lsamples = $left->getsamples(x => $x, y => $y, width => 1);
381 my @rsamples = $right->getsamples(x => $x, y => $y, width => 1);
382 if ("@lsamples" ne "@rsamples") {
383 $builder->diag("first mismatch at ($x, $y) - @lsamples vs @rsamples");
392 return $builder->ok(1, $comment);
396 my ($left, $right, $comment) = @_;
398 my $builder = Test::Builder->new;
400 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
402 return $builder->ok($diff, "$comment");
405 sub image_bounds_checks {
408 my $builder = Test::Builder->new;
410 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0)');
411 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0)');
412 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1)');
413 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10)');
414 $builder->ok(!$im->getpixel(x => -1, y => 0), 'bounds check get (-1, 0) float');
415 $builder->ok(!$im->getpixel(x => 10, y => 0), 'bounds check get (10, 0) float');
416 $builder->ok(!$im->getpixel(x => 0, y => -1), 'bounds check get (0, -1) float');
417 $builder->ok(!$im->getpixel(x => 0, y => 10), 'bounds check get (0, 10) float');
418 my $black = Imager::Color->new(0, 0, 0);
419 require Imager::Color::Float;
420 my $blackf = Imager::Color::Float->new(0, 0, 0);
421 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $black), 'bounds check set (-1, 0)');
422 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $black), 'bounds check set (10, 0)');
423 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $black), 'bounds check set (0, -1)');
424 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $black), 'bounds check set (0, 10)');
425 $builder->ok(!$im->setpixel(x => -1, y => 0, color => $blackf), 'bounds check set (-1, 0) float');
426 $builder->ok(!$im->setpixel(x => 10, y => 0, color => $blackf), 'bounds check set (10, 0) float');
427 $builder->ok(!$im->setpixel(x => 0, y => -1, color => $blackf), 'bounds check set (0, -1) float');
428 $builder->ok(!$im->setpixel(x => 0, y => 10, color => $blackf), 'bounds check set (0, 10) float');
431 sub test_colorf_gpix {
432 my ($im, $x, $y, $expected, $epsilon, $comment) = @_;
434 my $builder = Test::Builder->new;
436 defined $comment or $comment = '';
438 my $c = Imager::i_gpixf($im, $x, $y);
440 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
443 unless ($builder->ok(colorf_cmp($c, $expected, $epsilon) == 0,
444 "$comment - got right color ($x, $y)")) {
446 my @exp = $expected->rgba;
447 $builder->diag(<<EOS);
448 # got: ($c[0], $c[1], $c[2])
449 # expected: ($exp[0], $exp[1], $exp[2])
455 sub test_color_gpix {
456 my ($im, $x, $y, $expected, $comment) = @_;
458 my $builder = Test::Builder->new;
460 defined $comment or $comment = '';
461 my $c = Imager::i_get_pixel($im, $x, $y);
463 $builder->ok(0, "$comment - retrieve color at ($x,$y)");
466 unless ($builder->ok(color_cmp($c, $expected) == 0,
467 "got right color ($x, $y)")) {
469 my @exp = $expected->rgba;
470 $builder->diag(<<EOS);
471 # got: ($c[0], $c[1], $c[2])
472 # expected: ($exp[0], $exp[1], $exp[2])
480 sub test_colorf_glin {
481 my ($im, $x, $y, $pels, $comment) = @_;
483 my $builder = Test::Builder->new;
485 my @got = Imager::i_glinf($im, $x, $x+@$pels, $y);
487 or return $builder->is_num(scalar(@got), scalar(@$pels), "$comment - pixels retrieved");
489 return $builder->ok(!grep(colorf_cmp($pels->[$_], $got[$_], 0.005), 0..$#got),
490 "$comment - check colors ($x, $y)");
494 my ($c1, $c2, $epsilon) = @_;
496 defined $epsilon or $epsilon = 0;
501 # print "# (",join(",", @s1[0..2]),") <=> (",join(",", @s2[0..2]),")\n";
502 return abs($s1[0]-$s2[0]) >= $epsilon && $s1[0] <=> $s2[0]
503 || abs($s1[1]-$s2[1]) >= $epsilon && $s1[1] <=> $s2[1]
504 || abs($s1[2]-$s2[2]) >= $epsilon && $s1[2] <=> $s2[2];
513 return $s1[0] <=> $s2[0]
515 || $s1[2] <=> $s2[2];
518 # these test the action of the channel mask on the image supplied
519 # which should be an OO image.
521 my ($im, $epsilon) = @_;
523 my $builder = Test::Builder->new;
525 defined $epsilon or $epsilon = 0;
527 # we want to check all four of ppix() and plin(), ppix() and plinf()
528 # basic test procedure:
529 # first using default/all 1s mask, set to white
530 # make sure we got white
531 # set mask to skip a channel, set to grey
532 # make sure only the right channels set
534 print "# channel mask tests\n";
536 my $white = Imager::NC(255, 255, 255);
537 my $grey = Imager::NC(128, 128, 128);
538 my $white_grey = Imager::NC(128, 255, 128);
540 print "# with ppix\n";
541 $builder->ok($im->setmask(mask=>~0), "set to default mask");
542 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$white), "set to white all channels");
543 test_color_gpix($im->{IMG}, 0, 0, $white, "ppix");
544 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
545 $builder->ok($im->setpixel(x=>0, 'y'=>0, color=>$grey), "set to grey, no channel 2");
546 test_color_gpix($im->{IMG}, 0, 0, $white_grey, "ppix masked");
548 print "# with plin\n";
549 $builder->ok($im->setmask(mask=>~0), "set to default mask");
550 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels => [$white]),
551 "set to white all channels");
552 test_color_gpix($im->{IMG}, 0, 1, $white, "plin");
553 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
554 $builder->ok($im->setscanline(x=>0, 'y'=>1, pixels=>[$grey]),
555 "set to grey, no channel 2");
556 test_color_gpix($im->{IMG}, 0, 1, $white_grey, "plin masked");
559 my $whitef = Imager::NCF(1.0, 1.0, 1.0);
560 my $greyf = Imager::NCF(0.5, 0.5, 0.5);
561 my $white_greyf = Imager::NCF(0.5, 1.0, 0.5);
563 print "# with ppixf\n";
564 $builder->ok($im->setmask(mask=>~0), "set to default mask");
565 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$whitef), "set to white all channels");
566 test_colorf_gpix($im->{IMG}, 0, 2, $whitef, $epsilon, "ppixf");
567 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
568 $builder->ok($im->setpixel(x=>0, 'y'=>2, color=>$greyf), "set to grey, no channel 2");
569 test_colorf_gpix($im->{IMG}, 0, 2, $white_greyf, $epsilon, "ppixf masked");
571 print "# with plinf\n";
572 $builder->ok($im->setmask(mask=>~0), "set to default mask");
573 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels => [$whitef]),
574 "set to white all channels");
575 test_colorf_gpix($im->{IMG}, 0, 3, $whitef, $epsilon, "plinf");
576 $builder->ok($im->setmask(mask=>0xF-0x2), "set channel to exclude channel1");
577 $builder->ok($im->setscanline(x=>0, 'y'=>3, pixels=>[$greyf]),
578 "set to grey, no channel 2");
579 test_colorf_gpix($im->{IMG}, 0, 3, $white_greyf, $epsilon, "plinf masked");
589 Imager::Test - common functions used in testing Imager
593 use Imager::Test 'diff_text_with_nul';
594 diff_text_with_nul($test_name, $text1, $text2, @string_options);
598 This is a repository of functions used in testing Imager.
600 Some functions will only be useful in testing Imager itself, while
601 others should be useful in testing modules that use Imager.
603 No functions are exported by default.
609 =item is_color3($color, $red, $blue, $green, $comment)
611 Tests is $color matches the given ($red, $blue, $green)
613 =item is_image($im1, $im2, $comment)
615 Tests if the 2 images have the same content. Both images must be
616 defined, have the same width, height, channels and the same color in
617 each pixel. The color comparison is done at 8-bits per pixel. The
618 color representation such as direct vs paletted, bits per sample are
619 not checked. Equivalent to is_image_similar($im1, $im2, 0, $comment).
621 =item is_imaged($im, $im2, $comment)
623 Tests if the two images have the same content at the double/sample
626 =item is_image_similar($im1, $im2, $maxdiff, $comment)
628 Tests if the 2 images have similar content. Both images must be
629 defined, have the same width, height and channels. The cum of the
630 squares of the differences of each sample are calculated and must be
631 less than or equal to I<$maxdiff> for the test to pass. The color
632 comparison is done at 8-bits per pixel. The color representation such
633 as direct vs paletted, bits per sample are not checked.
635 =item test_image_raw()
637 Returns a 150x150x3 Imager::ImgRaw test image.
641 Returns a 150x150x3 8-bit/sample OO test image.
643 =item test_image_16()
645 Returns a 150x150x3 16-bit/sample OO test image.
647 =item test_image_double()
649 Returns a 150x150x3 double/sample OO test image.
651 =item diff_text_with_nul($test_name, $text1, $text2, @options)
653 Creates 2 test images and writes $text1 to the first image and $text2
654 to the second image with the string() method. Each call adds 3 ok/not
655 ok to the output of the test script.
657 Extra options that should be supplied include the font and either a
658 color or channel parameter.
660 This was explicitly created for regression tests on #21770.
662 =item image_bounds_checks($im)
664 Attempts to write to various pixel positions outside the edge of the
665 image to ensure that it fails in those locations.
667 Any new image type should pass these tests. Does 16 separate tests.
669 =item test_colorf_gpix($im, $x, $y, $expected, $epsilon, $comment)
671 Retrieves the pixel ($x,$y) from the low-level image $im and compares
672 it to the floating point color $expected, with a tolerance of epsilon.
674 =item test_color_gpix($im, $x, $y, $expected, $comment)
676 Retrieves the pixel ($x,$y) from the low-level image $im and compares
677 it to the floating point color $expected.
679 =item test_colorf_glin($im, $x, $y, $pels, $comment)
681 Retrieves the floating point pixels ($x, $y)-[$x+@$pels, $y] from the
682 low level image $im and compares them against @$pels.
684 =item mask_tests($im, $epsilon)
686 Perform a standard set of mask tests on the OO image $im.
692 Tony Cook <tony@develop-help.com>