File Coverage

blib/lib/PDF/Builder/Resource/XObject/Image/PNM.pm
Criterion Covered Total %
statement 137 329 41.6
branch 43 146 29.4
condition 6 39 15.3
subroutine 12 12 100.0
pod 1 5 20.0
total 199 531 37.4


line stmt bran cond sub pod time code
1             package PDF::Builder::Resource::XObject::Image::PNM;
2              
3             # For spec details, see man pages pam(5), pbm(5), pgm(5), pnm(5), ppm(5)
4              
5 2     2   1346 use base 'PDF::Builder::Resource::XObject::Image';
  2         5  
  2         645  
6              
7 2     2   15 use strict;
  2         4  
  2         41  
8 2     2   11 use warnings;
  2         4  
  2         100  
9             #no warnings qw[ deprecated recursion uninitialized ];
10              
11             our $VERSION = '3.023'; # VERSION
12             our $LAST_UPDATE = '3.021'; # manually update whenever code is changed
13              
14 2     2   12 use IO::File;
  2         3  
  2         367  
15 2     2   16 use PDF::Builder::Util;
  2         5  
  2         325  
16 2     2   18 use PDF::Builder::Basic::PDF::Utils;
  2         4  
  2         179  
17 2     2   14 use Scalar::Util qw(weaken);
  2         4  
  2         6079  
