PNG Encoder / Decoder in C++   

ysflight.com

Introduction

If you buy a product from the above links (you can choose a different product after opening Amazon.com web page,) I can earn some referral fee.  Please help maintain ysflight.com!

From this page you can download a PNG decoder that I've written for my fun.  I've been using BMP file if I need to include a picture in my program for both my job and my hobby.  However, it easily blows the total size of the project directory because BMP format doesn't include any compression scheme.  So, I wrote a PNG decoder.  I suppose some of you have the same problem, so I open the PNG decoder.  It covers most practical bit depths although not all of the bit depths are supported.

PNG is good for hand written pictures, and not as efficient for photos as JPEG because it uses lossless compression scheme.  However, I figured that the compression rate heavily depends on the program you use.  For example,  Paint Shop Pro creates 20 to 30% smaller PNG of a photo than Microsoft Photo Editor, which comes with MS Office.  So, if you need to put a picture in your program, why don't you use PNG?

By the way, YSFLIGHT project is running with marginal budget.  Please visit the following page, and help this project.  Thank you very much for your support!

http://supportysflight.en.ysflight.com

I have written PNG encoder when CMU was closed due to heavy snow fall this February.  I talked about my own PNG encoder to my friend, and his immediate reaction was "Why don't you use libpng?"  50% of the reason was just because I just wanted to write my own PNG encoder.  The other 50% of the reason was I didn't want to waste time to read license agreement of libpng.  I am too scared to use a code from the Internet for potential GPL contamination.  If I am told to download and use a code from the Internet for my work, I will do so because it would be my employer's problem not my problem.  But, for writing my own hobby program, I try to write by myself as much as possible.  So far, I haven't used any code other than libraries that comes with the compiler package for writing my own project.

This encoder is not very efficient in terms of speed and compression ratio.  But, according to [1], although PNG specification itself is open, many patent on PNG-encoding algorithms have been taken, and it would be dangerous unless I strictly stick on the algorithm suggested in [1].  I took that suggestion.

Disclaimer

The source codes you can download from this page -- files included in yspng.zip -- are free to use for any purposes.  You can use it in a free software or a commercial software, open-source or proprietary.  In any cases, you don't need to contact me for permissions.  You even don't have to mention about this web page, but I'll be happy if you put a reference to this page.

However, I do not take any responsibility for the consequence resulted by the use of these codes.  Please use these codes on your own risks.

Download

[Download] yspng.zip (including sample.cpp, yspng.h, yspng.cpp, yspngenc.h, yspngenc.cpp, and encodersample.cpp)

Updates

06/25/2014 (R3021)

Support 4-bit Indexed Color.

03/23/2014 (R2813)

Fixed a bug based on a bug-report from a user.  Sliding-window was not populated while decoding an uncompressed block.  Thank you for the report!  Also from this version is distributed on a BSD license. [Download this version]

01/13/2012 (R958)
Fixed a bug based on a bug-report from a user.  Thanks for the good catch! [Download this version]

09/18/2010
Fixed a bug based on a bug-report from a viewer.  Thanks for the good catch!  The transparency was not processed correctly in interlaced 16-bit true-color mode. [Download this version]

08/26/2010 21:54EDT
I realized my PNG encoder was not calculating CRC code if it was compiled with a 64-bit C++ compiler.  I have fixed the problem. [Download this version]

08/26/2010
Added PNG encoder.

05/15/2005
An easy Linux (GLX) sample PNG viewer is added in the archive (yspng.zip). [Download this version]

05/07/2005
An easy Win32 sample PNG viewer is added in the archive (yspng.zip).

04/08/2005
Started this page.  Still, far from intensively-tested.  So, there can be loads of bugs in it.

Tested Compilers

I have tested this code with Visual C++ 2008 and g++.

Supported Bit-Depths

PNG Decoder

Non-Interlace Interlace
1bit Grayscale (B & W) OK Not Supported
4bit Indexed Color OK Not Supported
8bit Grayscale OK OK
8bit Grayscale with Alpha OK OK
8bit Indexed Color OK OK
24bit True Color (*1) OK OK
24bit True Color with Alpha (*1) OK OK
48bit True Color (*2) OK OK

PNG Encoder (formats that can be used)

Non-Interlace Interlace
1bit Grayscale (B & W) OK Not Supported
4bit Indexed Color Not Supported Not Supported
8bit Grayscale OK Not Supported
8bit Grayscale with Alpha OK Not Supported
8bit Indexed Color Not Supported Not Supported
24bit True Color (*1) OK Not Supported
24bit True Color with Alpha (*1) OK Not Supported
48bit True Color (*2) OK Not Supported

(*1) The PNG specification describes 24bit true color as 8 bit true color (8 bit per component).  But, I think we commonly say "24bit true color" for describing 8-bit-per-component color.  So, I describe it as 24 bit true color here.

(*2) Same as the logic of (*1) I describe 16bit-per-component color as 48bit true color here.

Usage of PNG Decoder Classes

To use the PNG decoder classes, the source code that uses the classes must include yspng.h, and yspng.cpp must be added to the project.

