Image::PBMlib(3)

NAME
Image::PBMlib - Helper functions for PBM/PGM/PPM image file formats

SYNOPSIS
    use Image::PBMlib;

    ... open(PNM, '<:raw', "image.ppm")...

    my (%info, @pixels);
    # fourth is encoding of float, dec, or hex
    readpnmfile( \*PNM, \%info, \@pixels, 'float' );
    # sets $info{error} if an error

    readpnmheader( \*PNM, \%info );
    # sets $info{error} if an error

    checkpnminfo( \%info );
    # sets $info{error} if an error

    # float, dec, or hex
    readpnmpixels( \*PNM, \%info, \@pixels, 'float')
    # sets $info{error} if an error

    # R/G/B to RRRR/GGGG/BBBB, max 1 to 65535
    my $rgb = hextripletofloat( "F00/B/A4", $maxvalue );

    # R:G:B, max 1 to 65535
    my $rgb = dectripletofloat( "3840:11:164", $maxvalue );

    # returns the number of bytes written, as a positive
    # number if no error, and zero or -1*bytes if error
    my $return = writepnmfile(\*PNM, \%info, \@pixels);

    # this header can contain comments
    my $header = makepnmheader(\%info);

    # this header will not contain comments
    # 1 for ascii PBM, 2 for ascii PGM, 3 for ascii PPM,
    # 4 for raw   PBM, 5 for raw   PGM, 6 for raw   PPM
    my $header = makepnmheader('5', $width, $height, $maxvalue);

    # raw, dec, or hex format pixels, in 'raw' or 'ascii'
    # for writing to a file
    my $block = encodepixels('raw', $maxvalue, \@pixels);

DESCRIPTION
This is primarily a library for reading and writing portable bitmap (PBM), portable graymap (PGM), and portable pixmap (PPM) files. As a set they are portable anymap (PNM). There is a separate PAM format that is not yet supported. Within each format there are two representations on disk, ASCII and RAW. ASCII is suitable for raw email transmission, short lines, all 7-bit characters. RAW is much more compact and generally preferred. A single RAW formatted file can contain multiple concatenated images.

These image formats are only the barest step up from raw raster data, and have a very simple format which is the key to be "portable". Writing out images in these formats is very easy. Reading only slightly more complicated.

  Maxvalue
Version 1.x of this library had serious bugs except for the most basic versions of PGM and PPM files, by not properly observing the maxvalue. Version 2.x fixes that at a compatiblity cost. Raw gray and color channel information is now stored as a floating point number from 0.0 as full black to 1.0 as full white, and it is scaled to the approprate maxvalue, which is a decimal integer from 1 to 65535 inclusive.

  Pixels
When this version of the library returns a pixel it will be: "0" or "1" for PBM files; "0.0," to "1.0," for PGM in float format, "0:" to "65535:" for PGM in decimal, "0/" to "FFFF/" for PGM in hexadecimal; "0.0,0.0,0.0" to "1.0,1.0,1.0" for PPM in float, "0:0:0" to "65535:65535:65535" for PPM in decimal, and "FFFF/FFFF/FFFF" for PPM in hexadecimal.

That is to say PBM files always return just zeros and ones, regardless of float, dec, or hex settings.

PGM files return a floating point number, an unrescaled dec or hex value, but always followed by a comma if float, a colon if decimal, and a slash if hex. Unrescaled means that if the maxvalue is 1000 (decimal integer), then white is "1.0," in float, "1000:" in dec, and "3E8/" in hex.

PPM files return a RGB set of floating point numbers, an unrescaled set of dec or hex values, which are always separated by commas if float, colons if decimal, and slashes if hex. Be sure to read what unscaled means in the previous paragraph.

Image::PBMlib likes pixels in a two dimensional array, but can use a single dimensional array.

FUNCTIONS

  readpnmfile( \*PNM, \%info, \@pixels, $encoding );
Reads from a file handle and sets hash %info with properties, puts pixels into @pixels, formated as "float", "dec", or "hex". The @pixels structure is an array of rows, each row being an array of pixel strings.

The %info hash has numerous properties about the source file. The function itself returns 'error' for usage errors, and the empty string normally.

This function essentially chains readpnmheader(), checkpnminfo(), and readpnmpixels().

A single file, if in the RAW format, can contain multiple concatenated images. This function will only read one at a time, but can be called multiple times on the same file handle.

