iPXE
Data Structures | Functions | Variables
png.c File Reference

Portable Network Graphics (PNG) format. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/umalloc.h>
#include <ipxe/pixbuf.h>
#include <ipxe/deflate.h>
#include <ipxe/png.h>

Go to the source code of this file.

Data Structures

struct  png_context
 PNG context. More...
struct  png_interlace
 A PNG interlace pass. More...
struct  png_filter
 A PNG filter. More...
struct  png_chunk_handler
 A PNG chunk handler. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static const char * png_type_name (uint32_t type)
 Transcribe PNG chunk type name (for debugging)
static void png_interlace (struct png_context *png, unsigned int pass, struct png_interlace *interlace)
 Calculate PNG interlace pass parameters.
static unsigned int png_pixel_len (struct png_context *png)
 Calculate PNG pixel length.
static size_t png_scanline_len (struct png_context *png, struct png_interlace *interlace)
 Calculate PNG scanline length.
static int png_image_header (struct image *image, struct png_context *png, size_t len)
 Handle PNG image header chunk.
static int png_palette (struct image *image, struct png_context *png, size_t len)
 Handle PNG palette chunk.
static int png_image_data (struct image *image, struct png_context *png, size_t len)
 Handle PNG image data chunk.
static unsigned int png_unfilter_none (unsigned int current, unsigned int left __unused, unsigned int above __unused, unsigned int above_left __unused)
 Unfilter byte using the "None" filter.
static unsigned int png_unfilter_sub (unsigned int current, unsigned int left, unsigned int above __unused, unsigned int above_left __unused)
 Unfilter byte using the "Sub" filter.
static unsigned int png_unfilter_up (unsigned int current, unsigned int left __unused, unsigned int above, unsigned int above_left __unused)
 Unfilter byte using the "Up" filter.
static unsigned int png_unfilter_average (unsigned int current, unsigned int left, unsigned int above, unsigned int above_left __unused)
 Unfilter byte using the "Average" filter.
static unsigned int png_paeth_predictor (unsigned int a, unsigned int b, unsigned int c)
 Paeth predictor function (defined in RFC 2083)
static unsigned int png_unfilter_paeth (unsigned int current, unsigned int left, unsigned int above, unsigned int above_left)
 Unfilter byte using the "Paeth" filter.
static int png_unfilter_pass (struct image *image, struct png_context *png, struct png_interlace *interlace)
 Unfilter one interlace pass of PNG raw data.
static int png_unfilter (struct image *image, struct png_context *png)
 Unfilter PNG raw data.
static unsigned int png_pixel (unsigned int raw, unsigned int alpha, unsigned int max)
 Calculate PNG pixel component value.
static void png_pixels_pass (struct image *image, struct png_context *png, struct png_interlace *interlace)
 Fill one interlace pass of PNG pixels.
static void png_pixels (struct image *image, struct png_context *png)
 Fill PNG pixels.
static int png_image_end (struct image *image, struct png_context *png, size_t len)
 Handle PNG image end chunk.
static int png_chunk (struct image *image, struct png_context *png, uint32_t type, size_t len)
 Handle PNG chunk.
static int png_pixbuf (struct image *image, struct pixel_buffer **pixbuf)
 Convert PNG image to pixel buffer.
static int png_probe (struct image *image)
 Probe PNG image.
struct image_type png_image_type __image_type (PROBE_NORMAL)
 PNG image type.

Variables

static struct png_signature png_signature = PNG_SIGNATURE
 PNG file signature.
static uint8_t png_interlace_passes []
 Number of interlacing passes.
static struct png_filter png_filters []
 PNG filter types.
static struct png_chunk_handler png_chunk_handlers []
 PNG chunk handlers.

Detailed Description

Portable Network Graphics (PNG) format.

The PNG format is defined in RFC 2083.

Definition in file png.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static const char* png_type_name ( uint32_t  type) [static]

Transcribe PNG chunk type name (for debugging)

Parameters:
typeChunk type
Return values:
nameChunk type name

Definition at line 101 of file png.c.

References name, type, and u.

Referenced by png_chunk().

                                                    {
        static union {
                uint32_t type;
                char name[ sizeof ( uint32_t ) + 1 /* NUL */ ];
        } u;

        u.type = type;
        return u.name;
}
static void png_interlace ( struct png_context png,
unsigned int  pass,
struct png_interlace interlace 
) [static]

Calculate PNG interlace pass parameters.

Parameters:
pngPNG context
passPass number (0=first pass)
interlaceInterlace pass to fill in