The source codes yspng.h and yspng.cpp include two classes YsGenericPngDecoder and YsRawPngDecoder  YsGenericPngDecoder reads header information and decompress the compressed bitmap data.  However, it does not organize pixels into a format that can directly be transferred to the screen.

YsRawPngDecoder class reads PNG file, and makes an array of R, G, B, and A values, 8bit per component.  The array can be passed to a function like glDrawPixels directly to draw the bitmap image.  (But, if you use glDrawPixels will draw the picture upside-down.  So, you need to flip it before drawing.  You can do it by using Flip member function.  Please see sample.cpp for more details.)  I suppose you only need YsRawPngDecoder for practical purposes.

I describe a brief explanation of each class below.

Please see also sample.cpp for the usage. 

[yspng.cpp, yspng.h]

YsGenericPngDecoder

YsGenericPngDecoder itself does nothing unless you inherit the class and override the member functions -- PrepareOutput, Output, and EndOutput.  If you just need a quick and easy method for getting an array of bitmap, please use YsRawPngDecoder class.

Functions

  • void Initialize(void);
    It initializes the content of the class variable.
  • int Decode(const char fn[]);
    It decodes a PNG file specified by fn.
  • virtual int PrepareOutput(void);
    Decode function first calls this function.
  • virtual int Output(unsigned char dat);
    Decode function passes a byte from the stream of bitmap as it is uncompressed.
  • virtual int EndOutput(void);
    Decode function calls this function after reading all the content of the PNG file.

Variables

  • YsPngHeader hdr;
    Header information.  hdr.width and hdr.height will give the number of pixels.
  • YsPngPalette plt;
    Palette information.
  • YsPngTransparency trns;
    Transparency information.
  • unsigned int gamma;
    Gamma value.  Please read [1] for more details.

YsRawPngDecoder

YsRawPngDecoder class reads a PNG file and makes an array of pixels with R, G, B, and A, 8bit per component.  I think you only need this class practically.

Functions

  • int Decode(const char fn[]);
    It decodes a PNG file specified by fn, and stores the number of pixels in member variables wid and hei, and a pointer to the array of the bitmap in member variable rgba.  If the function succeeds, it returns a macro YSOK, otherwise it returns YSERR.  If your program needs to use the bitmap decoded by this function after the lifetime of the YsRawPngDecoder variable, zero must be set to member variable autoDeleteRgbaBuffer.  Otherwise, the class will automatically delete the array in the destructor.

  • void Flip(void);
    It inverts the image upside-down.  One of the purposes of this class is to draw a PNG bitmap image with OpenGL, but glDrawPixels itself draws a picture upside-down, so I added this function.

Variables

  • int wid,hei;
    The number of pixels of the decoded PNG file.
  • unsigned char *rgba;
    A pointer to the array of bitmaps of the decoded PNG.  Each pixel consists of four components, R, G, B, and A (A is inverse of the transparency.)  Each of R, G, B, and A is 8bit (one unsigned char.)

  • int autoDeleteRgbaBuffer;
    If this variable is non-zero, the memory block that is pointed by rgba is deleted in the destructor of YsRawPngDecoder class.  If your program needs to use the array of the bitmap of the decoded PNG, zero must be set to this variable.  In that case, the memory block must be deleted by your program (like by delete [] rgba;), or the memory block will be remain allocated as memory leak.

[yspngenc.cpp, yspngenc.h]

(* To use the encoder, you will also compile and link yspng.cpp)

YsGenericPngEncoder

This class itself does nothing useful.  To do something useful, you need to make a sub-class from YsGenericPngEncoder and override StreamOut function.  If you just need to write your bitmap to a PNG file, you can use YsRawPngEncoder class instead.

Functions

  • virtual int StreamOut(int nByte,const unsigned char byteData[]) const;
    Override this function to write a PNG data to an appropriate output stream.
  • int Encode(int width,int height,int bitDepth,int colorType,unsigned char dat[]);
    This function encodes a PNG file.  width and height is the picture resolution.  Usable combinations of bitDepth and colorType are as follows:
    bitDepth colorType
    Greyscale 1,2,4,8,16 0
    Truecolor 8,16 2
    Indexed-color Not available 3
    Greyscale with alpha 8,16 4
    Truecolor with alpha 8,16 6

    dat is a pointer for the bitmap data.

  • void SetDontCompress(int dontCompress);
    By specifying dontCompress=1, you can generate an uncompressed PNG.

YsRawPngEncoder

YsRawPngEncoder is a sub-class of YsGenericPngEncoder.  It can create a PNG file.

Function:

  • int EncodeToFile(const char fn[],int width,int height,int bitDepth,int colorType,unsigned char dat[]);
    Create a PNG file.  The file name is fn.  Meaning of other parameters are same as YsGenericPngEncoder::Encode.

References

[1] W3C, Portable Network Graphics (PNG) Specification (Second Edition),  http://www.w3.org/TR/PNG/

<<

Comments are welcome.  Send E-Mail to: 

Back to http://www.ysflight.com