•   $info{bgp}

    Will contain one of "b", "g", or "p" for pbm (bitmap), pgm (graymap), or ppm (pixmap). This is an informational value not used by this library.

•   $info{type}

    Will contain one of "1" for ASCII PBM, "2" for ASCII PGM, "3" for ASCII PPM, "4" for raw PBM, "5" for raw PGM, or "6" for raw PPM. This numerical value is right out of the header of the PBM family of files and is essential to understanding the pixel format.

•   $info{max}

    Will contain the max value of the image as a decimal integer. This is needed to properly understand what a decimal or hexadecimal pixel value means. It is used to convert raw pixel data into floating point values (and back to integers).

•   $info{format}

    Will contain 'raw' or 'ascii'.

•   $info{raw}

    Will contain a true value if the file is raw encoded, and false for ASCII. This is an informational value not used by this library.

•   $info{height}

    Will contain the height of the image in pixels.

•   $info{width}

    Will contain the width of the image in pixels.

•   $info{pixels}

    Will contain the number of pixels (height * width).

•   $info{comments}

    Will contain any comments found in the header, concatenated.

•   $info{fullheader}

    Will contain the complete, unparsed, header.

•   $info{error}

    Will contain an empty string if no errors occured, or an error message, including usage errors.

  checkpnminfo( \%info )
Checks the values in the image info hash for completeness. Used internally between reading the header and reading the pixels of an image, but might be useful generally. Expects to find numerical values for type, pixels, max, width, and height.

  readpnminfo( \*PNM, \%info )
Reads just the header of a PBM/PGM/PPM file from the file handle and populates the image info hash. See "readpnmfile" for a description of the image info hash. Returns the string 'error' if there is an problem, and the empty string otherwise. Sets the $info{error} value with an error string.

  readpnmpixels( \*PNM, \%info, \@pixels, $encoding )
Reads just the pixels of a PBM/PGM/PPM file from the file handle and populates the pixels array. See "readpnmfile" for a description of the image info hash, pixel array output format, and encoding details. Returns 'error' if there is an problem, and the empty string otherwise. Sets the $info{error} value with an error string.

  $float_pixel = hextripletofloat( $hex_pixel, $max )

  $float_pixel = hextripletofloat( \@hex_pixel, $max )
For a pixel string with hex red green and blue values separated by slashes (R/G/B to RRRR/GGGG/BBBB) or an array of hex values, and a of max 1 to 65535, convert to the comma separated floating point pixel format.

No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

$hex_pixel can be a scalar or an array ref (eg "\@triple") and $float_pixel can be a scalar or an array (eg @triple).

Returns undef if $hex_pixel is malformed.

  $float_pixel = dectripletofloat( $dec_pixel, $max )

  $float_pixel = dectripletofloat( \@dec_pixel, $max )
For a pixel string with decimal red green and blue values separated by colons (eg R:G:B), or an array of decimal values, and a max of 1 to 65535, convert to the comma separated floating point pixel format.

No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

$dec_pixel can be a scalar or an array ref (eg "\@triple") and $float_pixel can be a scalar or an array (eg @triple).

Returns undef if $dec_pixel is malformed.

  $float_pixel = hexvaltofloat( $hex_val, $max )
For a pixel value in hexadecimal and a max of 1 to 65535, convert to the comma separated floating point pixel value format.

No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

Returns undef if $hex_pixel is malformed.

  $float_pixel = decvaltofloat( $dec_val, $max )
For a pixel value in decimal and a max of 1 to 65535, convert to the comma separated floating point pixel value format.

No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

Returns undef if $dec_pixel is malformed.

  $dec_pixel = floattripletodec( \@float_pixel, $max )

  $dec_pixel = floattripletodec( $float_pixel, $max )
For a pixel string with floating red green and blue values separated by commas (eg R:G:B), and max 1 to 65535, convert to the colon separated decimal pixel format. No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

$float_pixel can be a scalar or an array ref (eg "\@triple") and $dec_pixel can be a scalar or an array (eg @triple).

Returns undef if $float_pixel is malformed.

  $hex_pixel = floattripletohex( \@float_pixel, $max )

  $hex_pixel = floattripletohex( $float_pixel, $max )
For a pixel string with floating red green and blue values separated by commas (eg R:G:B), and max 1 to 65535, convert to the slash separated hex pixel format. No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

$float_pixel can be a scalar or an array ref (eg "\@triple") and $hex_pixel can be a scalar or an array (eg @triple).

