]> git.imager.perl.org - imager.git/blob - t/t20fill.t
025f3453f131b03176ab6a72dfc73dff3dc5f93a
[imager.git] / t / t20fill.t
1 #!perl -w
2 use strict;
3
4 print "1..40\n";
5
6 use Imager ':handy';
7 use Imager::Fill;
8 use Imager::Color::Float;
9
10 sub ok ($$$);
11
12 Imager::init_log("testout/t20fill.log", 1);
13
14 my $blue = NC(0,0,255);
15 my $red = NC(255, 0, 0);
16 my $redf = Imager::Color::Float->new(1, 0, 0);
17 my $rsolid = Imager::i_new_fill_solid($blue, 0);
18 ok(1, $rsolid, "building solid fill");
19 my $raw1 = Imager::ImgRaw::new(100, 100, 3);
20 # use the normal filled box
21 Imager::i_box_filled($raw1, 0, 0, 99, 99, $blue);
22 my $raw2 = Imager::ImgRaw::new(100, 100, 3);
23 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rsolid);
24 ok(2, 1, "drawing with solid fill");
25 my $diff = Imager::i_img_diff($raw1, $raw2);
26 ok(3, $diff == 0, "solid fill doesn't match");
27 Imager::i_box_filled($raw1, 0, 0, 99, 99, $red);
28 my $rsolid2 = Imager::i_new_fill_solidf($redf, 0);
29 ok(4, $rsolid2, "creating float solid fill");
30 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rsolid2);
31 $diff = Imager::i_img_diff($raw1, $raw2);
32 ok(5, $diff == 0, "float solid fill doesn't match");
33
34 # ok solid still works, let's try a hatch
35 # hash1 is a 2x2 checkerboard
36 my $rhatcha = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 0, 0);
37 my $rhatchb = Imager::i_new_fill_hatch($blue, $red, 0, 1, undef, 2, 0);
38 ok(6, $rhatcha && $rhatchb, "can't build hatched fill");
39
40 # the offset should make these match
41 Imager::i_box_cfill($raw1, 0, 0, 99, 99, $rhatcha);
42 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb);
43 ok(7, 1, "filling with hatch");
44 $diff = Imager::i_img_diff($raw1, $raw2);
45 ok(8, $diff == 0, "hatch images different");
46 $rhatchb = Imager::i_new_fill_hatch($blue, $red, 0, 1, undef, 4, 6);
47 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb);
48 $diff = Imager::i_img_diff($raw1, $raw2);
49 ok(9, $diff == 0, "hatch images different");
50
51 # I guess I was tired when I originally did this - make sure it keeps
52 # acting the way it's meant to
53 # I had originally expected these to match with the red and blue swapped
54 $rhatchb = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 2, 2);
55 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb);
56 $diff = Imager::i_img_diff($raw1, $raw2);
57 ok(10, $diff == 0, "hatch images different");
58
59 # this shouldn't match
60 $rhatchb = Imager::i_new_fill_hatch($red, $blue, 0, 1, undef, 1, 1);
61 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rhatchb);
62 $diff = Imager::i_img_diff($raw1, $raw2);
63 ok(11, $diff, "hatch images the same!");
64
65 # custom hatch
66 # the inverse of the 2x2 checkerboard
67 my $hatch = pack("C8", 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC);
68 my $rcustom = Imager::i_new_fill_hatch($blue, $red, 0, 0, $hatch, 0, 0);
69 Imager::i_box_cfill($raw2, 0, 0, 99, 99, $rcustom);
70 $diff = Imager::i_img_diff($raw1, $raw2);
71 ok(12, !$diff, "custom hatch mismatch");
72
73 # test the oo interface
74 my $im1 = Imager->new(xsize=>100, ysize=>100);
75 my $im2 = Imager->new(xsize=>100, ysize=>100);
76
77 my $solid = Imager::Fill->new(solid=>'#FF0000');
78 ok(13, $solid, "creating oo solid fill");
79 ok(14, $solid->{fill}, "bad oo solid fill");
80 $im1->box(fill=>$solid);
81 $im2->box(filled=>1, color=>$red);
82 $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG});
83 ok(15, !$diff, "oo solid fill");
84
85 my $hatcha = Imager::Fill->new(hatch=>'check2x2');
86 my $hatchb = Imager::Fill->new(hatch=>'check2x2', dx=>2);
87 $im1->box(fill=>$hatcha);
88 $im2->box(fill=>$hatchb);
89 # should be different
90 $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG});
91 ok(16, $diff, "offset checks the same!");
92 $hatchb = Imager::Fill->new(hatch=>'check2x2', dx=>2, dy=>2);
93 $im2->box(fill=>$hatchb);
94 $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG});
95 ok(17, !$diff, "offset into similar check should be the same");
96
97 # test dymanic build of fill
98 $im2->box(fill=>{hatch=>'check2x2', dx=>2, fg=>NC(255,255,255), 
99                  bg=>NC(0,0,0)});
100 $diff = Imager::i_img_diff($im1->{IMG}, $im2->{IMG});
101 ok(18, !$diff, "offset and flipped should be the same");
102
103 # a simple demo
104 my $im = Imager->new(xsize=>200, ysize=>200);
105
106 $im->box(xmin=>10, ymin=>10, xmax=>190, ymax=>190,
107          fill=>{ hatch=>'check4x4',
108                  fg=>NC(128, 0, 0),
109                  bg=>NC(128, 64, 0) })
110   or print "# ",$im->errstr,"\n";
111 $im->arc(r=>80, d1=>45, d2=>75, 
112            fill=>{ hatch=>'stipple2',
113                    combine=>1,
114                    fg=>[ 0, 0, 0, 255 ],
115                    bg=>{ rgba=>[255,255,255,160] } })
116   or print "# ",$im->errstr,"\n";
117 $im->arc(r=>80, d1=>75, d2=>135,
118          fill=>{ fountain=>'radial', xa=>100, ya=>100, xb=>20, yb=>100 })
119   or print "# ",$im->errstr,"\n";
120 $im->write(file=>'testout/t20_sample.ppm');
121
122 # flood fill tests
123 my $rffimg = Imager::ImgRaw::new(100, 100, 3);
124 # build a H 
125 Imager::i_box_filled($rffimg, 10, 10, 20, 90, $blue);
126 Imager::i_box_filled($rffimg, 80, 10, 90, 90, $blue);
127 Imager::i_box_filled($rffimg, 20, 45, 80, 55, $blue);
128 my $black = Imager::Color->new(0, 0, 0);
129 Imager::i_flood_fill($rffimg, 15, 15, $red);
130 my $rffcmp = Imager::ImgRaw::new(100, 100, 3);
131 # build a H 
132 Imager::i_box_filled($rffcmp, 10, 10, 20, 90, $red);
133 Imager::i_box_filled($rffcmp, 80, 10, 90, 90, $red);
134 Imager::i_box_filled($rffcmp, 20, 45, 80, 55, $red);
135 $diff = Imager::i_img_diff($rffimg, $rffcmp);
136 ok(19, !$diff, "flood fill difference");
137
138 my $ffim = Imager->new(xsize=>100, ysize=>100);
139 my $yellow = Imager::Color->new(255, 255, 0);
140 $ffim->box(xmin=>10, ymin=>10, xmax=>20, ymax=>90, color=>$blue, filled=>1);
141 $ffim->box(xmin=>20, ymin=>45, xmax=>80, ymax=>55, color=>$blue, filled=>1);
142 $ffim->box(xmin=>80, ymin=>10, xmax=>90, ymax=>90, color=>$blue, filled=>1);
143 ok(20, $ffim->flood_fill('x'=>50, 'y'=>50, color=>$red), "flood fill");
144 $diff = Imager::i_img_diff($rffcmp, $ffim->{IMG});
145 ok(21, !$diff, "oo flood fill difference");
146 $ffim->flood_fill('x'=>50, 'y'=>50,
147                   fill=> {
148                           hatch => 'check2x2'
149                          });
150 #                  fill=>{
151 #                         fountain=>'radial',
152 #                         xa=>50, ya=>50,
153 #                         xb=>10, yb=>10,
154 #                        });
155 $ffim->write(file=>'testout/t20_ooflood.ppm');
156
157 # test combining modes
158 my $fill = NC(192, 128, 128, 128);
159 my $target = NC(64, 32, 64);
160 my %comb_tests =
161   (
162    none=>{ result=>$fill },
163    normal=>{ result=>NC(128, 80, 96) },
164    multiply => { result=>NC(56, 24, 48) },
165    dissolve => { result=>[ $target, NC(128, 80, 96) ] },
166    add => { result=>NC(159, 96, 128) },
167    subtract => { result=>NC(31, 15, 31) }, # 31.87, 15.9, 31.87
168    diff => { result=>NC(96, 64, 64) },
169    lighten => { result=>NC(128, 80, 96) },
170    darken => { result=>$target },
171    # the following results are based on the results of the tests and
172    # are suspect for that reason (and were broken at one point <sigh>)
173    # but trying to work them out manually just makes my head hurt - TC
174    hue => { result=>NC(64, 32, 47) },
175    saturation => { result=>NC(63, 37, 64) },
176    value => { result=>NC(127, 64, 128) },
177    color => { result=>NC(64, 37, 52) },
178   );
179
180 my $testnum = 22; # from 22 to 34
181 for my $comb (Imager::Fill->combines) {
182   my $test = $comb_tests{$comb};
183   my $targim = Imager->new(xsize=>1, ysize=>1);
184   $targim->box(filled=>1, color=>$target);
185   my $fillobj = Imager::Fill->new(solid=>$fill, combine=>$comb);
186   $targim->box(fill=>$fillobj);
187   my $c = Imager::i_get_pixel($targim->{IMG}, 0, 0);
188   if ($test->{result} =~ /ARRAY/) {
189     ok($testnum++, scalar grep(color_close($_, $c), @{$test->{result}}), 
190        "combine '$comb'")
191       or print "# got:",join(",", $c->rgba),"  allowed: ", 
192         join("|", map { join(",", $_->rgba) } @{$test->{result}}),"\n";
193   }
194   else {
195     ok($testnum++, color_close($c, $test->{result}), "combine '$comb'")
196       or print "# got: ",join(",", $c->rgba),
197         "  allowed: ",join(",", $test->{result}->rgba),"\n";
198   }
199 }
200
201 ok($testnum++, $ffim->arc(r=>45, color=>$blue, aa=>1), "aa circle");
202 $ffim->write(file=>"testout/t20_aacircle.ppm");
203
204 # image based fills
205 my $green = NC(0, 255, 0);
206 my $fillim = Imager->new(xsize=>40, ysize=>40, channels=>4);
207 $fillim->box(filled=>1, xmin=>5, ymin=>5, xmax=>35, ymax=>35, 
208              color=>NC(0, 0, 255, 128));
209 $fillim->arc(filled=>1, r=>10, color=>$green, aa=>1);
210 my $ooim = Imager->new(xsize=>150, ysize=>150);
211 $ooim->box(filled=>1, color=>$green, xmin=>70, ymin=>25, xmax=>130, ymax=>125);
212 $ooim->box(filled=>1, color=>$blue, xmin=>20, ymin=>25, xmax=>80, ymax=>125);
213 $ooim->arc(r=>30, color=>$red, aa=>1);
214
215 my $oocopy = $ooim->copy();
216 ok($testnum++, 
217    $oocopy->arc(fill=>{image=>$fillim, 
218                        combine=>'normal',
219                        xoff=>5}, r=>40),
220    "image based fill");
221 $oocopy->write(file=>'testout/t20_image.ppm');
222
223 # a more complex version
224 use Imager::Matrix2d ':handy';
225 $oocopy = $ooim->copy;
226 ok($testnum++,
227    $oocopy->arc(fill=>{
228                        image=>$fillim,
229                        combine=>'normal',
230                        matrix=>m2d_rotate(degrees=>30),
231                        xoff=>5
232                        }, r=>40),
233    "transformed image based fill");
234 $oocopy->write(file=>'testout/t20_image_xform.ppm');
235
236 ok($testnum++,
237    !$oocopy->arc(fill=>{ hatch=>"not really a hatch" }, r=>20),
238    "error handling of automatic fill conversion");
239 ok($testnum++,
240    $oocopy->errstr =~ /Unknown hatch type/,
241    "error message for automatic fill conversion");
242
243 # previous box fills to float images, or using the fountain fill
244 # got into a loop here
245 {
246   local $SIG{ALRM} = sub { die; };
247
248   eval {
249     alarm(2);
250     ok($testnum,
251        $ooim->box(xmin=>20, ymin=>20, xmax=>80, ymax=>40,
252                   fill=>{ fountain=>'linear', xa=>20, ya=>20, xb=>80, 
253                           yb=>20 }), "linear box fill");
254     ++$testnum;
255     alarm 0;
256   };
257   $@ and ok($testnum++, 0, "linear box fill $@");
258 }
259
260 sub ok ($$$) {
261   my ($num, $test, $desc) = @_;
262
263   if ($test) {
264     print "ok $num\n";
265   }
266   else {
267     print "not ok $num # $desc\n";
268   }
269   $test;
270 }
271
272 sub color_close {
273   my ($c1, $c2) = @_;
274
275   my @c1 = $c1->rgba;
276   my @c2 = $c2->rgba;
277
278   for my $i (0..2) {
279     if (abs($c1[$i]-$c2[$i]) > 2) {
280       return 0;
281     }
282   }
283   return 1;
284 }
285
286 # for use during testing
287 sub save {
288   my ($im, $name) = @_;
289
290   open FH, "> $name" or die "Cannot create $name: $!";
291   binmode FH;
292   my $io = Imager::io_new_fd(fileno(FH));
293   Imager::i_writeppm_wiol($im, $io) or die "Cannot save to $name";
294   undef $io;
295   close FH;
296 }