The png Module

Pure Python PNG Reader/Writer

This Python module implements support for PNG images (see PNG specification at http://www.w3.org/TR/2003/REC-PNG-20031110/ ). It reads and writes PNG files with all allowable bit depths (1/2/4/8/16/24/32/48/64 bits per pixel) and color combinations: greyscale (1/2/4/8/16 bit); RGB, RGBA, KA (greyscale with alpha) with 8/16 bits per channel; colormapped images (1/2/4/8 bit). Adam7 interlacing is supported for reading and writing. A number of optional chunks can be specified (when writing) and understood (when reading): tRNS, bKGD, gAMA.

For help, type import png; help(png) in your python interpreter.

A good place to start is the Reader and Writer classes.

This file can also be used as a command-line utility to convert Netpbm PNM files to PNG, and the reverse conversion from PNG to PNM. The interface is similar to that of the pnmtopng program from Netpbm. Type python png.py --help at the shell prompt for usage and a list of options.

A note on spelling

  • greyscale (British English);
  • color (North American English).

A note on formats

When getting pixel data out of this module (reading) and presenting data to this module (writing) there are a number of ways the data could be represented as a Python value. Generally this module uses one of three formats called “flat row flat pixel”, “boxed row flat pixel”, and “boxed row boxed pixel”. Basically the concern is whether each pixel and each row comes in its own little tuple (box), or not.

Consider an image that is 3 pixels wide by 2 pixels high, and each pixel has RGB components:

Boxed row flat pixel:

list([R,G,B, R,G,B, R,G,B],
     [R,G,B, R,G,B, R,G,B])

Each row appears as its own list, but the pixels are flattened so that three values for one pixel simply follow the three values for the previous pixel. This is the most common format used, because it provides a good compromise between space and convenience. The module regards itself as at liberty to replace any sequence type with any sufficiently compatible other sequence type; in practice each row is an array (from the array module), and the outer list is sometimes an iterator rather than an explicit list (so that streaming is possible).

Flat row flat pixel:

[R,G,B, R,G,B, R,G,B,
 R,G,B, R,G,B, R,G,B]

The entire image is one single giant sequence of colour values. Generally an array will be used (to save space), not a list.

Boxed row boxed pixel:

list([ (R,G,B), (R,G,B), (R,G,B) ],
     [ (R,G,B), (R,G,B), (R,G,B) ])

Each row appears in its own list, but each pixel also appears in its own tuple. A serious memory burn in Python.

In all cases the top row comes first, and for each row the pixels are ordered from left-to-right. Within a pixel the values appear in the order, R-G-B-A (or K-A for greyscale–alpha).

There is a fourth format, mentioned because it is used internally, is close to what lies inside a PNG file itself, and may one day have a public API exposed for it. This format is called serialised. When serialised an image is a sequence of bytes (integers from 0 to 255). Each row is packed into bytes (if bit depth < 8) or decomposed into bytes (big-endian, if bit depth is 16). This isn’t a particularly convenient format, but it is produced (in part) as a necessary step for decoding and encoding PNG files. There are some sorts of PNG to PNG recoding where this might be the most efficient format to use.

And now, my famous members

class png.Reader(_guess=None, **kw)

PNG decoder in pure Python.

Create a PNG decoder object.

The constructor expects exactly one keyword argument. If you supply a positional argument instead, it will guess the input type. You can choose among the following arguments: filename - name of PNG input file file - object with a read() method bytes - array or string with PNG data

asRGB8()

Return the image data as an RGB image with 8-bits per sample. Greyscales are expanded into RGB triplets; bit depths less than 8 are scaled up to 8-bits; bit depths greater than 8 are scaled down to 8 (note: no dithering is performed). An alpha channel will raise an exception.

This function returns a 4-tuple: (width, height, pixels, metadata). width, height, metadata are as per the read() method.

pixels is the pixel data in boxed row boxed pixel format. It is an iterator that yields each row. A row is a sequence of pixels; each pixel is an (R,G,B) triple with each channel being from 0 to 255.

asRGB8Aopt(n, dropalpha=False)
n is the number of channels in the target.
asRGBA8()
Return the image data as an RGBA image with 8-bits per sample. Greyscales are expanded into RGB triplets; an alpha channel is synthesized if necessary. Otherwise performs same as asRGB8().
chunk(seek=None)
Read the next PNG chunk from the input file; returns type (as a 4 character string) and data. If the optional seek argument is specified then it will keep reading chunks until it either runs out of file or finds the type specified by the argument. Note that in general the order of chunks in PNGs is unspecified, so using seek can cause you to miss chunks.
deinterlace(raw)
Read raw pixel data, undo filters, deinterlace, and flatten. Return in flat row flat pixel format.
iterboxed(rows)
Iterator that yields each scanline in boxed row flat pixel format. rows should be an iterator that yields the bytes of each row in turn.
iterstraight(raw)
Iterator that undoes the effect of filtering, and yields each row in serialised format (as a sequence of bytes). Assumes input is straightlaced. raw should be an iterable that yields the raw bytes in chunks of arbitrary size.
preamble()
Extract the image metadata by reading the initial part of the PNG file up to the start of the IDAT chunk. All the chunks that precede the IDAT chunk are read and either processed for metadata or discarded.
process_chunk()
Process the next chunk and its data. This only processes the following chunk types, all others are ignored: IHDR, PLTE, bKGD, tRNS, gAMA.
read()

Read the PNG file and decode it. Returns (width, height, pixels, metadata).

May use excessive memory.

pixels are returned in boxed row flat pixel format.

read_flat()

Read a simple PNG file; return width, height, pixels and image metadata.

This function is a very early prototype with limited flexibility and excessive use of memory.

pixels are returned in flat row flat pixel format.

serialtoflat(bytes, width=None)
Convert serial format (byte stream) pixel data to flat row flat pixel.
undo_filter(filter_type, scanline, previous)

Undo the filter for a scanline. scanline is a sequence of bytes that does not include the initial filter type byte. previous is decoded previous scanline (for straightlaced images this is the previous pixel row, but for interlaced images, it is the previous scanline in the reduced image, which in general is not the previous pixel row in the final image). When there is no previous scanline (the first row of a straightlaced image, or the first row in one of the passes in an interlaced image), then this argument should be None.

The scanline will have the effects of filtering removed, and the result will be returned as a fresh sequence of bytes.

validate_signature()
If signature (header) has not been read then read and validate it; otherwise do nothing.
class png.Writer(width, height, greyscale=False, alpha=False, bitdepth=8, palette=None, transparent=None, background=None, gamma=None, compression=None, interlace=False, bytes_per_sample=None, chunk_limit=1048576)

PNG encoder in pure Python.

Create a PNG encoder object.

Arguments: width, height - size of the image in pixels greyscale - input data is greyscale, not RGB alpha - input data has alpha channel (RGBA or KA) bitdepth - 1, 2, 4, 8, or 16 palette - create a palettized image (color type 3) transparent - create a tRNS chunk background - create a bKGD chunk gamma - create a gAMA chunk compression - zlib compression level (1-9) interlace - create an interlaced image chunk_limit - write multiple IDAT chunks to save memory

greyscale and alpha are booleans that specify whether an image is greyscale (or color), and whether it has an alpha channel (or not).

bitdepth specifies the bit depth of the PNG image. This is the number of bits used to specify the value of each color channel (or index, in the case of a palette). PNG allows this to be 1,2,4,8, or 16, but there are some restrictions on some values.

For greyscale and palette images the PNG specification allows the bit depth to be less than 8. For other types, bit depths less than 8 are rejected.

The palette option, when specified, causes a palettized (colour-mapped) image to be created: the PNG color type is set to 3; greyscale must not be set; alpha must not be set; transparent must not be set; the bit depth must be 1,2,4, or 8.

The palette argument value should be a sequence of 3- or 4-tuples. 3-tuples specify RGB palette entries; 4-tuples specify RGBA palette entries. If both 4-tuples and 3-tuples appear in the sequence then all the 4-tuples must come before all the 3-tuples. A PLTE chunk is created; if there are 4-tuples then a tRNS chunk is created as well. The PLTE chunk will contain all the RGB triples in the same sequence; the tRNS chunk will contain the alpha channel for all the 4-tuples, in the same sequence. Palette entries are always 8-bit.

If specified, the transparent and background parameters must be a tuple with three integer values for red, green, blue, or a simple integer (or singleton tuple) for a greyscale image.

If specified, the gamma parameter must be a positive number (generally, a float). A gAMA chunk will be created. Note that this will not change the values of the pixels as they appear in the PNG file, they are assumed to have already been converted appropriately for the gamma specified.

The default for the compression argument is None; this does not mean no compression, rather it means that the default from the zlib module is used (which is generally acceptable).

If interlace is true then an interlaced image is created (using PNG’s so far only interace method, Adam7). This does not affect how the pixels should be presented to the encoder, rather it changes how they are arranged into the PNG file. On slow connexions interlaced images can be partially decoded by the browser to give a rough view of the image that is successively refined as more image data appears. Caution: enabling this option requires the entire image to be processed in working memory.

chunk_limit is used to limit the amount of memory used whilst compressing the image. In order to avoid using large amounts of memory, multiple IDAT chunks may be created.

array_scanlines(pixels)
Generates boxed rows (flat pixels) from flat rows (flat pixels) in an array.
array_scanlines_interlace(pixels)
Generator for interlaced scanlines from an array. pixels is the full source image in flat row flat pixel format. The generator yields each scanline of the reduced passes in turn, in boxed row flat pixel format.
convert_pnm(infile, outfile)
Convert a PNM file containing raw pixel data into a PNG file with the parameters set in the writer object. Works for PGM and PPM formats.
convert_ppm_and_pgm(ppmfile, pgmfile, outfile)
Convert a PPM and PGM file containing raw pixel data into a PNG outfile with the parameters set in the writer object.
file_scanlines(infile)
Generates boxed rows in flat pixel format, from the input file infile.
make_palette()
Create the byte sequences for a PLTE and if necessary a tRNS chunk. Returned as a pair (p, t). t will be None if no tRNS chunk is necessary.
write(outfile, rows)
Write a PNG image to the output file. rows should be an iterable that yields each row in boxed row flat pixel format. The rows should be the rows of the original image, so there should be self.height rows of self.width * self.planes values. If interlace is specified (when creating the instance), then the interlacing is carried out internally. This will require the entire image to be in working memory.
write_array(outfile, pixels)
Write an array in flat row flat pixel format as a PNG file on the output file.
write_chunk(outfile, tag, data='')
Write a PNG chunk to the output file, including length and checksum.
write_passes(outfile, rows)
Write a PNG image to the output file. The rows should be given to this method in the order that they appear in the output file. For straightlaced images, this is the usual top to bottom ordering, but for interlaced images the rows should have already been interlaced before passing them to this function. Most users are expected to find the write() or write_array() method more convenient. rows should be an iterable that yields each row in boxed row flat pixel format.