As image formats go PNG is superb. If digital cameras had the option to generate .png, the world would be a happier place! PNG is lossless, but compressed, and supports a very wide range of sample formats and colour depths. It fits a niche between plain uncompressed image formats, and JPEG compressed formats. For a given image, a JPEG will usually be smaller, but a PNG will usually have better image quality. For detailed gumph on what PNG can do for you look no further. There's also a Wikimonster spiel here.
LibPNG has another dependency, ZLib. There is more info on our ZLib page, if that's your thing.
The PNG open source project has the noble aim of making this image format available to everyone. Given that it is non-proprietary this is no mean feat. As the folks there note, programming up any binary file format is always a painful task. Anything that can be done to focus that effort into a single code base, makes not only for a widely used format, but a stable format too.
If you want the full benefit of the PNG libraries, they are available here. Our versions of the LibPNG source are slightly modified. We input, and extract the PNG data as a datastream, rather than a file. To achieve this we wrote our own implementation of their buffer functions;
At the time it was considered that this was not the LibPNG authors preferred approach for implementing this. What we should have done is create our own named functions and register them properly with the PNG library. They provide functions explicitly for this purpose. Although it works well enough for us, we don't want to propagate problems for them. What we've done is to publish the changes to their library, as we have made for our purposes. We recommend that if you want to use LibPNG then you download source from them, and modify it for your purposes.
In addition we needed to make some changes to connect it up with our own memory manager;
This, is perhaps something that was never planned for LibPNG. We were unable to immediately determine any scheme by which the memory manager could be formally integrated. Nevertheless these changes worked, and all is well.
Our overall implementation takes a buffer, a buffer size and an ImgPNGInfo struct. The buffer and size are modified, reallocated and translated into the new format. This works in both directions i.e. both to and from PNG. The "other" format is nominally windows bitmap.
The windows BMP format, as used here, has been "modified" to some degree, and it is important to understand how, otherwise it will be difficult to get anything out of these functions. When we refer to the BMP format at this interface, what we mean is BMP format without the windows BITMAPINFOHEADER. It is an essential bitmap, in the sense that the memory block contains a palette (if appropriate) and the actual pixel data. These blocks are represented in the same way they would be with a windows bitmap, and like the bitmap placed in memory consecutively. All of the packing and stuffing of the palette and the pixel data is the same.
The ImgPngInfo struct, is the method by which one can supply the additional information that allows the conversion functions to determine what sort of PNG or bitmap to expect or create. Since there is no actual BITMAPINFO involved, there must at least be a way to describe the colour depth and image size of the bitmap. In most cases, the function just does the best it can. It will choose the best detination format it can on the basis of the source format. Sometimes this is not possible, because there is more than one best desination format, and each has an equivalent loss. The structure allows the user to choose which format is appropriate.
The Bitcount in the ImgPngInfo is straightforward. It is implicit that a bitmap with >8bpp would not have an associated palette. The PNGColor type parameter allows the distinction to be made between paletted greyscale and colour images, since the PNG format does not require a palette for greyscale images, and the BMP format does. XDim and YDim denote the image size, line size denotes the numbr of bytes per line to allow for packing. For more details about XDim, YDim and LineSize check out LibWinImage, and CalcBitmapMetrics() which is capable of creating generating this information. The Trns parameter allows for non alpha based transparency to be communicated. Obviously this is not something that windows bitmaps directly support, but the information must be carried somehow. Trns is set to none for alpha based images, because the bitmap format can handle an alpha channel where it is included in the pixel data. Alternatively it may indicate that an actual colour is passed, or the index of a colour in the palette.
Overall, during converstion of PNG to BMP the ImgPngInfo is filled out by the function png_FromPNG(). The function png_ToPNG() expects that the ImgPngInfo is provided. The overall interface is described;
#define PNG_TYPE_GREY 0
#define PNG_TYPE_PALETTE 1
#define PNG_TYPE_RGB 2
#define PNG_TYPE_ALPHA 3
#define PNG_TRNS_NONE 0
#define PNG_TRNS_INDEX 1
#define PNG_TRNS_COLOR 2
// 8 bit palettes only, 24 bit RGB, 32 bit RGBA
// Palette entries are always four bytes
// Palette and pixel data are always consecutive
// The PNG color type indicates how to treat the palette
// for 8bit maps. PNG uses no palette for greyscale images
// so it is important to keep track of this property when
// loading modifying and saving png files since the associated
// function always returns and expects a palette for any 8 bit image
// Values RGB and ALPHA are purely informational
unsigned long XDim;
unsigned long YDim;
unsigned long LineSize;
// Transparency for PNG should be set by index for GREY and PALETTE
// and by colour for RGB. It is not valid for ALPHA.
// If valid, information is returned this way in FromPNG. When
// presented in ToPng, and this convention is ignored, so will the
// transparency data
unsigned char TrnsIndex;
unsigned long TrnsColor;
void png_ToPNG(void*& pBuf,unsigned long& BufSz,ImgPNGInfo& Info);
void png_FromPNG(void*& pBuf,unsigned long& BufSz,ImgPNGInfo& Info);
This interface to the library doesn't really make any effort to report any errors, or even resolve any conflicts that might arise from requesting an action that it is incapable of fulfilling. If you chose to use this code, then you must implement a scheme to wrap around it, which will prevent those things from occuring.