Returns undef if $float_pixel is malformed.

  $dec_pixel = floatvaltodec( $float_pixel, $max )
For a floating point pixel value and max 1 to 65535, convert to the decimal pixel format. No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

Returns undef if $float_pixel is malformed.

  $hex_pixel = floatvaltohex( $float_pixel, $max )
For a floating point pixel value and max 1 to 65535, convert to the hexadecimal pixel format. No error is returned if $max is outside of the allowed range, but 0 will kill the program. Any value larger than max is clipped.

Returns undef if $float_pixel is malformed.

  $status = comparefloattriple(\@a, \@b)

  $status = comparefloattriple($a, $b)
Returns -1, 0, or 1 much like <=>, but allows a variance of up to half 1/65535. Checks only a single pair at a time (red value of $a to red value of $b, etc) and stops at the first obvious non-equal value. Does not check if any value is outside of 0.0 to 1.0. Returns undef if either triple can't be understood.

  $status = comparefloatval($a, $b)
Returns -1, 0, or 1 much like <=>, but allows a variance of up to half 1/65535. Checks only a single pair (not an RGB triple), does not check if either value is outside of 0.0 to 1.0.

  $status = comparepixelval($a, $max_a, $b, $max_b)
Returns -1, 0, or 1 much like <=>, taking into account that each is really a fraction: "$v / $max_v". Decimal values should have a colon (eg "123:"), while hex values should have a slash (eg "7B/"). Uses integer comparisions and should not be used with floating point values. Max should always be a regular decimal integer. Checks only a single pair (not an RGB triple), does not enforce checks on the max values.

This is a less forgiving comparison than comparefloatval().

  $status = comparepixeltriple(\@a, $max_a, \@b, $max_b)

  $status = comparepixeltriple($a, $max_a, $b, $max_b)
Returns -1, 0, or 1 much like <=>, taking into account that RGB each is really a fraction: "$v / $max_v". Decimal values should be colon separated (eg "123:1:1024" or terminated ["123:", "1:", "1024:"]), while hex values should have slashes (eg "7B/1/400" or ["7B/", "1/", "400/"]). Uses integer comparisions and should not be used with floating point values. Max should always be a regular decimal integer. Checks only a single pair at a time (red value of $a to red value of $b, etc) and stops at the first obvious non-equal value. Does not enforce checks on the max values. Returns undef if either triple can't be understood.

This is a less forgiving comparison than comparefloattriple().

  ($r, $g, $b) = explodetriple( \@pixel );

  ($r, $g, $b) = explodetriple( $pixel );
Helper function to separate the values of an RGB pixel, either in array or string format. Float pixels have comma separated triples, and comma suffixed single values. Decimal pixels use colons, and hex pixels use slashes. Does not enforce values to be within the allowed range.

Returns undef if the pixel could not be understood.

  @pixel = rescaletriple( \@pixel, $old_max, $new_max );

  $pixel = rescaletriple( $pixel, $old_max, $new_max );
Helper function to rescale the values of an RGB pixel to a new max value, either in array or string format. Float pixels do not need rescaling. Decimal pixels use colons as separator / suffix, and hex pixels use slashes. Does not enforce values to be within the allowed range.

Returns undef if the pixel could not be understood.

  $value = rescaleval( $value, $old_max, $new_max );
Helper function to rescale a single value to a new max value, either in array or string format. Float values do not need rescaling. Decimal values use colons as suffix, and hex values use slashes. Does not enforce values to be within the allowed range.

Returns undef if the value could not be understood.

  $header = makepnmheader( \%info );

  $header = makepnmheader($type, $width, $height, $max);
Takes a hash reference similar to readpnmheader() or "readpnmfile" would return and makes a PBM, PGM, or PPM header string from it. "makeppmheader" first looks for a type in the hash and uses that, otherwise it expects bgp and format to be set in the hash (and it will set type for you then). If there is a non-empty comments in the hash, that will be put in as one or more lines of comments. There must be sizes for width and height, and if the image is not a bitmap, there should be one for max. A missing max will result in "makeppmheader" guessing 255 and setting max accordingly.

The numerical types are 1 for ASCII PBM, 2 for ASCII PGM, 3 for ASCII PPM, 4 for raw PBM, 5 for raw PGM, and 6 for raw PPM. The maxvalue is ignored for PBM files.

Returns the header string if successful. Returns undef if there is an error.

  $block = encodepixels($format, $max, \@pixels);
