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
-
The documentation leaves quite a bit to be desired. You may need to go to the source code. I also found the
example.c
program helpful. It’s a pain to just look at so it’s best to just do it like this:wget -qO- https://dev.w3.org/Amaya/libpng/example.c | less
-
The source code. Especially "SIMPLIFIED API" in the png.h header file.
-
Andrew Greensted’s excellent notes. Tested. Works.
-
Apparently John Carmack likes this no nonsense image library. So if you need more than just PNGs and want it lightweight and in C, check that out.
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.