PNG Encoder / Decoder in C++ 

ysflight.com

はじめに


上のリンクから商品をご購入いただけると、少しの紹介料が作者に入ります。よかったら、サイト運営にご協力ください。

このページでは、趣味で書いたPNGエンコーダ / デコーダを公開しています。今まで、自作ソフトで(仕事でも趣味でも)ビットマップの読み込みといえば、必ずBMPを使っていたんですが、そうするとプロジェクト全体のファイルのサイズがすぐ膨れてしまって、さらに、芸が無いのが気になって、それなりの圧縮ができるフォーマットに対応しようと一念発起して、PNG Decoderを書きました。せっかくなので、他にも同じような問題を持っている人がいると思うので、公開することにしました。まだ未対応のBit Depthもありますが、一応、普通に使う分はすべてカバーしたつもりです。

PNGファイルは、どっちかというと、手書き絵向けで、(可逆圧縮だけに)写真などはJPEGほど圧縮率は良くありませんが、しかし、PNGを作るソフトの性能によって、サイズが結構違ってくるようです。僕はPaint Shop Pro を使っていますが、このPNG Optimizerというのをかけてやると、MS OfficeについてくるMicrosoft Photo EditorでPNGを作るよりも、20〜30%自然がのサイズが小さくなります。自分のプログラムに絵を追加したい、けれどもビットマップファイルを展開して置いておくのもあまり芸が無い、という方は、PNGを利用してみてはどうでしょうか?

なお、YSFLIGHTプロジェクトは、慢性的にぎりぎり予算が続いています。よかったら、以下のリンクでサイト運営にご協力いただけると大変ありがたく思います。ご協力感謝します。

http://supportysflight.jp.ysflight.com

なお、2月ぐらいに、大雪が降って大学が閉鎖になってアパートに閉じこもっていた間、エンコーダも書きました。という話を友達にしたら、なんでlibpngを使わないの?と言われましたが、単に作ってみたかった、という理由が50%で、libpngの使用ライセンス条項を読むのが面倒くさかったというのが50%ぐらいです。どうも、ネットに落ちてるコードには、GPL地雷が仕掛けてあるんじゃないかと心配になるので、怖くて使えません。仕事で使えと言われりゃそれは、使えと言う人の責任だから使いますが。

このエンコーダは、必ずしも効率(圧縮率、スピードともに)は良くありません。が、[1]の記述によると、どうも、PNGの仕様事態はオープンにも関わらず、エンコードのアルゴリズムにはいろいろ特許が取られているようで、[1]の勧める方法に厳密に沿って書かないと危険とのことだったので、愚直に[1]の方法に沿って書きました。

このページからダウンロードできるコードの利用について

このページからダウンロードできるコード(yspng.zipに含まれるファイル)は、とくにどのような目的に利用していただいても構いません。その目的がフリーソフトでも、商用ソフトでもどちらの場合でも、とくに作者に連絡しなくても使っていただいて結構です。それから、利用するプログラムがオープンソースでも、プロプライエタリでも、どちらでもいいです。なお、利用する場合、とくに出展の記述などは入れていただかなくても構いませんが、もちろん、入れていただければその方がうれしいです。

ただし、このコードを利用した結果について、作者は一切責任を負いませんので、利用する方ご自身の責任でご利用ください。

ダウンロード

[ダウンロード] yspng.zip (sample.cpp, yspng.h, yspng.cpp, yspngenc.cpp, yspngenc.h, encodersample.cppを含みます)

更新履歴

2014/06/25 (R3021)

4-bit Indexed Color対応。

2014/03/22 (R2813)
ユーザからのバグレポートに対応。無圧縮のブロックを読み込み中、スライディングウィンドウにデータをコピーしてなかった。ご報告ありがとうございました! あと、実質的になんも変わってないけど、ライセンス条項をBSDライセンスにした。[このバージョンをダウンロード]

2012/01/13 (R958)
ユーザからのバグレポートに対応。単色半透明色を正しく読み込んでなかった。ご報告ありがとうございました。[このバージョンをダウンロード]