18              
19             =head1 NAME
20              
21             PDF::Builder::Resource::XObject::Image::PNM - support routines for PNM (Portable aNy Map) image library. Inherits from L
22              
23             =head2 METHODS
24              
25             =over
26              
27             =new($pdf, $file, $name)
28              
29             Returns an image in the PDF. PNM types 1 (ASCII/plain bi-level/PBM),
30             2 (ASCII/plain grayscale/PGM), 3 (ASCII/plain RGB/PPM),
31             4 (binary/raw bi-level/PBM), 5 (binary/raw grayscale/PGM), and
32             6 (binary/raw RGB/PPM) are supported.
33              
34             For bi-level, only values 0/1 (white/black) are supported. For grayscale, the
35             maximum sample (full white) may be anything from 1 to 65535, with 0 being full
36             black. If the maximum sample value is 255 or smaller, one byte of raw binary
37             data per pixel, otherwise two bytes. For RGB, each sample (full-on of that
38             color) may be anything from 1 to 65535 (the same maximum for all three colors),
39             with 0 being full black. If the maximum sample value is 255 or smaller, three
40             bytes of raw binary data per pixel, otherwise six bytes.
41              
42             =back
43              
44             =cut
45              
46             # -------------------------------------------------------------------
47             sub new {
48 3     3 1 8 my ($class, $pdf, $file, $name) = @_;
49              
50 3         7 my $self;
51              
52 3 50       8 $class = ref $class if ref $class;
53              
54 3   33     18 $self = $class->SUPER::new($pdf, $name || 'Nx'.pdfkey());
55 3 50       10 $pdf->new_obj($self) unless $self->is_obj($pdf);
56              
57 3         6 $self->{' apipdf'} = $pdf;
58 3         9 weaken $self->{' apipdf'};
59              
60 3         10 $self->read_pnm($pdf, $file);
61              
62 2         7 return $self;
63             }
64              
65             # -------------------------------------------------------------------
66             # READPPMHEADER
67             # taken from Image::PBMLib
68             # Copyright by Benjamin Elijah Griffin (28 Feb 2003)
69             # extensively modified by Phil M Perry, copyright 2020
70             #
71             sub readppmheader {
72 2     2 0 7 my ($gr, $buffer) = @_; # already-opened input file's filehandle
73 2         4 my %info;
74 2         6 $info{'error'} = undef;
75 2         5 my ($width, $height, $max, $comment, $content);
76              
77             # extension: allow whitespace BEFORE the magic number (usually none)
78             # read Px magic number
79 2         6 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
80 2         7 ($buffer, $content) = read_content($gr, $buffer);
81              
82 2 50       6 if (length($content) != 2) {
83 0         0 $info{'error'} = 'Read error or EOF';
84 0         0 return (\%info, $buffer);
85             }
86              
87 2 50       9 if ($content =~ /^P([1-6])/) {
88 2         6 $info{'type'} = $1;
89 2 50       9 if ($info{'type'} > 3) {
90 2         6 $info{'raw'} = 1; # P4-6 is raw (binary)
91             } else {
92 0         0 $info{'raw'} = 0; # P1-3 is plain (ASCII)
93             }
94             } else {
95 0         0 $info{'error'} = 'Unrecognized magic number, not 1..6';
96 0         0 return (\%info, $buffer);
97             }
98              
99 2 50 33     26 if ($info{'type'} == 1 or $info{'type'} == 4) {
    50 33        
100 0         0 $max = 1;
101 0         0 $info{'bgp'} = 'b';
102             } elsif ($info{'type'} == 2 or $info{'type'} == 5) {
103             # need to read and validate 'max'
104 0         0 $info{'bgp'} = 'g';
105             } else { # 3 or 6
106             # need to read and validate 'max'
107 2         4 $info{'bgp'} = 'p';
108             }
109              
110             # expect width as unsigned integer > 0
111 2         6 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
112 2         6 ($buffer, $content) = read_content($gr, $buffer);
113 2 50       6 if (length($content) == 0) {
114 0         0 $info{'error'} = 'Read error or EOF on width';
115 0         0 return (\%info, $buffer);
116             }
117 2 50       11 if ($content =~ m/(^\d+)$/) {
118 2         4 $width = $1;
119             } else {
120 0         0 $info{'error'} = 'Invalid width value '.$1;
121 0         0 return (\%info, $buffer);
122             }
123 2 50       7 if ($width < 1) {
124 0         0 $info{'error'} = 'Invalid width value '.$width;
125 0         0 return (\%info, $buffer);
126             }
127            
128             # expect height as unsigned integer > 0
129 2         6 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
130 2         6 ($buffer, $content) = read_content($gr, $buffer);
131 2 50       6 if (length($content) == 0) {
132 0         0 $info{'error'} = 'Read error or EOF on height';
133 0         0 return (\%info, $buffer);
134             }
135 2 50       9 if ($content =~ m/(^\d+)$/) {
136 2         5 $height = $1;
137             } else {
138 0         0 $info{'error'} = 'Invalid height value '.$1;
139 0         0 return (\%info, $buffer);
140             }
141 2 50       7 if ($height < 1) {
142 0         0 $info{'error'} = 'Invalid height value '.$height;
143 0         0 return (\%info, $buffer);
144             }
145            
146             # expect max sample value as unsigned integer > 0 & < 65536
147             # IF grayscale or pixmap (RGB). already set to 1 for bi-level
148 2 50       17 if ($info{'bgp'} =~ m/^[gp]$/) {
149 2         7 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
150 2         5 ($buffer, $content) = read_content($gr, $buffer);
151 2 50       15 if (length($content) == 0) {
152 0         0 $info{'error'} = 'Read error or EOF on max';
153 0         0 return (\%info, $buffer);
154             }
155 2 50       11 if ($content =~ m/(^\d+)$/) {
156 2         6 $max = $1;
157             } else {
158 0         0 $info{'error'} = 'Invalid max value '.$1;
159 0         0 return (\%info, $buffer);
160             }
161 2 50 33     12 if ($max < 1 || $max > 65535) {
162 0         0 $info{'error'} = 'Invalid max value '.$max;
163 0         0 return (\%info, $buffer);
164             }
165             }
166            
167 2         5 $info{'width'} = $width;
168 2         6 $info{'height'} = $height;
169 2         4 $info{'max'} = $max;
170              
171             # for binary (raw) files, a single whitespace character should be seen.
172             # for ASCII (plain) files, extend to allow arbitrary whitespace
173 2 50       5 if ($info{'raw'}) {
174             # The buffer should have a single ws char in it already, left over from
175             # the previous content read. We don't want to read anything beyond that
176             # in case a byte value happens to be a valid whitespace character! If
177             # the file format is botched and there is additional whitespace, it
178             # will unfortunately be read as binary data.
179 2 50       8 if ($buffer =~ m/^\s/) {
180 2         5 $buffer = substr($buffer, 1); # discard first character
181             } else {
182 0         0 $info{'error'} = 'Expected single whitespace before raster data';
183 0         0 return (\%info, $buffer);
184             }
185             } else {
186             # As an extension, for plain (ASCII) format we allow arbitrary
187             # whitespace (including comments) after the max value and before the
188             # raster data, not just one whitespace.
189 0         0 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
190             }
191              
192 2         8 return (\%info, $buffer);
193             } # end of readppmheader()
194              
195             # -------------------------------------------------------------------
196             # eat and discard whitespace stream, but return any comment(s) found
197             # within the header, cannot have an EOF during whitespace read
198             sub eat_whitespace {
199 8     8 0 16 my ($gr, $buffer, $qflag) = @_;
200             # qflag = 0 if OK to read more from file (don't expect an EOF)
201             # = 1 eating ws at end of image, might hit EOF here
202              
203 8         13 my ($count, $buf, @comment);
204             # first see if enough material is already in the buffer. if not, read some
205 8         13 my $in_comment = 0; # not currently processing a comment, just ws.
206 8         12 while (1) {
207             # is buffer empty? if so, read some content
208 8 100       20 if (length($buffer) == 0) {
209 2         40 $count = read($gr, $buffer, 50); # chunk of up to 50 bytes (could be 0)
210 2 0 0     10 if ($count == 0 && (!$qflag || $in_comment)) {
      33        
211             # EOF or read error, is bad thing here
212 0         0 print STDERR "EOF or read error reading whitespace.\n";
213 0         0 return ($buffer, '');
214             }
215             }
216             # if buffer is still empty (qflag == 1), will exit cleanly
217              
218 8 50       17 if (!$in_comment) { $buffer =~ s/^\s+//; }
  8         51  
219             # a bunch of whitespace may have been discarded. if buffer now starts
220             # with a #, it is a comment to be read to EOL. otherwise we're done.
221 8 50       20 if (length($buffer) > 0) {
222             # buffer still has stuff in it (starts with non-ws)
223 8 50       19 if ($buffer =~ m/^#/) {
224 0         0 $in_comment = 1;
225             # at start of comment. discard up through \n
226             # (\n might not yet be in buffer!)
227             # special case: #\n
228 0 0       0 if ($buffer =~ s/^#\n//) {
    0          
229             # special empty case
230 0         0 $in_comment = 0;
231             } elsif ($buffer =~ s/^#\s*([^\n]*)\n//) {
232 0         0 push @comment, $1; # has been removed from buffer
233 0         0 $in_comment = 0;
234             } else {
235             # haven't gotten to end of comment (\n) yet
236 0         0 $count = read($gr, $buf, 50);
237 0 0       0 if ($count == 0) {
238             # EOF or read error, is bad thing here
239 0         0 print STDERR "EOF or read error reading whitespace in pixel data\n";
240 0         0 return ($buffer, '');
241             }
242 0         0 $buffer .= $buf;
243 0         0 next;
244             }
245             } else {
246             # non-whitespace, not #. content to be left in buffer
247 8         13 $in_comment = 0;
248 8         14 last;
249             }
250             } else {
251             # empty buffer, need to read some more
252 0 0 0     0 if ($qflag && !$in_comment) { last; }
  0         0  
253 0         0 next;
254             }
255             } # while(1) until run out of whitespace
256              
257 8         12 my $comments = '';
258 8 50       19 if (scalar(@comment) > 0) { $comments = join("\n", @comment); }
  0         0  
259 8         26 return ($buffer, $comments);
260             } # end of eat_whitespace()
261              
262             # -------------------------------------------------------------------
263             # eat a non-whitespace stream, returning the content up until whitespace
264             # should not see an EOF during this (at least one ws after this stream)
265             sub read_content {
266 8     8 0 16 my ($gr, $buffer) = @_;
267              
268 8         12 my ($count, $content);
269 8         13 $content = '';
270             # first see if enough material is already in the buffer. if not, read some
271 8         9 while (1) {
272             # is buffer empty? if so, read some content
273 8 50       27 if (length($buffer) == 0) {
274 0         0 $count = read($gr, $buffer, 50); # chunk of up to 50 bytes (could be 0)
275 0 0       0 if ($count == 0) {
276             # EOF or read error, is bad thing here
277 0         0 print STDERR "EOF or read error reading content in pixel data\n";
278 0         0 return ($buffer, '');
279             }
280             }
281              
282             # should always be non-ws content here
283 8         31 $buffer =~ s/^([^\s]+)//;
284 8         20 $content .= $1; # has been removed from buffer (now possibly empty)
285             # if buffer now empty (didn't see ws char), need to read more
286 8 50       19 if (length($buffer) == 0) { next; }
  0         0  
287 8         14 last; # non-empty buffer means it starts with a ws char
288              
289             # this function is used for header fields and non-raw pixel data, so
290             # we don't expect to have an EOF immediately after a data item (must
291             # be a \n after it at the last data item).
292              
293             } # while(1) until run out of non-whitespace
294              
295 8         22 return ($buffer, $content);
296             } # end of read_content()
297              
298             # -------------------------------------------------------------------
299             sub read_pnm {
300 3     3 0 4 my $self = shift;
301 3         5 my $pdf = shift;
302 3         6 my $file = shift;
303              
304 3         5 my ($rc, $buf, $buf2, $s, $pix, $max);
305             # $s is a scale factor for sample not full 8 or 16 bits.
306             # it should scale the input to 0..255 or 0..65535, so final value
307             # will be a full 8 or 16 bits per channel (bpc)
308 3         8 my ($w,$h, $bpc, $cs, $img, @img) = (0,0, '', '', '');
309 3         8 my ($info, $buffer, $content, $comment, $sample, $gr);
310 3         0 my $inf;
311 3 100       9 if (ref($file)) {
312 1         2 $inf = $file;
313             } else {
314 2 100       127 open $inf, "<", $file or die "$!: $file";
315             }
316 2         13 binmode($inf,':raw');
317 2         21 $inf->seek(0, 0);
318 2         31 $buffer = ''; # initialize
319 2         8 ($info, $buffer) = readppmheader($inf, $buffer);
320             # info (hashref) fields:
321             # error undef or an error description
322             # type magic number 1-6
323             # raw 0 if plain/ASCII, 1 if raw/binary
324             # bgp b=bi-level (1,4) g=grayscale (2,5), p=pixmap/RGB (3,6)
325             # width width (row length/horizontal) in pixels
326             # height height (row count/vertical) in pixels
327             # max sample max value 1 for bi-level, 1-65535 for grayscale/RGB
328             # comments comment line(s), if any (else '')
329 2 50       7 if (defined $info->{'error'}) {
330 0         0 print STDERR "Error reported during PNM file header read:\n".($info->{'error'}).".\n";
331 0         0 return $self;
332             }
333              
334 2         5 $w = $info->{'width'};
335 2         3 $h = $info->{'height'};
336 2         4 $max = $info->{'max'};
337              
338 2         3 my $bytes_per_sample = 1;
339 2 50       5 if ($max > 255) { $bytes_per_sample = 2; }
  0         0  
340              
341             # ------------------------------
342 2 50       22 if ($info->{'type'} == 1) {
    50          
    50          
    50          
    50          
    50          
343             # plain (ASCII) PBM bi-level, each pixel 0..1, ws between is optional
344            
345 0         0 $bpc = 1; # one bit per channel/sample/pixel
346             # pack 8 pixels (possibly with don't-care at end of row) to a byte
347 0         0 my ($row, $col, $bits); # need to handle rows separately for d/c bits
348 0         0 my $qflag;
349 0         0 $content = '';
350 0         0 for ($row = 0; $row < $h; $row++) {
351 0         0 $bits = '';
352 0         0 for ($col = 0; $col < $w; $col++) {
353             # could be a single 0 or 1, or a whole bunch lumped together
354             # in one or more groups
355             # buffer has 0 or more entries. handle just one in this loop,
356             # reading in new buffer if necessary
357 0 0       0 if (length($content) == 0) {
358 0         0 $qflag = 0;
359 0 0 0     0 if ($row == $h-1 && $col == $w-1) { $qflag = 1; }
  0         0  
360 0         0 ($buffer, $comment) = eat_whitespace($inf, $buffer, $qflag);
361 0         0 ($buffer, $content) = read_content($inf, $buffer);
362 0 0       0 if (length($content) == 0) {
363 0         0 print STDERR "Unexpected EOF or read error reading pixel data.\n";
364 0         0 return $self;
365             }
366             }
367 0         0 $sample = substr($content, 0, 1);
368 0         0 $content = substr($content, 1);
369 0 0 0     0 if ($sample ne '0' && $sample ne '1') {
370 0         0 print STDERR "Invalid bit value '$sample' in pixel data.\n";
371 0         0 return $self;
372             }
373 0         0 $bits .= $sample;
374 0 0       0 if (length($bits) == 8) {
375 0         0 $self->{' stream'} .= pack('B8', $bits);
376 0         0 $bits = '';
377             }
378              
379             } # end of cols in row. partial $bits to finish?
380 0 0       0 if ($bits ne '') {
381 0         0 while (length($bits) < 8) {
382 0         0 $bits .= '0'; # don't care, but must be 0 or 1
383             }
384 0         0 $self->{' stream'} .= pack('B8', $bits);
385             }
386             } # end of rows
387              
388 0         0 $cs = 'DeviceGray'; # at 1 bit per pixel
389 0         0 $self->{'Decode'} = PDFArray(PDFNum(1), PDFNum(0));
390            
391             # ------------------------------
392             } elsif ($info->{'type'} == 2) {
393             # plain (ASCII) PGM grayscale, each pixel 0..max (1 or 2 bytes)
394            
395             # get scale factor $s to fully fill 8 or 16 bit sample (channel)
396 0 0 0     0 if ($max == 255 || $max == 65535) {
    0          
397 0         0 $s = 0; # flag: no scaling
398             } elsif ($max > 255) {
399 0         0 $s = 65535/$max;
400             } else {
401 0         0 $s = 255/$max;
402             }
403 0         0 $bpc = 8 * $bytes_per_sample;
404 0         0 my $format = 'C';
405 0 0       0 if ($bytes_per_sample == 2) { $format = 'S>'; }
  0         0  
406 0         0 my $sample;
407              
408 0         0 for ($pix=($w*$h); $pix>0; $pix--) {
409 0         0 ($buffer, $content) = read_content($inf, $buffer);
410 0 0       0 if (length($content) == 0) {
411 0         0 print STDERR "Unexpected EOF or read error reading pixel data.\n";
412 0         0 return $self;
413             }
414 0         0 ($buffer, $comment) = eat_whitespace($inf, $buffer, $pix==1);
415              
416 0 0       0 if ($content =~ m/^\d+$/) {
417 0 0       0 if ($content > $max) {
418 0         0 print STDERR "Pixel data entry '$content' higher than $max. Value changed to $max.\n";
419 0         0 $content = $max;
420             }
421             } else {
422 0         0 print STDERR "Invalid pixel data entry '$content'.\n";
423 0         0 return $self;
424             }
425 0         0 $sample = $content;
426              
427 0 0       0 if ($s > 0) {
428             # scaling needed
429 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
430             }
431 0         0 $self->{' stream'} .= pack($format, $sample);
432             } # loop through all pixels
433 0         0 $cs = 'DeviceGray';
434            
435             # ------------------------------
436             } elsif ($info->{'type'} == 3) {
437             # plain (ASCII) PPM rgb, each pixel 0..max for R, G, B (1 or 2 bytes)
438            
439             # get scale factor $s to fully fill 8 or 16 bit sample (channel)
440 0 0 0     0 if ($max == 255 || $max == 65535) {
    0          
441 0         0 $s = 0; # flag: no scaling
442             } elsif ($max > 255) {
443 0         0 $s = 65535/$max;
444             } else {
445 0         0 $s = 255/$max;
446             }
447 0         0 $bpc = 8 * $bytes_per_sample;
448 0         0 my $format = 'C';
449 0 0       0 if ($bytes_per_sample == 2) { $format = 'S>'; }
  0         0  
450 0         0 my ($sample, $rgb);
451              
452 0         0 for ($pix=($w*$h); $pix>0; $pix--) {
453 0         0 for ($rgb = 0; $rgb < 3; $rgb++) { # R, G, and B values
454 0         0 ($buffer, $comment) = eat_whitespace($inf, $buffer, $pix==1);
455 0         0 ($buffer, $content) = read_content($inf, $buffer);
456 0 0       0 if (length($content) == 0) {
457 0         0 print STDERR "Unexpected EOF or read error reading pixel data.\n";
458 0         0 return $self;
459             }
460              
461 0 0       0 if ($content =~ m/^\d+$/) {
462 0 0       0 if ($content > $max) {
463             # remember, $pix counts DOWN from w x h
464 0         0 print STDERR "Pixel $pix data entry '$content' higher than $max. Value changed to $max.\n";
465 0         0 $content = $max;
466             }
467             } else {
468 0         0 print STDERR "Invalid pixel data entry '$content'.\n";
469 0         0 return $self;
470             }
471 0         0 $sample = $content;
472              
473 0 0       0 if ($s > 0) {
474             # scaling needed
475 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
476             }
477 0         0 $self->{' stream'} .= pack($format, $sample);
478             } # R G B loop
479             } # loop through all pixels
480 0         0 $cs = 'DeviceRGB';
481            
482             # ------------------------------
483             } elsif ($info->{'type'} == 4) {
484             # raw (binary) PBM bi-level, each pixel 0..1, row packed 8 pixel/byte
485 0         0 $bpc = 1; # one bit per channel/sample/pixel
486             # round up for don't care bits at end of row
487 0         0 my $bytes = int(($w+7)/8) * $h;
488 0         0 $bytes -= length($buffer); # some already read from file!
489 0         0 $rc = read($inf, $buf2, $bytes);
490 0 0       0 if ($rc != $bytes) {
491 0         0 print STDERR "Unexpected EOF or read error while reading PNM binary pixel data.\n";
492 0         0 return $self;
493             }
494 0         0 $self->{' stream'} = $buffer.$buf2;
495 0         0 $cs = 'DeviceGray'; # at 1 bit per pixel
496 0         0 $self->{'Decode'} = PDFArray(PDFNum(1), PDFNum(0));
497              
498             # ------------------------------
499             } elsif ($info->{'type'} == 5) {
500             # raw (binary) PGM grayscale, each pixel 0..max (1 or 2 bytes)
501            
502             # get scale factor $s to fully fill 8 or 16 bit sample (channel)
503 0 0 0     0 if ($max == 255 || $max == 65535) {
    0          
504 0         0 $s = 0; # flag: no scaling
505             } elsif ($max > 255) {
506 0         0 $s = 65535/$max;
507             } else {
508 0         0 $s = 255/$max;
509             }
510 0         0 $bpc = 8 * $bytes_per_sample;
511 0         0 my $format = 'C';
512 0 0       0 if ($bytes_per_sample == 2) { $format = 'S>'; }
  0         0  
513 0         0 my ($buf, $sample);
514              
515 0         0 my $bytes = $w * $h * $bytes_per_sample;
516 0         0 $bytes -= length($buffer); # some already read from file!
517 0         0 $rc = read($inf, $buf, $bytes);
518 0 0       0 if ($rc != $bytes) {
519 0         0 print STDERR "Unexpected EOF or read error reading pixel data.\n";
520 0         0 return $self;
521             }
522 0         0 $buf = $buffer . $buf;
523 0 0       0 if ($s > 0) {
524             # scaling needed
525 0         0 for ($pix=($w*$h); $pix>0; $pix--) {
526 0         0 $buf2 = substr($buf, 0, $bytes_per_sample);
527 0         0 $buf = substr($buf, $bytes_per_sample);
528 0         0 $sample = unpack($format, $buf2);
529 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
530 0         0 $self->{' stream'} .= pack($format, $sample);
531             }
532             } else {
533             # no scaling needed
534 0         0 $self->{' stream'} = $buf;
535             }
536 0         0 $cs = 'DeviceGray';
537            
538             # ------------------------------
539             } elsif ($info->{'type'} == 6) {
540             # raw (binary) PPM rgb, each pixel 0..max for R, G, B (3 or 6 bytes)
541            
542             # get scale factor $s to fully fill 8 or 16 bit sample (channel)
543 2 50 33     8 if ($max == 255 || $max == 65535) {
    0          
544 2         4 $s = 0; # flag: no scaling
545             } elsif ($max > 255) {
546 0         0 $s = 65535/$max;
547             } else {
548 0         0 $s = 255/$max;
549             }
550 2         4 $bpc = 8 * $bytes_per_sample;
551 2         4 my $format = 'C';
552 2 50       5 if ($bytes_per_sample == 2) { $format = 'S>'; }
  0         0  
553 2         4 my ($buf, $sample);
554              
555 2         4 my $bytes = $w * $h * $bytes_per_sample * 3;
556 2         4 $bytes -= length($buffer); # some already read from file!
557 2         8 $rc = read($inf, $buf, $bytes);
558 2 50       5 if ($rc != $bytes) {
559 0         0 print STDERR "Unexpected EOF or read error reading pixel data.\n";
560 0         0 return $self;
561             }
562 2         5 $buf = $buffer . $buf;
563 2 50       13 if ($s > 0) {
564             # scaling needed
565 0         0 for ($pix=($w*$h); $pix>0; $pix--) {
566             # Red
567 0         0 $buf2 = substr($buf, 0, $bytes_per_sample);
568 0         0 $sample = unpack($format, $buf2);
569 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
570 0         0 $self->{' stream'} .= pack($format, $sample);
571             # Green
572 0         0 $buf2 = substr($buf, $bytes_per_sample, $bytes_per_sample);
573 0         0 $sample = unpack($format, $buf2);
574 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
575 0         0 $self->{' stream'} .= pack($format, $sample);
576             # Blue
577 0         0 $buf2 = substr($buf, 2*$bytes_per_sample, $bytes_per_sample);
578 0         0 $sample = unpack($format, $buf2);
579 0         0 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
580 0         0 $self->{' stream'} .= pack($format, $sample);
581              
582 0         0 $buf = substr($buf, $bytes_per_sample*3);
583             }
584             } else {
585             # no scaling needed
586 2         6 $self->{' stream'} = $buf;
587             }
588 2         4 $cs = 'DeviceRGB';
589             }
590 2         31 close($inf);
591              
592 2         20 $self->width($w);
593 2         8 $self->height($h);
594              
595 2         9 $self->bits_per_component($bpc);
596              
597 2         14 $self->filters('FlateDecode');
598              
599 2         10 $self->colorspace($cs);
600              
601 2         10 return $self;
602             } # end of read_pnm()
603              
604             1;