PNG stands for Portable Network Graphics and is a lossless format for image encoding.

The O’Reilly PNG book, a very comprehensive reference, is now freely available online.

Obviously by now most software worth using supports PNG just fine. To develop your own such software you may need this.

sudo apt-get install libpng-dev

References

Compiling

Don’t forget the -lpng flag!

gcc -lpng -o xedpng xedpng.c

Simplified API

Need to write your own PNGs from C? It might be smart to use the "Simplifed API" which is present after libpng-1.6.0. Simplicity is achieved by limiting formats to a sensible subset of the vast possibilities that PNG theoretically provides for.

Much of the following are choice excerpts from the offical documentation.

Write Procedure Overview

To write a PNG file using the simplified API:

  • 1) Declare a png_image structure on the stack and memset() it to all zero.

  • 2) Initialize the members of the structure that describe the image, setting the format member to the format of the image samples.

  • 3) Call the appropriate png_image_write… function with a pointer to the image and, if necessary, the color-map to write the PNG data.

png_image Definition

png_image is a structure that describes the in-memory format of an image when it is being read or defines the in-memory format of an image that you need to write. The png_image structure contains the following members:

png_controlp opaque  Initialize to NULL, free with png_image_free
png_uint_32  version Set to PNG_IMAGE_VERSION
png_uint_32  width   Image width in pixels (columns)
png_uint_32  height  Image height in pixels (rows)
png_uint_32  format  Image format as defined below
png_uint_32  flags   A bit mask containing informational flags
png_uint_32  colormap_entries; Number of entries in the color-map
png_uint_32  warning_or_error;
char         message[64];

Channels

The pixels (samples) of the image have one to four channels:

  • 1: A single gray or luminance channel (G).

  • 2: A gray/luminance channel and an alpha channel (GA).

  • 3: Three red, green, blue color channels (RGB).

  • 4: Three color channels and an alpha channel (RGBA).

The channel components have original values in the range 0 to 1.0.

The channels are encoded in one of two ways:

Encoding One

As a small integer, value 0..255, contained in a single byte. For the alpha channel the original value is simply value/255. For the color or luminance channels the value is encoded according to the sRGB specification and matches the 8-bit format expected by typical display devices.

The color/gray channels are not scaled (pre-multiplied) by the alpha channel and are suitable for passing to color management software.

Encoding Two

As a value in the range 0..65535, contained in a 2-byte integer,…[etc, etc. but I don’t care about multibyte pixels at this time].

Write Function

int png_image_write_to_file (png_imagep image,
                             const char *file,
                             int convert_to_8bit,
                             const void *buffer,
                             png_int_32 row_stride,
                             const void *colormap));

A row_stride of 0 will compute the correct one for you based on width and number of channels.

Write Example

This small program is close to the smallest sensible libpng image creator.

/* Minimal Sample For Synthesizing PNG Files */
/* Chris X Edwards - xed.ch */
#include "stdlib.h"
#include "string.h"
#include "png.h"
int main(int argc, char** argv){
    png_image image;                             /* Set up image structure. */
    memset(&image, 0, sizeof image);             /* Zero it out. */
    image.version= PNG_IMAGE_VERSION;            /* Encode what version of libpng made this. */
    image.height= 256; image.width= 256;         /* Image pixel dimensions. */
    png_bytep buffer= malloc(PNG_IMAGE_SIZE(image)); /* Reserve image's memory. */
    int n=0;                                     /* Sequential position in entire image buffer. */
    for (int r=0;r<image.width;r++){             /* Row loop. */
        for (int c=0;c<image.height;c++){        /* Column loop. */
            buffer[n]= (r*c)%255;                /* <Do something interesting here.> */
            n++;                                 /* Update position index. */
        }
    }
    png_image_write_to_file (&image, "/tmp/test.png", 0, buffer, 0, NULL); /* Execute image write. */
    return 0;
}

Here is the image that this program produces.

pngwritetest