2010/09/18
ユーザからのバグレポートに対応。16ビット、インタレースモード、True colorモードで、単色透明処理の透明色判定が間違っていたので修正。ご報告ありがとうございました。 [このバージョンをダウンロード]

2010/08/26 21:54アメリカ東部時間
ふと気になって64 bitコンパイラでコンパイルしてみたらCRCの計算が間違うことが判明したので修正。 [このバージョンをダウンロード]

2010/08/26
エンコーダを公開。

2005/05/15
Linux (GLX) サンプルの簡単なコマンドラインPNGビューアを追加しました。yspng.zipに一緒に入ってます。 [このバージョンをダウンロード]

2005/05/07
Win32サンプル(簡単なPNGビューア)を追加しました。yspng.zip に一緒に入ってます。

2005/04/08
公開。まだとても強力にテスト済みという状態ではないので、バグってる可能性大です。

対応コンパイラ

Visual C++ 2010とg++で確認しました。

対応Bit Depth

Bit Depthって日本語になんて訳すんでしたっけ?ビット深度?

PNG Decoder

Non-Interlace Interlace
1bit Grayscale (Black & White) ×
4bit Indexed Color ×
8bit Grayscale
8bit Grayscale with Alpha
8bit Indexed Color
24bit True Color (*1)
24bit True Color with Alpha (*1)
48bit True Color (*2)

PNG Encoder (出力可能なタイプ)

Non-Interlace Interlace
1bit Grayscale (Black & White) ×
4bit Indexed Color × ×
8bit Grayscale ×
8bit Grayscale with Alpha ×
8bit Indexed Color × ×
24bit True Color (*1) ×
24bit True Color with Alpha (*1) ×
48bit True Color (*2) ×

(*1) PNGのSpecificationでは、24bit True Colorのことを8 bit True Colorと表記していますが(8bit per component)一般的には24bitと書くと思うので、ここではそのように書きます。

(*2) 24bit True Colorと同じ理屈で、R,G,Bそれぞれ16ビットをここでは、48bit True Colorと書きます。

PNG Decoder Classの使い方

PNG Decoderクラスを利用するには、利用するソースコードにyspng.hをincludeして、プロジェクトにyspng.cppを追加してください。

yspng.h, yspng.cppは、ふたつのクラス、YsGenericPngDecoderとYsRawPngDecoder、を含みます。YsGenericPngDecoderは、ヘッダの読み込みと圧縮データの展開をしますが、ピクセルデータを並べて表示可能な状態にする機能はありません。

YsRawPngDecoderは、PNGファイルを読み込んで、とにかくどの対応Bit DepthでもR,G,B,Aそれぞれ8ビットの配列に並べます。なので、その配列へのポインタは、例えばglDrawPixelsに直接渡して描画することができます。ただし、そのままでは上下反転しているので、表示前にいったん反転しておく必要がありますが、それは、YsRawPngDecoderのFlip関数でできます。それについては、sample.cppを参照してください。YsRawPngDecoderがあれば実用的には困らないのではないかと思います。

以下にそれぞれの使い方を書きます。すべての関数と変数は書いてないですが、大体使うのに十分程度なものだけ書きます。

使い方のサンプルは、sample.cppも参照してください。

[yspng.cpp, yspng.h]

YsGenericPngDecoder

YsGenericPngDecoderは、そのままでは、事実上何もしません。YsGenericPngDecoderを継承したクラスがPrepareOutput, Output, EndOutputの3関数をオーバーライドすることで、機能するPNGデコーダになります。手っ取り早く展開したビットマップが欲しいだけの場合は、YsRawPngDecoderクラスを参照してください。

関数

  • void Initialize(void);
    読み込み前にクラスの中身を初期化します。
  • int Decode(const char fn[]);
    fnで与えられたファイル名の.PNGファイルをデコードします。
  • virtual int PrepareOutput(void);
    Decode関数が、最初にこの関数を呼び出します。
  • virtual int Output(unsigned char dat);
    Decode関数が、圧縮されたビットマップデータを展開して、一バイト分だけ出力するためにこの関数を呼び出します。その他のヘッダ情報はDecode関数の中で処理するので、hdr, plt, trns, gammaなどのメンバ変数を参照することでヘッダ情報を見ることができます。
  • virtual int EndOutput(void);
    Decode関数が、読み込み終了後にこの関数を呼びます。