Definition at line 118 of file png.c.

References assert, pixel_buffer::height, png_interlace::height, png_interlace::pass, png_context::passes, png_context::pixbuf, pixel_buffer::width, png_interlace::width, png_interlace::x_indent, png_interlace::x_stride, png_interlace::y_indent, and png_interlace::y_stride.

Referenced by png_image_header(), png_pixels(), and png_unfilter().

                                                              {
        unsigned int grid_width_log2;
        unsigned int grid_height_log2;
        unsigned int x_indent;
        unsigned int y_indent;
        unsigned int x_stride_log2;
        unsigned int y_stride_log2;
        unsigned int x_stride;
        unsigned int y_stride;
        unsigned int width;
        unsigned int height;

        /* Sanity check */
        assert ( png->passes > 0 );

        /* Store pass number */
        interlace->pass = pass;

        /* Calculate interlace grid dimensions */
        grid_width_log2 = ( png->passes / 2 );
        grid_height_log2 = ( ( png->passes - 1 ) / 2 );

        /* Calculate starting indents */
        interlace->x_indent = x_indent =
                ( ( pass & 1 ) ?
                  ( 1 << ( grid_width_log2 - ( pass / 2 ) - 1 ) ) : 0 );
        interlace->y_indent = y_indent =
                ( ( pass && ! ( pass & 1 ) ) ?
                  ( 1 << ( grid_height_log2 - ( ( pass - 1 ) / 2 ) - 1 ) ) : 0);

        /* Calculate strides */
        x_stride_log2 = ( grid_width_log2 - ( pass / 2 ) );
        y_stride_log2 =
                ( grid_height_log2 - ( pass ? ( ( pass - 1 ) / 2 ) : 0 ) );
        interlace->x_stride = x_stride = ( 1 << x_stride_log2 );
        interlace->y_stride = y_stride = ( 1 << y_stride_log2 );

        /* Calculate pass dimensions */
        width = png->pixbuf->width;
        height = png->pixbuf->height;
        interlace->width =
                ( ( width - x_indent + x_stride - 1 ) >> x_stride_log2 );
        interlace->height =
                ( ( height - y_indent + y_stride - 1 ) >> y_stride_log2 );
}
static unsigned int png_pixel_len ( struct png_context png) [static]

Calculate PNG pixel length.

Parameters:
pngPNG context
Return values:
pixel_lenPixel length

Definition at line 171 of file png.c.

References png_context::channels, and png_context::depth.

Referenced by png_unfilter_pass().

                                                              {

        return ( ( ( png->channels * png->depth ) + 7 ) / 8 );
}
static size_t png_scanline_len ( struct png_context png,
struct png_interlace interlace 
) [static]

Calculate PNG scanline length.

Parameters:
pngPNG context
interlaceInterlace pass
Return values:
scanline_lenScanline length (including filter byte)

Definition at line 183 of file png.c.

References png_context::channels, png_context::depth, and png_interlace::width.

Referenced by png_image_header(), and png_unfilter_pass().

                                                                   {

        return ( 1 /* Filter byte */ +
                 ( ( interlace->width * png->channels * png->depth ) + 7 ) / 8);
}
static int png_image_header ( struct image image,
struct png_context png,
size_t  len 
) [static]

Handle PNG image header chunk.

Parameters:
imagePNG image
pngPNG context
lenChunk length
Return values:
rcReturn status code

Definition at line 198 of file png.c.

