3 use Test::More tests => 191;
5 use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image);
7 init_log("testout/t104ppm.log",1);
9 my $green = i_color_new(0,255,0,255);
10 my $blue = i_color_new(0,0,255,255);
11 my $red = i_color_new(255,0,0,255);
13 my $img = test_image_raw();
15 my $fh = openimage(">testout/t104.ppm");
16 my $IO = Imager::io_new_fd(fileno($fh));
17 ok(i_writeppm_wiol($img, $IO), "write pnm low")
18 or die "Cannot write testout/t104.ppm\n";
21 $IO = Imager::io_new_bufchain();
22 ok(i_writeppm_wiol($img, $IO), "write to bufchain")
23 or die "Cannot write to bufchain";
24 my $data = Imager::io_slurp($IO);
26 $fh = openimage("testout/t104.ppm");
27 $IO = Imager::io_new_fd( fileno($fh) );
28 my $cmpimg = i_readpnm_wiol($IO,-1);
29 ok($cmpimg, "read image we wrote")
30 or die "Cannot read testout/t104.ppm\n";
33 is(i_img_diff($img, $cmpimg), 0, "compare written and read images");
35 my $rdata = slurp("testout/t104.ppm");
36 is($data, $rdata, "check data read from file and bufchain data");
38 # build a grayscale image
39 my $gimg = Imager::ImgRaw::new(150, 150, 1);
40 my $gray = i_color_new(128, 0, 0, 255);
41 my $dgray = i_color_new(64, 0, 0, 255);
42 my $white = i_color_new(255, 0, 0, 255);
43 i_box_filled($gimg, 20, 20, 130, 130, $gray);
44 i_box_filled($gimg, 40, 40, 110, 110, $dgray);
45 i_arc($gimg, 75, 75, 30, 0, 361, $white);
47 open FH, "> testout/t104_gray.pgm" or die "Cannot create testout/t104_gray.pgm: $!\n";
49 $IO = Imager::io_new_fd(fileno(FH));
50 ok(i_writeppm_wiol($gimg, $IO), "write grayscale");
53 open FH, "< testout/t104_gray.pgm" or die "Cannot open testout/t104_gray.pgm: $!\n";
55 $IO = Imager::io_new_fd(fileno(FH));
56 my $gcmpimg = i_readpnm_wiol($IO, -1);
57 ok($gcmpimg, "read grayscale");
58 is(i_img_diff($gimg, $gcmpimg), 0,
59 "compare written and read greyscale images");
61 my $ooim = Imager->new;
62 ok($ooim->read(file=>"testimg/simple.pbm"), "read simple pbm, via OO");
64 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 0), 0);
65 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 1), 255);
66 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 0), 255);
67 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 1), 0);
68 is($ooim->type, 'paletted', "check pbm read as paletted");
69 is($ooim->tags(name=>'pnm_type'), 1, "check pnm_type tag");
72 # https://rt.cpan.org/Ticket/Display.html?id=7465
73 # the pnm reader ignores the maxval that it reads from the pnm file
74 my $maxval = Imager->new;
75 ok($maxval->read(file=>"testimg/maxval.ppm"),
76 "read testimg/maxval.ppm");
78 # this image contains three pixels, with each sample from 0 to 63
79 # the pixels are (63, 63, 63), (32, 32, 32) and (31, 31, 0)
81 # check basic parameters
82 is($maxval->getchannels, 3, "channel count");
83 is($maxval->getwidth, 3, "width");
84 is($maxval->getheight, 1, "height");
87 ok(my ($white, $grey, $green) = $maxval->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
88 is_color3($white, 255, 255, 255, "white pixel");
89 is_color3($grey, 130, 130, 130, "grey pixel");
90 is_color3($green, 125, 125, 0, "green pixel");
91 is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval");
93 # and do the same for ASCII images
94 my $maxval_asc = Imager->new;
95 ok($maxval_asc->read(file=>"testimg/maxval_asc.ppm"),
96 "read testimg/maxval_asc.ppm");
98 # this image contains three pixels, with each sample from 0 to 63
99 # the pixels are (63, 63, 63), (32, 32, 32) and (31, 31, 0)
101 # check basic parameters
102 is($maxval_asc->getchannels, 3, "channel count");
103 is($maxval_asc->getwidth, 3, "width");
104 is($maxval_asc->getheight, 1, "height");
106 is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval");
109 ok(my ($white_asc, $grey_asc, $green_asc) = $maxval_asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
110 is_color3($white_asc, 255, 255, 255, "white asc pixel");
111 is_color3($grey_asc, 130, 130, 130, "grey asc pixel");
112 is_color3($green_asc, 125, 125, 0, "green asc pixel");
115 { # previously we didn't validate maxval at all, make sure it's
117 my $maxval0 = Imager->new;
118 ok(!$maxval0->read(file=>'testimg/maxval_0.ppm'),
119 "should fail to read maxval 0 image");
120 print "# ", $maxval0->errstr, "\n";
121 like($maxval0->errstr, qr/maxval is zero - invalid pnm file/,
122 "error expected from reading maxval_0.ppm");
124 my $maxval65536 = Imager->new;
125 ok(!$maxval65536->read(file=>'testimg/maxval_65536.ppm'),
126 "should fail reading maxval 65536 image");
127 print "# ",$maxval65536->errstr, "\n";
128 like($maxval65536->errstr, qr/maxval of 65536 is over 65535 - invalid pnm file/,
129 "error expected from reading maxval_65536.ppm");
131 # maxval of 256 is valid, and handled as of 0.56
132 my $maxval256 = Imager->new;
133 ok($maxval256->read(file=>'testimg/maxval_256.ppm'),
134 "should succeed reading maxval 256 image");
135 is_color3($maxval256->getpixel(x => 0, 'y' => 0),
136 0, 0, 0, "check black in maxval_256");
137 is_color3($maxval256->getpixel(x => 0, 'y' => 1),
138 255, 255, 255, "check white in maxval_256");
139 is($maxval256->bits, 16, "check bits/sample on maxval 256");
141 # make sure we handle maxval > 255 for ascii
142 my $maxval4095asc = Imager->new;
143 ok($maxval4095asc->read(file=>'testimg/maxval_4095_asc.ppm'),
144 "read maxval_4095_asc.ppm");
145 is($maxval4095asc->getchannels, 3, "channels");
146 is($maxval4095asc->getwidth, 3, "width");
147 is($maxval4095asc->getheight, 1, "height");
148 is($maxval4095asc->bits, 16, "check bits/sample on maxval 4095");
150 ok(my ($white, $grey, $green) = $maxval4095asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
151 is_color3($white, 255, 255, 255, "white 4095 pixel");
152 is_color3($grey, 128, 128, 128, "grey 4095 pixel");
153 is_color3($green, 127, 127, 0, "green 4095 pixel");
156 { # check i_format is set when reading a pnm file
157 # doesn't really matter which file.
158 my $maxval = Imager->new;
159 ok($maxval->read(file=>"testimg/maxval.ppm"),
161 my ($type) = $maxval->tags(name=>'i_format');
162 is($type, 'pnm', "check i_format");
165 { # check file limits are checked
166 my $limit_file = "testout/t104.ppm";
167 ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
168 my $im = Imager->new;
169 ok(!$im->read(file=>$limit_file),
170 "should fail read due to size limits");
171 print "# ",$im->errstr,"\n";
172 like($im->errstr, qr/image width/, "check message");
174 ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
175 ok(!$im->read(file=>$limit_file),
176 "should fail read due to size limits");
177 print "# ",$im->errstr,"\n";
178 like($im->errstr, qr/image height/, "check message");
180 ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
181 ok($im->read(file=>$limit_file),
182 "should succeed - just inside width limit");
183 ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
184 ok($im->read(file=>$limit_file),
185 "should succeed - just inside height limit");
187 # 150 x 150 x 3 channel image uses 67500 bytes
188 ok(Imager->set_file_limits(reset=>1, bytes=>67499),
189 "set bytes limit 67499");
190 ok(!$im->read(file=>$limit_file),
191 "should fail - too many bytes");
192 print "# ",$im->errstr,"\n";
193 like($im->errstr, qr/storage size/, "check error message");
194 ok(Imager->set_file_limits(reset=>1, bytes=>67500),
195 "set bytes limit 67500");
196 ok($im->read(file=>$limit_file),
197 "should succeed - just inside bytes limit");
198 Imager->set_file_limits(reset=>1);
202 # check we correctly sync with the data stream
203 my $im = Imager->new;
204 ok($im->read(file => 'testimg/pgm.pgm', type => 'pnm'),
206 or print "# cannot read pgm.pgm: ", $im->errstr, "\n";
207 print "# ", $im->getsamples('y' => 0), "\n";
208 is_color1($im->getpixel(x=>0, 'y' => 0), 254, "check top left");
211 { # check error messages set correctly
212 my $im = Imager->new;
213 ok(!$im->read(file=>'t/t104ppm.t', type=>'pnm'),
214 'should fail to read script as an image file');
215 is($im->errstr, 'unable to read pnm image: bad header magic, not a PNM file',
216 "check error message");
221 # give 4/2 channel images a background color when saving to pnm
222 my $im = Imager->new(xsize=>16, ysize=>16, channels=>4);
223 $im->box(filled => 1, xmin => 8, color => '#FFE0C0');
224 $im->box(filled => 1, color => NC(0, 192, 192, 128),
225 ymin => 8, xmax => 7);
226 ok($im->write(file=>"testout/t104_alpha.ppm", type=>'pnm'),
227 "should succeed writing 4 channel image");
228 my $imread = Imager->new;
229 ok($imread->read(file => 'testout/t104_alpha.ppm'), "read it back");
230 is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0,
231 "check transparent became black");
232 is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
233 "check color came through");
234 is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96,
235 "check translucent came through");
237 ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000'),
238 "write with red background");
239 ok($imread->read(data => $data, type => 'pnm'),
241 is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0,
242 "check transparent became red");
243 is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
244 "check color came through");
245 is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96,
246 "check translucent came through");
250 # more RT #30074 - 16 bit images
251 my $im = Imager->new(xsize=>16, ysize=>16, channels=>4, bits => 16);
252 $im->box(filled => 1, xmin => 8, color => '#FFE0C0');
253 $im->box(filled => 1, color => NC(0, 192, 192, 128),
254 ymin => 8, xmax => 7);
255 ok($im->write(file=>"testout/t104_alp16.ppm", type=>'pnm',
256 pnm_write_wide_data => 1),
257 "should succeed writing 4 channel image");
258 my $imread = Imager->new;
259 ok($imread->read(file => 'testout/t104_alp16.ppm'), "read it back");
260 is($imread->bits, 16, "check we did produce a 16 bit image");
261 is_color3($imread->getpixel('x' => 0, 'y' => 0), 0, 0, 0,
262 "check transparent became black");
263 is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
264 "check color came through");
265 is_color3($imread->getpixel('x' => 0, 'y' => 15), 0, 96, 96,
266 "check translucent came through");
268 ok($im->write(data => \$data, type => 'pnm', i_background => '#FF0000',
269 pnm_write_wide_data => 1),
270 "write with red background");
271 ok($imread->read(data => $data, type => 'pnm'),
273 is($imread->bits, 16, "check it's 16-bit");
274 is_color3($imread->getpixel('x' => 0, 'y' => 0), 255, 0, 0,
275 "check transparent became red");
276 is_color3($imread->getpixel('x' => 8, 'y' => 0), 255, 224, 192,
277 "check color came through");
278 is_color3($imread->getpixel('x' => 0, 'y' => 15), 127, 96, 96,
279 "check translucent came through");
282 # various bad input files
283 print "# check error handling\n";
285 my $im = Imager->new;
286 ok(!$im->read(file => 'testimg/short_bin.ppm', type=>'pnm'),
287 "fail to read short bin ppm");
288 cmp_ok($im->errstr, '=~', 'short read - file truncated',
289 "check error message");
293 my $im = Imager->new;
294 ok(!$im->read(file => 'testimg/short_bin16.ppm', type=>'pnm'),
295 "fail to read short bin ppm (maxval 65535)");
296 cmp_ok($im->errstr, '=~', 'short read - file truncated',
297 "check error message");
301 my $im = Imager->new;
302 ok(!$im->read(file => 'testimg/short_bin.pgm', type=>'pnm'),
303 "fail to read short bin pgm");
304 cmp_ok($im->errstr, '=~', 'short read - file truncated',
305 "check error message");
309 my $im = Imager->new;
310 ok(!$im->read(file => 'testimg/short_bin16.pgm', type=>'pnm'),
311 "fail to read short bin pgm (maxval 65535)");
312 cmp_ok($im->errstr, '=~', 'short read - file truncated',
313 "check error message");
317 my $im = Imager->new;
318 ok(!$im->read(file => 'testimg/short_bin.pbm', type => 'pnm'),
319 "fail to read a short bin pbm");
320 cmp_ok($im->errstr, '=~', 'short read - file truncated',
321 "check error message");
325 my $im = Imager->new;
326 ok(!$im->read(file => 'testimg/short_asc.ppm', type => 'pnm'),
327 "fail to read a short asc ppm");
328 cmp_ok($im->errstr, '=~', 'short read - file truncated',
329 "check error message");
333 my $im = Imager->new;
334 ok(!$im->read(file => 'testimg/short_asc.pgm', type => 'pnm'),
335 "fail to read a short asc pgm");
336 cmp_ok($im->errstr, '=~', 'short read - file truncated',
337 "check error message");
341 my $im = Imager->new;
342 ok(!$im->read(file => 'testimg/short_asc.pbm', type => 'pnm'),
343 "fail to read a short asc pbm");
344 cmp_ok($im->errstr, '=~', 'short read - file truncated',
345 "check error message");
349 my $im = Imager->new;
350 ok(!$im->read(file => 'testimg/bad_asc.ppm', type => 'pnm'),
351 "fail to read a bad asc ppm");
352 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
353 "check error message");
357 my $im = Imager->new;
358 ok(!$im->read(file => 'testimg/bad_asc.pgm', type => 'pnm'),
359 "fail to read a bad asc pgm");
360 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
361 "check error message");
365 my $im = Imager->new;
366 ok(!$im->read(file => 'testimg/bad_asc.pbm', type => 'pnm'),
367 "fail to read a bad asc pbm");
368 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
369 "check error message");
373 my $im = Imager->new;
374 ok($im->read(file => 'testimg/short_bin.ppm', type => 'pnm',
375 allow_incomplete => 1),
376 "partial read bin ppm");
377 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
378 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
382 my $im = Imager->new;
383 ok($im->read(file => 'testimg/short_bin16.ppm', type => 'pnm',
384 allow_incomplete => 1),
385 "partial read bin16 ppm");
386 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
387 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
388 is($im->bits, 16, "check correct bits");
392 my $im = Imager->new;
393 ok($im->read(file => 'testimg/short_bin.pgm', type => 'pnm',
394 allow_incomplete => 1),
395 "partial read bin pgm");
396 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
397 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
401 my $im = Imager->new;
402 ok($im->read(file => 'testimg/short_bin16.pgm', type => 'pnm',
403 allow_incomplete => 1),
404 "partial read bin16 pgm");
405 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
406 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
410 my $im = Imager->new;
411 ok($im->read(file => 'testimg/short_bin.pbm', type => 'pnm',
412 allow_incomplete => 1),
413 "partial read bin pbm");
414 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
415 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
419 my $im = Imager->new;
420 ok($im->read(file => 'testimg/short_asc.ppm', type => 'pnm',
421 allow_incomplete => 1),
422 "partial read asc ppm");
423 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
424 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
428 my $im = Imager->new;
429 ok($im->read(file => 'testimg/short_asc.pgm', type => 'pnm',
430 allow_incomplete => 1),
431 "partial read asc pgm");
432 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
433 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
437 my $im = Imager->new;
438 ok($im->read(file => 'testimg/short_asc.pbm', type => 'pnm',
439 allow_incomplete => 1),
440 "partial read asc pbm");
441 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
442 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
446 my @imgs = Imager->read_multi(file => 'testimg/multiple.ppm');
447 is( 0+@imgs, 3, "Read 3 images");
448 is( $imgs[0]->tags( name => 'pnm_type' ), 1, "Image 1 is type 1" );
449 is( $imgs[0]->getwidth, 2, " ... width=2" );
450 is( $imgs[0]->getheight, 2, " ... width=2" );
451 is( $imgs[1]->tags( name => 'pnm_type' ), 6, "Image 2 is type 6" );
452 is( $imgs[1]->getwidth, 164, " ... width=164" );
453 is( $imgs[1]->getheight, 180, " ... width=180" );
454 is( $imgs[2]->tags( name => 'pnm_type' ), 5, "Image 3 is type 5" );
455 is( $imgs[2]->getwidth, 2, " ... width=2" );
456 is( $imgs[2]->getheight, 2, " ... width=2" );
460 my $im = Imager->new;
461 ok($im->read(file => 'testimg/bad_asc.ppm', type => 'pnm',
462 allow_incomplete => 1),
463 "partial read bad asc ppm");
464 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
465 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
469 my $im = Imager->new;
470 ok($im->read(file => 'testimg/bad_asc.pgm', type => 'pnm',
471 allow_incomplete => 1),
472 "partial read bad asc pgm");
473 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
474 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
478 my $im = Imager->new;
479 ok($im->read(file => 'testimg/bad_asc.pbm', type => 'pnm',
480 allow_incomplete => 1),
481 "partial read bad asc pbm");
482 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
483 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
487 print "# monochrome output\n";
488 my $im = Imager->new(xsize => 10, ysize => 10, channels => 1, type => 'paletted');
489 ok($im->addcolors(colors => [ '#000000', '#FFFFFF' ]),
490 "add black and white");
491 $im->box(filled => 1, xmax => 4, color => '#000000');
492 $im->box(filled => 1, xmin => 5, color => '#FFFFFF');
493 is($im->type, 'paletted', 'mono still paletted');
494 ok($im->write(file => 'testout/t104_mono.pbm', type => 'pnm'),
498 my $imread = Imager->new;
499 ok($imread->read(file => 'testout/t104_mono.pbm', type=>'pnm'),
501 or print "# ", $imread->errstr, "\n";
502 is($imread->type, 'paletted', "check result is paletted");
503 is($imread->tags(name => 'pnm_type'), 4, "check type");
504 is_image($im, $imread, "check image matches");
508 print "# monochrome output - reversed palette\n";
509 my $im = Imager->new(xsize => 10, ysize => 10, channels => 1, type => 'paletted');
510 ok($im->addcolors(colors => [ '#FFFFFF', '#000000' ]),
511 "add white and black");
512 $im->box(filled => 1, xmax => 4, color => '#000000');
513 $im->box(filled => 1, xmin => 5, color => '#FFFFFF');
514 is($im->type, 'paletted', 'mono still paletted');
515 ok($im->write(file => 'testout/t104_mono2.pbm', type => 'pnm'),
519 my $imread = Imager->new;
520 ok($imread->read(file => 'testout/t104_mono2.pbm', type=>'pnm'),
522 or print "# ", $imread->errstr, "\n";
523 is($imread->type, 'paletted', "check result is paletted");
524 is($imread->tags(name => 'pnm_type'), 4, "check type");
525 is_image($im, $imread, "check image matches");
529 print "# 16-bit output\n";
531 my $im = test_image_16();
533 # without tag, it should do 8-bit output
534 ok($im->write(data => \$data, type => 'pnm'),
535 "write 16-bit image as 8-bit/sample ppm");
536 my $im8 = Imager->new;
537 ok($im8->read(data => $data), "read it back");
538 is($im8->tags(name => 'pnm_maxval'), 255, "check maxval");
539 is_image($im, $im8, "check image matches");
542 $im->settag(name => 'pnm_write_wide_data', value => 1);
544 ok($im->write(data => \$data, type => 'pnm'),
545 "write 16-bit image as 16-bit/sample ppm");
546 $im->write(file=>'testout/t104_16.ppm');
547 my $im16 = Imager->new;
548 ok($im16->read(data => $data), "read it back");
549 is($im16->tags(name => 'pnm_maxval'), 65535, "check maxval");
550 $im16->write(file=>'testout/t104_16b.ppm');
551 is_image($im, $im16, "check image matches");
555 ok(grep($_ eq 'pnm', Imager->read_types), "check pnm in read types");
556 ok(grep($_ eq 'pnm', Imager->write_types), "check pnm in write types");
559 { # test new() loading an image
560 my $im = Imager->new(file => "testimg/penguin-base.ppm");
561 ok($im, "received an image");
562 is($im->getwidth, 164, "check width matches image");
564 # fail to load an image
565 my $im2 = Imager->new(file => "Imager.pm", filetype => "pnm");
566 ok(!$im2, "no image when file failed to load");
567 cmp_ok(Imager->errstr, '=~', "bad header magic, not a PNM file",
568 "check error message transferred");
573 ok(open(FH, "< testimg/penguin-base.ppm"), "open test file")
574 or skip("couldn't open data source", 4);
576 my $imdata = do { local $/; <FH> };
578 ok(length $imdata, "we got the data");
579 my $im3 = Imager->new(data => $imdata);
580 ok($im3, "read the file data");
581 is($im3->getwidth, 164, "check width matches image");
588 open(FH, $fname) or die "Cannot open $fname: $!\n";
594 my $fh = openimage(shift);
605 is($g, $gray, "compare gray");