Encodes pixels into 'raw' or 'ascii' PBM/PGM/PPM format. The supplied pixels can be decimal, hex, or floating point values. Decimal and hex values greater than $max will be clipped to $max. A $max of 1 will encode a PBM file, otherwise the first pixel will be examined to determine if it is PGM or PPM data.

The array of pixels can be one, two, or three dimensional. A two dimensional array is prefered and will be considered to be same format readpnmfile() and readpnmpixels() uses. There, the @pixels structure is an array of rows, each row being an array of pixel strings. This function will expect every row to have the same number of pixels as the first. If subsequent rows have different amounts, the results can be unpredictable. Missing values will be assumed to be 0 if it it tries to read past the end of the array.

A three dimensional @pixels structure is considered to be an array of rows, each row being an array of PPM pixel values.

A one dimensional @pixels structure is an array of pixel strings with no hint of row and column structure. With a one dimensional array, raw PBM files will be misencoded if number of columns is not a multiple of 8 and the data represents more than one row: each row is supposed to be padded to a multiple of 8 bits.

Returns undef if $encoding is not recognized, $max is out of bounds (1 to 65535, inclusive), or @pixels cannot be understood.

  $return = writepnmfile(\*PNM, \%info, \@pixels);
Writes an entire PNM image to a given filehandle. Sometimes more memory efficient than a makepnmheader() encodepixels() pair (by encoding row by row when possible). Does not do an inspectpixels().

Writes are done using syswrite() so see that the documentation for that function for warnings about mixing with other file operations.

Returns undef if $encoding is not recognized, $max is out of bounds (1 to 65535, inclusive), or @pixels cannot be understood. Returns number of bytes written with positive values for complete success, 0 for no bytes successfully written, and -1 * bytes written for a partial success (eg, ran out of disk space).

  inspectpixels($format, $max, \@pixels, \%report );
Performs all of the argument checks of encodepixels(), and if no errors are found it does a thorough inspection all pixels looking for inconsitencies.

Returns undef if there was an error, and the number of pixels if it succeeded. (An image with no pixels is considered an error.) The report hash will contain information gleaned from the inspection.

•   $report{error}

    Set if there is an error with a description of the problem.

•   $report{where}

    Set if there is an error with the array coordinates of the problem.

•   $report{deep}

    Set to '1d', '2d', or '3d' to describe the pixel array.

•   $report{width}

    Width of the pixel array (if not '1d' deep).

•   $report{height}

    Height of the pixel array (if not '1d' deep).

•   $report{pixels}

    Expected number pixels.

•   $report{bytes}

    Number of bytes needed to encode each pixel, if in raw. Will be 1 for PBM files.

•   $report{encode}

    The 'float', 'dec', or 'hex' encoding of the first pixel. All others are expected to match this.

•   $report{first}

    First pixel found.

•   $report{type}

    The numerical type of the format. Might be wrong if $report{first} is unset. Will contain one of "1" for ASCII PBM, "2" for ASCII PGM, "3" for ASCII PPM, "4" for raw PBM, "5" for raw PGM, or "6" for raw PPM.

•   $report{checked}

    Number of pixels checked.

  checkval($value, $encode);
Checks that a value (not an RGB triple) conforms to an encoding of 'float', 'dec', or 'hex'. Returns undef if there was an error, and a positive value otherwise.

PORTABILITY
This code is pure perl for maximum portability, as befitting the PBM/PGM/PPM philosophy.

CHANGES
2.0 is a nearly complete rewrite fixing the bugs that arose from not taking the max value into account. Only the code to read an image header is taken from 1.x. None of the function names are the same and most of the interface has changed.

1.05 fixes two comment related bugs (thanks Ladislav Sladecek!) and some error reporting bugs with bad filehandles.

BUGS
No attempt is made to deal with comments after the header in ASCII formatted files.

No attempt is made to handle the PAM format.

Pure perl code makes this slower than it could be.

Not all PBM/PGM/PPM tools are safe for images from untrusted sources but this one should be. Be careful what you use this with. This software can create raw files with multibyte (max over 255) values, but some older PBM/PGM/PPM tools can only handle ASCII files for large max values (or cannot handle it at all).

SEE ALSO
The manual pages for pbm(5), pgm(5), and ppm(5) define the various file formats. The netpbm and pbmplus packages include a host of interesting PNM tools.

COPYRIGHT
Copyright 2012, 2003 Benjamin Elijah Griffin / Eli the Bearded <elijah@cpan.org>

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.