4 use Test::More tests => 124;
6 -d "testout" or mkdir "testout";
8 Imager::init_log("testout/t61filters.log", 1);
9 use Imager::Test qw(is_image_similar test_image is_image is_color4 is_fcolor4);
10 # meant for testing the filters themselves
12 my $imbase = test_image();
14 my $im_other = Imager->new(xsize=>150, ysize=>150);
15 $im_other->box(xmin=>30, ymin=>60, xmax=>120, ymax=>90, filled=>1);
17 test($imbase, {type=>'autolevels'}, 'testout/t61_autolev.ppm');
19 test($imbase, {type=>'autolevels_skew'}, 'testout/t61_autoskew.ppm');
21 test($imbase, {type=>'contrast', intensity=>0.5},
22 'testout/t61_contrast.ppm');
24 # this one's kind of cool
25 test($imbase, {type=>'conv', coef=>[ 0.3, 1, 0.3, ], },
26 'testout/t61_conv_blur.ppm');
29 my $work = $imbase->copy;
30 ok(!Imager::i_conv($work->{IMG}, []), "conv should fail with empty array");
31 ok(!$work->filter(type => 'conv', coef => []),
32 "check the conv OO intergave too");
33 is($work->errstr, "there must be at least one coefficient",
34 "check conv error message");
38 my $work8 = $imbase->copy;
39 ok(!$work8->filter(type => "conv", coef => "ABC"),
43 my $work8 = $imbase->copy;
44 ok(!$work8->filter(type => "conv", coef => [ -1, 2, -1 ]),
45 "should fail if sum of coef is 0");
46 is($work8->errstr, "sum of coefficients is zero", "check message");
50 my $work8 = $imbase->copy;
51 my $work16 = $imbase->to_rgb16;
52 my $coef = [ -0.2, 1, -0.2 ];
53 ok($work8->filter(type => "conv", coef => $coef),
54 "filter 8 bit image");
55 ok($work16->filter(type => "conv", , coef => $coef),
56 "filter 16 bit image");
57 is_image_similar($work8, $work16, 80000, "8 and 16 bit conv match");
61 my $gauss = test($imbase, {type=>'gaussian', stddev=>5 },
62 'testout/t61_gaussian.ppm');
64 my $imbase16 = $imbase->to_rgb16;
65 my $gauss16 = test($imbase16, {type=>'gaussian', stddev=>5 },
66 'testout/t61_gaussian16.ppm');
67 is_image_similar($gauss, $gauss16, 250000, "8 and 16 gaussian match");
71 test($imbase, { type=>'gradgen', dist=>1,
74 colors=> [ NC('#FF0000'), NC('#FFFF00'), NC('#00FFFF') ]},
75 'testout/t61_gradgen.ppm');
77 test($imbase, {type=>'mosaic', size=>8}, 'testout/t61_mosaic.ppm');
79 test($imbase, {type=>'hardinvert'}, 'testout/t61_hardinvert.ppm');
82 my $im = Imager->new(xsize => 1, ysize => 1, channels => 4);
83 ok($im, "make test image for invert test");
84 ok($im->setpixel(x => 0, y => 0, color => "000010C0"),
87 ok($im->filter(type => "hardinvert"), "hardinvert it");
88 is_color4($im->getpixel(x => 0, y => 0), 255, 255, 0xEF, 0xC0,
89 "check only colour inverted");
90 ok($copy->filter(type => "hardinvertall"), "hardinvertall copy");
91 is_color4($copy->getpixel(x => 0, y => 0), 255, 255, 0xEF, 0x3f,
92 "check all inverted");
95 { # invert - double image
96 my $im = Imager->new(xsize => 1, ysize => 1, channels => 4, bits => "double");
97 ok($im, "make double test image for invert test");
98 ok($im->setpixel(x => 0, y => 0, color => Imager::Color::Float->new(0, 0, 0.125, 0.75)),
100 my $copy = $im->copy;
101 ok($im->filter(type => "hardinvert"), "hardinvert it");
102 is_fcolor4($im->getpixel(x => 0, y => 0, type => "double"),
103 1.0, 1.0, 0.875, 0.75, 1e-5,
104 "check only colour inverted");
105 ok($copy->filter(type => "hardinvertall"), "hardinvertall copy");
106 is_fcolor4($copy->getpixel(x => 0, y => 0, type =>"double"),
107 1.0, 1.0, 0.875, 0.25, 1e-5,
108 "check all inverted");
111 test($imbase, {type=>'noise'}, 'testout/t61_noise.ppm');
113 test($imbase, {type=>'radnoise'}, 'testout/t61_radnoise.ppm');
115 test($imbase, {type=>'turbnoise'}, 'testout/t61_turbnoise.ppm');
117 test($imbase, {type=>'bumpmap', bump=>$im_other, lightx=>30, lighty=>30},
118 'testout/t61_bumpmap.ppm');
120 test($imbase, {type=>'bumpmap_complex', bump=>$im_other}, 'testout/t61_bumpmap_complex.ppm');
122 test($imbase, {type=>'postlevels', levels=>3}, 'testout/t61_postlevels.ppm');
124 test($imbase, {type=>'watermark', wmark=>$im_other },
125 'testout/t61_watermark.ppm');
127 test($imbase, {type=>'fountain', xa=>75, ya=>75, xb=>85, yb=>30,
128 repeat=>'triangle', #ftype=>'radial',
129 super_sample=>'circle', ssample_param => 16,
131 'testout/t61_fountain.ppm');
132 use Imager::Fountain;
134 my $f1 = Imager::Fountain->new;
135 $f1->add(end=>0.2, c0=>NC(255, 0,0), c1=>NC(255, 255,0));
136 $f1->add(start=>0.2, c0=>NC(255,255,0), c1=>NC(0,0,255,0));
137 test($imbase, { type=>'fountain', xa=>20, ya=>130, xb=>130, yb=>20,
141 'testout/t61_fountain2.ppm');
142 my $f2 = Imager::Fountain->new
143 ->add(end=>0.5, c0=>NC(255,0,0), c1=>NC(255,0,0), color=>'hueup')
144 ->add(start=>0.5, c0=>NC(255,0,0), c1=>NC(255,0,0), color=>'huedown');
147 test($imbase, { type=>'fountain', xa=>20, ya=>130, xb=>130, yb=>20,
149 'testout/t61_fount_hsv.ppm');
150 my $f3 = Imager::Fountain->read(gimp=>'testimg/gimpgrad');
151 ok($f3, "read gimpgrad");
152 test($imbase, { type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15,
153 segments=>$f3, super_sample=>'grid',
154 ftype=>'radial_square', combine=>'color' },
155 'testout/t61_fount_gimp.ppm');
156 { # test new fountain with no parameters
158 local $SIG{__WARN__} = sub { $warn .= "@_" };
159 my $f4 = Imager::Fountain->read();
160 ok(!$f4, "read with no parameters does nothing");
161 like($warn, qr/Nothing to do!/, "check the warning");
163 { # test with missing file
165 local $SIG{__WARN__} = sub { $warn .= "@_" };
166 my $f = Imager::Fountain->read(gimp => "no-such-file");
167 ok(!$f, "try to read a fountain defintion that doesn't exist");
168 is($warn, "", "should be no warning");
169 like(Imager->errstr, qr/^Cannot open no-such-file: /, "check message");
173 my $fh = IO::File->new("testimg/gimpgrad", "r");
174 ok($fh, "opened gradient")
175 or skip "Couldn't open gradient: $!", 1;
176 my $f = Imager::Fountain->read(gimp => $fh);
177 ok($f, "read gradient from file handle");
181 my $f = Imager::Fountain->read(gimp => "t/400-filter/010-filters.t");
182 ok(!$f, "fail to read non-gradient");
183 is(Imager->errstr, "t/400-filter/010-filters.t is not a GIMP gradient file",
184 "check error message");
186 { # an invalid gradient file
187 my $f = Imager::Fountain->read(gimp => "testimg/gradbad.ggr");
188 ok(!$f, "fail to read bad gradient (bad seg count)");
189 is(Imager->errstr, "testimg/gradbad.ggr is missing the segment count",
190 "check error message");
192 { # an invalid gradient file
193 my $f = Imager::Fountain->read(gimp => "testimg/gradbad2.ggr");
194 ok(!$f, "fail to read bad gradient (bad segment)");
195 is(Imager->errstr, "Bad segment definition",
196 "check error message");
198 test($imbase, { type=>'unsharpmask', stddev=>2.0 },
199 'testout/t61_unsharp.ppm');
200 test($imbase, {type=>'conv', coef=>[ -1, 3, -1, ], },
201 'testout/t61_conv_sharp.ppm');
203 test($imbase, { type=>'nearest_color', dist=>1,
206 colors=> [ NC('#FF0000'), NC('#FFFF00'), NC('#00FFFF') ]},
207 'testout/t61_nearest.ppm');
209 # Regression test: the checking of the segment type was incorrect
210 # (the comparison was checking the wrong variable against the wrong value)
211 my $f4 = [ [ 0, 0.5, 1, NC(0,0,0), NC(255,255,255), 5, 0 ] ];
212 test($imbase, {type=>'fountain', xa=>75, ya=>75, xb=>90, yb=>15,
213 segments=>$f4, super_sample=>'grid',
214 ftype=>'linear', combine=>'color' },
215 'testout/t61_regress_fount.ppm');
216 my $im2 = $imbase->copy;
217 $im2->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1);
218 $im2->write(file=>'testout/t61_diff_base.ppm');
219 my $im3 = Imager->new(xsize=>150, ysize=>150, channels=>3);
220 $im3->box(xmin=>20, ymin=>20, xmax=>40, ymax=>40, color=>'FF0000', filled=>1);
221 my $diff = $imbase->difference(other=>$im2);
222 ok($diff, "got difference image");
225 skip(1, "missing comp or diff image") unless $im3 && $diff;
227 is(Imager::i_img_diff($im3->{IMG}, $diff->{IMG}), 0,
228 "compare test image and diff image");
231 # newer versions of gimp add a line to the gradient file
233 my $f5 = Imager::Fountain->read(gimp=>'testimg/newgimpgrad.ggr',
235 ok($f5, "read newer gimp gradient")
236 or print "# ",Imager->errstr,"\n";
237 is($name, "imager test gradient", "check name read correctly");
238 $f5 = Imager::Fountain->read(gimp=>'testimg/newgimpgrad.ggr');
239 ok($f5, "check we handle case of no name reference correctly")
240 or print "# ",Imager->errstr,"\n";
242 # test writing of gradients
243 ok($f2->write(gimp=>'testout/t61grad1.ggr'), "save a gradient")
244 or print "# ",Imager->errstr,"\n";
246 my $f6 = Imager::Fountain->read(gimp=>'testout/t61grad1.ggr',
248 ok($f6, "read what we wrote")
249 or print "# ",Imager->errstr,"\n";
250 ok(!defined $name, "we didn't set the name, so shouldn't get one");
253 ok($f2->write(gimp=>'testout/t61grad2.ggr', name=>'test gradient'),
254 "write gradient with a name")
255 or print "# ",Imager->errstr,"\n";
257 my $f7 = Imager::Fountain->read(gimp=>'testout/t61grad2.ggr', name=>\$name);
258 ok($f7, "read what we wrote")
259 or print "# ",Imager->errstr,"\n";
260 is($name, "test gradient", "check the name matches");
262 # we attempt to convert color names in segments to segments now
266 [ 0.0, 0.5, 1.0, '000000', '#FFF', 0, 0 ],
268 my $im = Imager->new(xsize=>50, ysize=>50);
269 ok($im->filter(type=>'fountain', segments => \@segs,
270 xa=>0, ya=>30, xb=>49, yb=>30),
271 "fountain with color names instead of objects in segments");
272 my $left = $im->getpixel('x'=>0, 'y'=>20);
273 ok(color_close($left, Imager::Color->new(0,0,0)),
274 "check black converted correctly");
275 my $right = $im->getpixel('x'=>49, 'y'=>20);
276 ok(color_close($right, Imager::Color->new(255,255,255)),
277 "check white converted correctly");
279 # check that invalid color names are handled correctly
282 [ 0.0, 0.5, 1.0, '000000', 'FxFxFx', 0, 0 ],
284 ok(!$im->filter(type=>'fountain', segments => \@segs2,
285 xa=>0, ya=>30, xb=>49, yb=>30),
286 "fountain with invalid color name");
287 cmp_ok($im->errstr, '=~', 'No color named', "check error message");
291 # test simple gradient creation
292 my @colors = map Imager::Color->new($_), qw/white blue red/;
293 my $s = Imager::Fountain->simple(positions => [ 0, 0.3, 1.0 ],
295 ok($s, "made simple gradient");
297 is($start->[0], 0, "check start of first correct");
298 is_color4($start->[3], 255, 255, 255, 255, "check color at start");
301 # simple gradient error modes
304 local $SIG{__WARN__} = sub { $warn .= "@_" };
305 my $s = Imager::Fountain->simple();
306 ok(!$s, "no parameters to simple()");
307 like($warn, qr/Nothing to do/);
310 my $s = Imager::Fountain->simple(positions => [ 0, 1 ],
311 colors => [ NC(0, 0, 0) ]);
312 ok(!$s, "mismatch of positions and colors fails");
313 is(Imager->errstr, "positions and colors must be the same size",
317 my $s = Imager::Fountain->simple(positions => [ 0 ],
318 colors => [ NC(0, 0, 0) ]);
319 ok(!$s, "not enough positions");
320 is(Imager->errstr, "not enough segments");
325 my $im = Imager->new(xsize=>100, ysize=>100);
326 # build the gradient the hard way - linear from black to white,
330 [ 0, 0.25, 0.5, 'black', 'white', 0, 0 ],
331 [ 0.5. 0.75, 1.0, 'white', 'black', 0, 0 ],
334 my $linear = $im->filter(type => "fountain",
336 repeat => 'sawtooth',
338 ya => $im->getheight / 2,
339 xb => $im->getwidth - 1,
340 yb => $im->getheight / 2);
341 ok($linear, "linear fountain sample");
343 my $revolution = $im->filter(type => "fountain",
344 ftype => 'revolution',
345 xa => $im->getwidth / 2,
346 ya => $im->getheight / 2,
347 xb => $im->getwidth / 2,
349 ok($revolution, "revolution fountain sample");
350 # out from the middle
351 my $radial = $im->filter(type => "fountain",
353 xa => $im->getwidth / 2,
354 ya => $im->getheight / 2,
355 xb => $im->getwidth / 2,
357 ok($radial, "radial fountain sample");
361 # try a simple custom filter that uses the Perl image interface
365 my $im = $args{imager};
367 my $channels = $args{channels};
368 unless (@$channels) {
369 $channels = [ reverse(0 .. $im->getchannels-1) ];
371 my @chans = @$channels;
372 push @chans, 0 while @chans < 4;
374 for my $y (0 .. $im->getheight-1) {
375 my $row = $im->getsamples(y => $y, channels => \@chans);
376 $im->setscanline(y => $y, pixels => $row);
379 Imager->register_filter(type => 'perl_test',
380 callsub => \&perl_filt,
381 defaults => { channels => [] },
382 callseq => [ qw/imager channels/ ]);
383 test($imbase, { type => 'perl_test' }, 'testout/t61perl.ppm');
386 { # check the difference method out
387 my $im1 = Imager->new(xsize => 3, ysize => 2);
388 $im1->box(filled => 1, color => '#FF0000');
389 my $im2 = $im1->copy;
390 $im1->setpixel(x => 1, 'y' => 0, color => '#FF00FF');
391 $im2->setpixel(x => 1, 'y' => 0, color => '#FF01FF');
392 $im1->setpixel(x => 2, 'y' => 0, color => '#FF00FF');
393 $im2->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
395 my $diff1 = $im1->difference(other => $im2);
396 my $cmp1 = Imager->new(xsize => 3, ysize => 2, channels => 4);
397 $cmp1->setpixel(x => 1, 'y' => 0, color => '#FF01FF');
398 $cmp1->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
399 is_image($diff1, $cmp1, "difference() - check image with mindist 0");
401 my $diff2 = $im1->difference(other => $im2, mindist => 1);
402 my $cmp2 = Imager->new(xsize => 3, ysize => 2, channels => 4);
403 $cmp2->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
404 is_image($diff2, $cmp2, "difference() - check image with mindist 1");
408 # and again with large samples
409 my $im1 = Imager->new(xsize => 3, ysize => 2, bits => 'double');
410 $im1->box(filled => 1, color => '#FF0000');
411 my $im2 = $im1->copy;
412 $im1->setpixel(x => 1, 'y' => 0, color => '#FF00FF');
413 $im2->setpixel(x => 1, 'y' => 0, color => '#FF01FF');
414 $im1->setpixel(x => 2, 'y' => 0, color => '#FF00FF');
415 $im2->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
417 my $diff1 = $im1->difference(other => $im2);
418 my $cmp1 = Imager->new(xsize => 3, ysize => 2, channels => 4);
419 $cmp1->setpixel(x => 1, 'y' => 0, color => '#FF01FF');
420 $cmp1->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
421 is_image($diff1, $cmp1, "difference() - check image with mindist 0 - large samples");
423 my $diff2 = $im1->difference(other => $im2, mindist => 1.1);
424 my $cmp2 = Imager->new(xsize => 3, ysize => 2, channels => 4);
425 $cmp2->setpixel(x => 2, 'y' => 0, color => '#FF02FF');
426 is_image($diff2, $cmp2, "difference() - check image with mindist 1.1 - large samples");
430 my $empty = Imager->new;
431 ok(!$empty->filter(type => "hardinvert"), "can't filter an empty image");
432 is($empty->errstr, "filter: empty input image",
433 "check error message");
434 ok(!$empty->difference(other => $imbase), "can't difference empty image");
435 is($empty->errstr, "difference: empty input image",
436 "check error message");
437 ok(!$imbase->difference(other => $empty),
438 "can't difference against empty image");
439 is($imbase->errstr, "difference: empty input image (other image)",
440 "check error message");
444 my ($in, $params, $out) = @_;
446 my $copy = $in->copy;
447 if (ok($copy->filter(%$params), $params->{type})) {
448 ok($copy->write(file=>$out), "write $params->{type}")
449 or print "# ",$copy->errstr,"\n";
455 skip("couldn't filter", 1);
468 if (abs($c1[$i]-$c2[$i]) > 2) {