References alloc_pixbuf(), png_context::channels, png_context::colour_type, png_image_header::colour_type, png_image_header::compression, copy_from_user(), image::data, deflate_chunk::data, DBGC, png_context::depth, png_image_header::depth, EINVAL, ENOMEM, ENOTSUP, png_image_header::filter, png_interlace::height, png_image_header::height, png_image_header::interlace, deflate_chunk::len, image::name, ntohl, png_context::offset, png_interlace::pass, png_context::passes, png_context::pixbuf, PNG_COLOUR_TYPE_ALPHA, PNG_COLOUR_TYPE_PALETTE, PNG_COLOUR_TYPE_RGB, PNG_COMPRESSION_UNKNOWN, PNG_FILTER_UNKNOWN, png_interlace(), png_interlace_passes, PNG_INTERLACE_UNKNOWN, png_scanline_len(), png_context::raw, umalloc(), png_image_header::width, and png_interlace::width.

                                           {
        struct png_image_header ihdr;
        struct png_interlace interlace;
        unsigned int pass;

        /* Sanity check */
        if ( len != sizeof ( ihdr ) ) {
                DBGC ( image, "PNG %s invalid IHDR length %zd\n",
                       image->name, len );
                return -EINVAL;
        }
        if ( png->pixbuf ) {
                DBGC ( image, "PNG %s duplicate IHDR\n", image->name );
                return -EINVAL;
        }

        /* Extract image header */
        copy_from_user ( &ihdr, image->data, png->offset, len );
        DBGC ( image, "PNG %s %dx%d depth %d type %d compression %d filter %d "
               "interlace %d\n", image->name, ntohl ( ihdr.width ),
               ntohl ( ihdr.height ), ihdr.depth, ihdr.colour_type,
               ihdr.compression, ihdr.filter, ihdr.interlace );

        /* Sanity checks */
        if ( ihdr.compression >= PNG_COMPRESSION_UNKNOWN ) {
                DBGC ( image, "PNG %s unknown compression method %d\n",
                       image->name, ihdr.compression );
                return -ENOTSUP;
        }
        if ( ihdr.filter >= PNG_FILTER_UNKNOWN ) {
                DBGC ( image, "PNG %s unknown filter method %d\n",
                       image->name, ihdr.filter );
                return -ENOTSUP;
        }
        if ( ihdr.interlace >= PNG_INTERLACE_UNKNOWN ) {
                DBGC ( image, "PNG %s unknown interlace method %d\n",
                       image->name, ihdr.interlace );
                return -ENOTSUP;
        }

        /* Allocate pixel buffer */
        png->pixbuf = alloc_pixbuf ( ntohl ( ihdr.width ),
                                     ntohl ( ihdr.height ) );
        if ( ! png->pixbuf ) {
                DBGC ( image, "PNG %s could not allocate pixel buffer\n",
                       image->name );
                return -ENOMEM;
        }

        /* Extract bit depth */
        png->depth = ihdr.depth;
        if ( ( png->depth == 0 ) ||
             ( ( png->depth & ( png->depth - 1 ) ) != 0 ) ) {
                DBGC ( image, "PNG %s invalid depth %d\n",
                       image->name, png->depth );
                return -EINVAL;
        }

        /* Calculate number of channels */
        png->colour_type = ihdr.colour_type;
        png->channels = 1;
        if ( ! ( ihdr.colour_type & PNG_COLOUR_TYPE_PALETTE ) ) {
                if ( ihdr.colour_type & PNG_COLOUR_TYPE_RGB )
                        png->channels += 2;
                if ( ihdr.colour_type & PNG_COLOUR_TYPE_ALPHA )
                        png->channels += 1;
        }

        /* Calculate number of interlace passes */
        png->passes = png_interlace_passes[ihdr.interlace];

        /* Calculate length of raw data buffer */
        for ( pass = 0 ; pass < png->passes ; pass++ ) {
                png_interlace ( png, pass, &interlace );
                if ( interlace.width == 0 )
                        continue;
                png->raw.len += ( interlace.height *
                                  png_scanline_len ( png, &interlace ) );
        }

        /* Allocate raw data buffer */
        png->raw.data = umalloc ( png->raw.len );
        if ( ! png->raw.data ) {
                DBGC ( image, "PNG %s could not allocate data buffer\n",
                       image->name );
                return -ENOMEM;
        }

        return 0;
}
static int png_palette ( struct image image,
struct png_context png,
size_t  len 
) [static]

Handle PNG palette chunk.

Parameters:
imagePNG image
pngPNG context
lenChunk length
Return values:
rcReturn status code

Definition at line 298 of file png.c.

References png_palette_entry::blue, copy_from_user(), image::data, DBGC2, png_palette_entry::green, image::name, png_context::offset, offset, png_context::palette, and png_palette_entry::red.

                                      {
        size_t offset = png->offset;
        struct png_palette_entry palette;
        unsigned int i;

        /* Populate palette */
        for ( i = 0 ; i < ( sizeof ( png->palette ) /
                            sizeof ( png->palette[0] ) ) ; i++ ) {

                /* Stop when we run out of palette data */
                if ( len < sizeof ( palette ) )
                        break;

                /* Extract palette entry */
                copy_from_user ( &palette, image->data, offset,
                                 sizeof ( palette ) );
                png->palette[i] = ( ( palette.red << 16 ) |
                                    ( palette.green << 8 ) |
                                    ( palette.blue << 0 ) );
                DBGC2 ( image, "PNG %s palette entry %d is %#06x\n",
                        image->name, i, png->palette[i] );

                /* Move to next entry */
                offset += sizeof ( palette );
                len -= sizeof ( palette );
        }

        return 0;
}
static int png_image_data ( struct image image,
struct png_context png,
size_t  len 
) [static]