変数

  • YsPngHeader hdr;
    ヘッダ情報です。hdr.width, hdr.heightが横と縦のピクセル数です。
  • YsPngPalette plt;
    パレット情報です。
  • YsPngTransparency trns;
    透明色です。
  • unsigned int gamma;
    ガンマです。詳しくは、参考文献[1]を参照してください。

YsRawPngDecoder

YsRawPngDecoderは、PNGファイルを読み込んで、R,G,B,Aそれぞれ8ビットのピクセル情報を配列に展開します。とりあえず、手っ取り早くPNGを読み込んで表示したい場合は、このクラスが便利です。

関数

  • int Decode(const char fn[]);
    fnで与えられたファイル名の.PNGファイルをデコードして、メンバwid, heiにピクセル数を、rgbaにビットマップの配列へのポインタをセットします。読み込みに成功したときは、マクロYSOKを、失敗したときはマクロYSERRを返します。なお、このクラスで読み込んだビットマップの配列を、このクラスのライフタイム後に利用したい場合(例えば、YsRawPngDecoderクラスをローカル変数として定義して、読み込んだビットマップはその関数が終わった後も利用したいような場合)、メンバautoDeleteRgbaBufferにゼロをセットしてください。そうでないと、YsRawPngDecoderは、終了時に自動的にrgbaが指すメモリブロックを解放してしまいます。
  • void Flip(void);
    読み込んだビットマップの上下を反転します。このクラスは、とりあえず僕はOpenGLでPNG形式のビットマップを表示したかったとかいう目的で作ったのですが、そのままだとOpenGLは上下さかさまの絵を描いてしまうので、上下反転する関数を追加しました。

変数

  • int wid,hei;
    読み込んだPNGファイルのピクセル数です。
  • unsigned char *rgba;
    読み込んだPNGのビットマップのR,G,B,A値がストアしてある配列へのポインタです。
  • int autoDeleteRgbaBuffer;
    これがゼロでない場合、ポインタrgbaが指すメモリブロックを、YsRawPngDecoderが終了するとき、またはDecode関数が二度目以降呼ばれたとき、自動的に解放します。もしも、読み込んだビットマップをこのクラス外部で利用したい場合は、この値にゼロをセットしてください。なお、その場合、rgbaが指すメモリブロックを、delete [] rgba;みたいな形で解放しないと、メモリリークになるので気をつけてください。

[yspngenc.cpp, yspngenc.h]

(* エンコーダを使うには、yspng.cppもコンパイルしてリンクする必要があります。)

YsGenericPngEncoder

YsGenericPngEncoderクラスは、そのままだと何もしません。StreamOut関数をオーバーライドして、ファイルとかに出力するようにして使うようになってます。ファイルに出力するだけであれば、YsRawPngEncoderクラスを使ってください。

関数

  • virtual int StreamOut(int nByte,const unsigned char byteData[]) const;
    Encode関数がこの関数を呼び出すので、この関数をオーバーライドして、必要な出力先に出力するようにコードを書いてください。
  • int Encode(int width,int height,int bitDepth,int colorType,unsigned char dat[]);
    PNGファイルをエンコードします。width,heightが解像度の指定で、使用可能なbitDepthとcolorTypeの組み合わせは以下の通りです。
    bitDepth colorType
    Greyscale 1,2,4,8,16 0
    Truecolor 8,16 2
    Indexed-color 使用不可 3
    Greyscale with alpha 8,16 4
    Truecolor with alpha 8,16 6

    datは、出力したいビットマップのポインタです。

  • void SetDontCompress(int dontCompress);
    dontCompressに1を指定することで、無圧縮PNGを作ることができます。

YsRawPngEncoder

YsRawPngEncoderクラスは、YsGenericPngEncoderクラスの派生クラスで、メモリ上のビットマップをPNG形式のファイルに保存します。

関数

  • EncodeToFile(const char fn[],int width,int height,int bitDepth,int colorType,unsigned char dat[]);
    ファイル名fnのPNGファイルにビットマップを出力します。‘width,height,bitDepth,colorType,datは、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