Handle PNG image data chunk.

Parameters:
imagePNG image
pngPNG context
lenChunk length
Return values:
rcReturn status code

Definition at line 337 of file png.c.

References image::data, DBGC, png_context::deflate, deflate_inflate(), image::name, png_context::offset, png_context::raw, rc, and strerror().

                                         {
        struct deflate_chunk in;
        int rc;

        /* Deflate this chunk */
        deflate_chunk_init ( &in, image->data, png->offset,
                             ( png->offset + len ) );
        if ( ( rc = deflate_inflate ( &png->deflate, &in, &png->raw ) ) != 0 ) {
                DBGC ( image, "PNG %s could not decompress: %s\n",
                       image->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static unsigned int png_unfilter_none ( unsigned int  current,
unsigned int left  __unused,
unsigned int above  __unused,
unsigned int above_left  __unused 
) [static]

Unfilter byte using the "None" filter.

Parameters:
currentFiltered current byte
leftUnfiltered left byte
aboveUnfiltered above byte
above_leftUnfiltered above-left byte
Return values:
currentUnfiltered current byte

Definition at line 363 of file png.c.

                                                                           {

        return current;
}
static unsigned int png_unfilter_sub ( unsigned int  current,
unsigned int  left,
unsigned int above  __unused,
unsigned int above_left  __unused 
) [static]

Unfilter byte using the "Sub" filter.

Parameters:
currentFiltered current byte
leftUnfiltered left byte
aboveUnfiltered above byte
above_leftUnfiltered above-left byte
Return values:
currentUnfiltered current byte

Definition at line 380 of file png.c.

                                                                          {

        return ( current + left );
}
static unsigned int png_unfilter_up ( unsigned int  current,
unsigned int left  __unused,
unsigned int  above,
unsigned int above_left  __unused 
) [static]

Unfilter byte using the "Up" filter.

Parameters:
currentFiltered current byte
leftUnfiltered left byte
aboveUnfiltered above byte
above_leftUnfiltered above-left byte
Return values:
currentUnfiltered current byte

Definition at line 397 of file png.c.

                                                                         {

        return ( current + above );
}
static unsigned int png_unfilter_average ( unsigned int  current,
unsigned int  left,
unsigned int  above,
unsigned int above_left  __unused 
) [static]

Unfilter byte using the "Average" filter.

Parameters:
currentFiltered current byte
leftUnfiltered left byte
aboveUnfiltered above byte
above_leftUnfiltered above-left byte
Return values:
currentUnfiltered current byte

Definition at line 414 of file png.c.

                                                                              {

        return ( current + ( ( above + left ) >> 1 ) );
}
static unsigned int png_paeth_predictor ( unsigned int  a,
unsigned int  b,
unsigned int  c 
) [static]

Paeth predictor function (defined in RFC 2083)

Parameters:
aPixel A
bPixel B
cPixel C
Return values:
predictorPredictor pixel

Definition at line 430 of file png.c.

References abs.

Referenced by png_unfilter_paeth().

                                                           {
        unsigned int p;
        unsigned int pa;
        unsigned int pb;
        unsigned int pc;

        /* Algorithm as defined in RFC 2083 section 6.6 */
        p = ( a + b - c );
        pa = abs ( p - a );
        pb = abs ( p - b );
        pc = abs ( p - c );
        if ( ( pa <= pb ) && ( pa <= pc ) ) {
                return a;
        } else if ( pb <= pc ) {
                return b;
        } else {
                return c;
        }
}
static unsigned int png_unfilter_paeth ( unsigned int  current,
unsigned int  left,
unsigned int  above,
unsigned int  above_left 
) [static]

Unfilter byte using the "Paeth" filter.

Parameters:
currentFiltered current byte
above_leftUnfiltered above-left byte
aboveUnfiltered above byte
leftUnfiltered left byte
Return values:
currentUnfiltered current byte

Definition at line 460 of file png.c.

References png_paeth_predictor().

                                                                   {

        return ( current + png_paeth_predictor ( left, above, above_left ) );
}
static int png_unfilter_pass ( struct image image,
struct png_context png,
struct png_interlace interlace 
) [static]

Unfilter one interlace pass of PNG raw data.

Parameters:
imagePNG image
pngPNG context
interlaceInterlace pass
Return values:
rcReturn status code

This routine may assume that it is impossible to overrun the raw data buffer, since the size is determined by the image dimensions.

Definition at line 505 of file png.c.

References assert, byte, copy_from_user(), copy_to_user(), deflate_chunk::data, DBGC, DBGC2, ENOTSUP, filter, png_interlace::height, image::name, NULL, deflate_chunk::offset, offset, png_interlace::pass, png_pixel_len(), png_scanline_len(), png_context::raw, and png_filter::unfilter.

Referenced by png_unfilter().

                                                                 {
        size_t offset = png->raw.offset;
        size_t pixel_len = png_pixel_len ( png );
        size_t scanline_len = png_scanline_len ( png, interlace );
        struct png_filter *filter;
        unsigned int scanline;
        unsigned int byte;
        uint8_t filter_type;
        uint8_t left;
        uint8_t above;
        uint8_t above_left;
        uint8_t current;

        /* On the first scanline of a pass, above bytes are assumed to
         * be zero.
         */
        above = 0;

        /* Iterate over each scanline in turn */
        for ( scanline = 0 ; scanline < interlace->height ; scanline++ ) {

                /* Extract filter byte and determine filter type */
                copy_from_user ( &filter_type, png->raw.data, offset++,
                                 sizeof ( filter_type ) );
                if ( filter_type >= ( sizeof ( png_filters ) /
                                      sizeof ( png_filters[0] ) ) ) {
                        DBGC ( image, "PNG %s unknown filter type %d\n",
                               image->name, filter_type );
                        return -ENOTSUP;
                }
                filter = &png_filters[filter_type];
                assert ( filter->unfilter != NULL );
                DBGC2 ( image, "PNG %s pass %d scanline %d filter type %d\n",
                        image->name, interlace->pass, scanline, filter_type );

                /* At the start of a line, both above-left and left
                 * bytes are taken to be zero.
                 */
                left = 0;
                above_left = 0;

                /* Iterate over each byte (not pixel) in turn */
                for ( byte = 0 ; byte < ( scanline_len - 1 ) ; byte++ ) {

                        /* Extract predictor bytes, if applicable */
                        if ( byte >= pixel_len ) {
                                copy_from_user ( &left, png->raw.data,
                                                 ( offset - pixel_len ),
                                                 sizeof ( left ) );
                        }
                        if ( scanline > 0 ) {
                                copy_from_user ( &above, png->raw.data,
                                                 ( offset - scanline_len ),
                                                 sizeof ( above ) );
                        }
                        if ( ( scanline > 0 ) && ( byte >= pixel_len ) ) {
                                copy_from_user ( &above_left, png->raw.data,
                                                 ( offset - scanline_len -
                                                   pixel_len ),
                                                 sizeof ( above_left ) );
                        }

                        /* Unfilter current byte */
                        copy_from_user ( &current, png->raw.data,
                                         offset, sizeof ( current ) );
                        current = filter->unfilter ( current, left, above,
                                                     above_left );
                        copy_to_user ( png->raw.data, offset++,
                                       &current, sizeof ( current ) );
                }
        }

        /* Update offset */
        png->raw.offset = offset;

        return 0;
}
static int png_unfilter ( struct image image,
struct png_context png 
) [static]

Unfilter PNG raw data.

Parameters:
imagePNG image
pngPNG context
Return values:
rcReturn status code

This routine may assume that it is impossible to overrun the raw data buffer, since the size is determined by the image dimensions.

Definition at line 594 of file png.c.

References assert, deflate_chunk::len, deflate_chunk::offset, png_interlace::pass, png_context::passes, png_interlace(), png_unfilter_pass(), png_context::raw, rc, and png_interlace::width.

Referenced by png_image_end().

                                                                         {
        struct png_interlace interlace;
        unsigned int pass;
        int rc;

        /* Process each interlace pass */
        png->raw.offset = 0;
        for ( pass = 0 ; pass < png->passes ; pass++ ) {

                /* Calculate interlace pass parameters */
                png_interlace ( png, pass, &interlace );

                /* Skip zero-width rows (which have no filter bytes) */
                if ( interlace.width == 0 )
                        continue;

                /* Unfilter this pass */
                if ( ( rc = png_unfilter_pass ( image, png,
                                                &interlace ) ) != 0 )
                        return rc;
        }
        assert ( png->raw.offset == png->raw.len );

        return 0;
}
static unsigned int png_pixel ( unsigned int  raw,
unsigned int  alpha,
unsigned int  max 
) [inline, static]

Calculate PNG pixel component value.

Parameters:
rawRaw component value
alphaAlpha value
maxMaximum raw/alpha value
Return values:
valueComponent value in range 0-255

Definition at line 628 of file png.c.

Referenced by png_pixels_pass().

                                                          {

        /* The basic calculation is 255*(raw/max)*(value/max).  We use
         * fixed-point arithmetic (scaling up to the maximum range for
         * a 32-bit integer), in order to get the same results for
         * alpha blending as the test cases (produced using
         * ImageMagick).
         */
        return ( ( ( ( ( 0xff00 * raw * alpha ) / max ) / max ) + 0x80 ) >> 8 );
}
static void png_pixels_pass ( struct image image,
struct png_context png,
struct png_interlace interlace 
) [static]

Fill one interlace pass of PNG pixels.

Parameters:
imagePNG image
pngPNG context
interlaceInterlace pass

This routine may assume that it is impossible to overrun either the raw data buffer or the pixel buffer, since the sizes of both are determined by the image dimensions.

Definition at line 651 of file png.c.

References assert, channel, png_context::channels, png_context::colour_type, copy_from_user(), copy_to_user(), pixel_buffer::data, deflate_chunk::data, DBGC2, png_context::depth, png_interlace::height, max, image::name, deflate_chunk::offset, png_context::palette, png_interlace::pass, png_context::pixbuf, PNG_COLOUR_TYPE_ALPHA, PNG_COLOUR_TYPE_PALETTE, PNG_COLOUR_TYPE_RGB, png_pixel(), png_context::raw, raw, value, pixel_buffer::width, png_interlace::width, png_interlace::x_indent, png_interlace::x_stride, png_interlace::y_indent, and png_interlace::y_stride.

Referenced by png_pixels().

                                                                {
        size_t raw_offset = png->raw.offset;
        uint8_t channel[png->channels];
        int is_indexed = ( png->colour_type & PNG_COLOUR_TYPE_PALETTE );
        int is_rgb = ( png->colour_type & PNG_COLOUR_TYPE_RGB );
        int has_alpha = ( png->colour_type & PNG_COLOUR_TYPE_ALPHA );
        size_t pixbuf_y_offset;
        size_t pixbuf_offset;
        size_t pixbuf_x_stride;
        size_t pixbuf_y_stride;
        size_t raw_stride;
        unsigned int y;
        unsigned int x;
        unsigned int c;
        unsigned int bits;
        unsigned int depth;
        unsigned int max;
        unsigned int alpha;
        unsigned int raw;
        unsigned int value;
        uint8_t current = 0;
        uint32_t pixel;

        /* We only ever use the top byte of 16-bit pixels.  Model this
         * as a bit depth of 8 with a stride of more than one.
         */
        depth = png->depth;
        raw_stride = ( ( depth + 7 ) / 8 );
        if ( depth > 8 )
                depth = 8;
        max = ( ( 1 << depth ) - 1 );

        /* Calculate pixel buffer offset and strides */
        pixbuf_y_offset = ( ( ( interlace->y_indent * png->pixbuf->width ) +
                              interlace->x_indent ) * sizeof ( pixel ) );
        pixbuf_x_stride = ( interlace->x_stride * sizeof ( pixel ) );
        pixbuf_y_stride = ( interlace->y_stride * png->pixbuf->width *
                            sizeof ( pixel ) );
        DBGC2 ( image, "PNG %s pass %d %dx%d at (%d,%d) stride (%d,%d)\n",
                image->name, interlace->pass, interlace->width,
                interlace->height, interlace->x_indent, interlace->y_indent,
                interlace->x_stride, interlace->y_stride );

        /* Iterate over each scanline in turn */
        for ( y = 0 ; y < interlace->height ; y++ ) {

                /* Skip filter byte */
                raw_offset++;

                /* Iterate over each pixel in turn */
                bits = depth;
                pixbuf_offset = pixbuf_y_offset;
                for ( x = 0 ; x < interlace->width ; x++ ) {

                        /* Extract sample value */
                        for ( c = 0 ; c < png->channels ; c++ ) {

                                /* Get sample value into high bits of current */
                                current <<= depth;
                                bits -= depth;
                                if ( ! bits ) {
                                        copy_from_user ( &current,
                                                         png->raw.data,
                                                         raw_offset,
                                                         sizeof ( current ) );
                                        raw_offset += raw_stride;
                                        bits = 8;
                                }

                                /* Extract sample value */
                                channel[c] = ( current >> ( 8 - depth ) );
                        }

                        /* Convert to native pixel format */
                        if ( is_indexed ) {

                                /* Indexed */
                                pixel = png->palette[channel[0]];

                        } else {

                                /* Determine alpha value */
                                alpha = ( has_alpha ?
                                          channel[ png->channels - 1 ] : max );

                                /* Convert to RGB value */
                                pixel = 0;
                                for ( c = 0 ; c < 3 ; c++ ) {
                                        raw = channel[ is_rgb ? c : 0 ];
                                        value = png_pixel ( raw, alpha, max );
                                        assert ( value <= 255 );
                                        pixel = ( ( pixel << 8 ) | value );
                                }
                        }

                        /* Store pixel */
                        copy_to_user ( png->pixbuf->data, pixbuf_offset,
                                       &pixel, sizeof ( pixel ) );
                        pixbuf_offset += pixbuf_x_stride;
                }

                /* Move to next output row */
                pixbuf_y_offset += pixbuf_y_stride;
        }

        /* Update offset */
        png->raw.offset = raw_offset;
}
static void png_pixels ( struct image image,
struct png_context png 
) [static]

Fill PNG pixels.

Parameters:
imagePNG image
pngPNG context

This routine may assume that it is impossible to overrun either the raw data buffer or the pixel buffer, since the sizes of both are determined by the image dimensions.

Definition at line 772 of file png.c.

References assert, deflate_chunk::len, deflate_chunk::offset, png_interlace::pass, png_context::passes, png_interlace(), png_pixels_pass(), png_context::raw, and png_interlace::width.

Referenced by png_image_end().

                                                                        {
        struct png_interlace interlace;
        unsigned int pass;

        /* Process each interlace pass */
        png->raw.offset = 0;
        for ( pass = 0 ; pass < png->passes ; pass++ ) {

                /* Calculate interlace pass parameters */
                png_interlace ( png, pass, &interlace );

                /* Skip zero-width rows (which have no filter bytes) */
                if ( interlace.width == 0 )
                        continue;

                /* Unfilter this pass */
                png_pixels_pass ( image, png, &interlace );
        }
        assert ( png->raw.offset == png->raw.len );
}
static int png_image_end ( struct image image,
struct png_context png,
size_t  len 
) [static]

Handle PNG image end chunk.

Parameters:
imagePNG image
pngPNG context
lenChunk length
Return values:
rcReturn status code

Definition at line 801 of file png.c.

References DBGC, png_context::deflate, EINVAL, deflate_chunk::len, image::name, deflate_chunk::offset, png_context::pixbuf, png_pixels(), png_unfilter(), png_context::raw, and rc.

                                        {
        int rc;

        /* Sanity checks */
        if ( len != 0 ) {
                DBGC ( image, "PNG %s invalid IEND length %zd\n",
                       image->name, len );
                return -EINVAL;
        }
        if ( ! png->pixbuf ) {
                DBGC ( image, "PNG %s missing pixel buffer (no IHDR?)\n",
                       image->name );
                return -EINVAL;
        }
        if ( ! deflate_finished ( &png->deflate ) ) {
                DBGC ( image, "PNG %s decompression not complete\n",
                       image->name );
                return -EINVAL;
        }
        if ( png->raw.offset != png->raw.len ) {
                DBGC ( image, "PNG %s incorrect decompressed length (expected "
                       "%zd, got %zd)\n", image->name, png->raw.len,
                       png->raw.offset );
                return -EINVAL;
        }

        /* Unfilter raw data */
        if ( ( rc = png_unfilter ( image, png ) ) != 0 )
                return rc;

        /* Fill pixel buffer */
        png_pixels ( image, png );

        return 0;
}
static int png_chunk ( struct image image,
struct png_context png,
uint32_t  type,
size_t  len 
) [static]

Handle PNG chunk.

Parameters:
imagePNG image
pngPNG context
typeChunk type
lenChunk length
Return values:
rcReturn status code

Definition at line 871 of file png.c.

References DBGC, ENOTSUP, png_chunk_handler::handle, htonl, image::name, png_context::offset, PNG_CHUNK_ANCILLARY, png_chunk_handlers, png_type_name(), and png_chunk_handler::type.

Referenced by png_pixbuf().

                                                   {
        struct png_chunk_handler *handler;
        unsigned int i;

        DBGC ( image, "PNG %s chunk type %s offset %zd length %zd\n",
               image->name, png_type_name ( type ), png->offset, len );

        /* Handle according to chunk type */
        for ( i = 0 ; i < ( sizeof ( png_chunk_handlers ) /
                            sizeof ( png_chunk_handlers[0] ) ) ; i++ ) {
                handler = &png_chunk_handlers[i];
                if ( handler->type == type )
                        return handler->handle ( image, png, len );
        }

        /* Fail if unknown chunk type is critical */
        if ( ! ( type & htonl ( PNG_CHUNK_ANCILLARY ) ) ) {
                DBGC ( image, "PNG %s unknown critical chunk type %s\n",
                       image->name, png_type_name ( type ) );
                return -ENOTSUP;
        }

        /* Ignore non-critical unknown chunk types */
        return 0;
}
static int png_pixbuf ( struct image image,
struct pixel_buffer **  pixbuf 
) [static]

Convert PNG image to pixel buffer.

Parameters:
imagePNG image
pixbufPixel buffer to fill in
Return values:
rcReturn status code

Definition at line 905 of file png.c.

References copy_from_user(), image::data, deflate_chunk::data, DBGC, png_context::deflate, deflate_init(), DEFLATE_ZLIB, EINVAL, ENOMEM, free, header, htonl, png_chunk_header::len, image::len, image::name, ntohl, png_context::offset, png_context::pixbuf, png_chunk(), PNG_TYPE_IEND, png_context::raw, rc, png_chunk_header::type, ufree(), and zalloc().

                                                                            {
        struct png_context *png;
        struct png_chunk_header header;
        struct png_chunk_footer footer;
        size_t remaining;
        size_t chunk_len;
        int rc;

        /* Allocate and initialise context */
        png = zalloc ( sizeof ( *png ) );
        if ( ! png ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        png->offset = sizeof ( struct png_signature );
        deflate_init ( &png->deflate, DEFLATE_ZLIB );

        /* Process chunks */
        do {

                /* Extract chunk header */
                remaining = ( image->len - png->offset );
                if ( remaining < sizeof ( header ) ) {
                        DBGC ( image, "PNG %s truncated chunk header at offset "
                               "%zd\n", image->name, png->offset );
                        rc = -EINVAL;
                        goto err_truncated;
                }
                copy_from_user ( &header, image->data, png->offset,
                                 sizeof ( header ) );
                png->offset += sizeof ( header );

                /* Validate chunk length */
                chunk_len = ntohl ( header.len );
                if ( remaining < ( sizeof ( header ) + chunk_len +
                                   sizeof ( footer ) ) ) {
                        DBGC ( image, "PNG %s truncated chunk data/footer at "
                               "offset %zd\n", image->name, png->offset );
                        rc = -EINVAL;
                        goto err_truncated;
                }

                /* Handle chunk */
                if ( ( rc = png_chunk ( image, png, header.type,
                                        chunk_len ) ) != 0 )
                        goto err_chunk;

                /* Move to next chunk */
                png->offset += ( chunk_len + sizeof ( footer ) );

        } while ( png->offset < image->len );

        /* Check that we finished with an IEND chunk */
        if ( header.type != htonl ( PNG_TYPE_IEND ) ) {
                DBGC ( image, "PNG %s did not finish with IEND\n",
                       image->name );
                rc = -EINVAL;
                goto err_iend;
        }

        /* Return pixel buffer */
        *pixbuf = pixbuf_get ( png->pixbuf );

        /* Success */
        rc = 0;

 err_iend:
 err_chunk:
 err_truncated:
        pixbuf_put ( png->pixbuf );
        ufree ( png->raw.data );
        free ( png );
 err_alloc:
        return rc;
}
static int png_probe ( struct image image) [static]

Probe PNG image.

Parameters:
imagePNG image
Return values:
rcReturn status code

Definition at line 987 of file png.c.

References copy_from_user(), image::data, DBGC, ENOEXEC, image::len, memcmp(), and image::name.

                                             {
        struct png_signature signature;

        /* Sanity check */
        if ( image->len < sizeof ( signature ) ) {
                DBGC ( image, "PNG %s is too short\n", image->name );
                return -ENOEXEC;
        }

        /* Check signature */
        copy_from_user ( &signature, image->data, 0, sizeof ( signature ) );
        if ( memcmp ( &signature, &png_signature, sizeof ( signature ) ) != 0 ){
                DBGC ( image, "PNG %s has invalid signature\n", image->name );
                return -ENOEXEC;
        }

        return 0;
}
struct image_type png_image_type __image_type ( PROBE_NORMAL  ) [read]

PNG image type.


Variable Documentation

PNG file signature.

Definition at line 87 of file png.c.

Initial value:

Number of interlacing passes.

Definition at line 90 of file png.c.

Referenced by png_image_header().

struct png_filter png_filters[] [static]
Initial value:

PNG chunk handlers.

Definition at line 855 of file png.c.

Referenced by png_chunk().