libpng
とはPNG用の公式ライブラリです。ほとんどのPNGの機能をサポートしていて、拡張可能で、七年以上にわたって検証されてきました。開発バージョン(つまり、バグがあるかもしれないし、改変されるかも知れないし、試験的な機能を含んでいるかもしれない)のホームサイトは http://libpng.sourceforge.net/
です。また、ライブラリについて質問は png-implement
メーリングリストにしてください。(libpngホームページ
より)
libpngを使えば、驚くほど簡単にPNGファイルの読み込みや書き込みをする事が出来ます。ここでは、libpngを実際にVisual Studio .NETで使用するまでの手順を説明していきます。(VS 6.0でも動くかも知れないけど、インストールが面倒なので未確認)
libpngはzlibを使用しているので、まずはzlibが必要です。zlibホームサイト
からzlibのソースコードをダウンロードしましょう。zlib source codeと書かれている物をダウンロードすればOKです。zip fileの物を落としておくと展開に面倒がなくていいですね。
つぎに、libpngホームページ
から、libpngのソースコードをダウンロードしましょう。上の方に英語で説明が沢山書いてありますが、それはひとまずおいといて、Source Codeの横にあるリンクをクリックしましょう。これも.zipを落としておくと便利でしょう。
それではファイルを展開します。まず、zlibのアーカイブを展開して出来たファイルを「zlib」という名前のフォルダに放り込んでください。同じようにlibpngアーカイブにも「libpng」と言った名前をつけたフォルダに放り込んでおいてください。その後に、その二つのフォルダを同じディレクトリに入れておきます。
沢山のファイルが出てきましたね。READMEやLICENSEは重要です。使用方法や配布条件について書いてあります。LICENSEについてはこのページの一番最後に解説を書いていますのでそれも参考にしてくださいね。
それではビルドしてみましょう。libpngの方を展開したファイル群のprojects\msvcにlibpng.dswがあるはずなのでそれを開いてください。.NETを使用していると、「7.0形式に変換するか?」という問い合わせのダイアログがでるはずですので、「すべてはい」を押して変換しちゃいましょう。libpngはDLL形式の物も作成できますが、ここではLIB形式の物を作ってみます。[ビルド]→[構成マネージャ]で、LIBを選んでおきましょう。
それが出来たらメニューの[ビルド]→[ソリューションのビルド]を選んでください。ビルドが始まります。正常にビルドが出来ればプロジェクトのあったフォルダの「win32\libpng\lib」にlibpng.libが出来ているはずです。これでlibpngライブラリの完成です。
これでlibpng.libが出来ましたが、VC++から使える状態にしなければ成りません。libpng.libを開発用のフォルダにでも「lib」といったフォルダをつくって入れておきます。また、libpngを展開して出来たpng.hとpngconf.h、zlibを展開して出来たzlib.hとzconf.hも「include」というフォルダをつくって入れておきましょう。
それでは、この二つのフォルダをVC++から認識させます。VC++のメニュー[ツール]→[オプション]の[プロジェクト\VC++ ディレクトリ]の「ディレクトリを表示するプロジェクト:ライブラリ」で、先ほどの「lib」フォルダを一番下に追加します。
同様にインクルードの方にも「include」フォルダも追加すればできあがりです。
これで、libpngを使用する準備は整いました。それでは実際にPNGファイルの読み込みをしてみましょう。
その前にプログラムでlibpngを使用する事を宣言するために、先頭に
|
#include "png.h" #pragma comment(lib, "libpng.lib") |
int LoadPngFile(HWND hWnd){
FILE *fp = fopen("test.png", "rb");
if(!fp) return 0;
ktFileCloser pngfilecloser(fp);
int fsize;
unsigned char *FileImage = (unsigned char*)malloc((fseek(fp, 0, SEEK_END), fsize = ftell(fp)));
ktMemoryReleaser fileimagereleaer(FileImage);
fseek(fp, 0, SEEK_SET);
fread(FileImage, fsize, 1, fp);
|
if(!png_check_sig(FileImage, fsize))
return 0;
png_struct *pPng;
png_info *pInfo;
if(!(pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
return 0;
if(!(pInfo = png_create_info_struct(pPng)))
return 0;
ktPngReadStructReleaser pngreleaser(pPng, pInfo);
|
| int png_sig_check(png_bytep sig, int num) | ||
| 引数: | sig | チェックするデータ |
| num | データのサイズ(8以上でなければなりません。) | |
| 返り値: | PNGファイルなら非ゼロ | |
| png_structp png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn) | ||
| 引数: | user_png_ver | PNGのバージョンを指定します。PNG_LIBPNG_VER_STRINGを使っておけばいいです。 |
| error_ptr, error_fn, warn_fn | エラーが起こったときに呼び出される関数と渡されるデータです・・・が、今回は使用していません。NULLにしています。 | |
| 返り値: | 成功すれば正常なpng_struct *を返します。失敗した場合はNULL値になります。 | |
| int png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr) | ||
| 引数: | png_ptr_ptr | png_create_read_structで取得できたpng_struct *へのアドレスを指定します。 |
| info_ptr_ptr | png_create_info_struct(後述)で取得したpng_info *へのアドレスを指定します。一緒に閉じられます。 | |
| end_info_ptr_ptr | 今回は使いません。NULLを指定しておいてください。 | |
| png_info_structp png_create_info_struct(png_structp png_ptr) | ||
| 引数: | png_ptr | png_create_read_structで取得できたpng_struct *へのアドレスを指定します。 |
| 返り値: | 成功すれば正常なpng_info_struct *を返します。失敗した場合はNULL値になります。 | |
unsigned char* filepos = FileImage;
png_set_read_fn(pPng,(png_voidp)&filepos,(png_rw_ptr)PngReadFunc);
|
void PngReadFunc(png_struct *pPng, png_bytep buf, png_size_t size){
unsigned char** p = (unsigned char**)png_get_io_ptr(pPng);
memcpy(buf, *p, size);
*p += (int)size;
}
|
png_read_info(pPng, pInfo);
png_uint_32 PngWidth;
png_uint_32 PngHeight;
int bpp;
int ColorType;
png_get_IHDR(pPng, pInfo, &PngWidth, &PngHeight, &bpp, &ColorType, NULL, NULL, NULL);
|
if(png_get_valid(pPng, pInfo, PNG_INFO_tRNS))
png_set_expand(pPng);
if(ColorType == PNG_COLOR_TYPE_PALETTE)
png_set_expand(pPng);
if(ColorType == PNG_COLOR_TYPE_GRAY && bpp < 8)
png_set_expand(pPng);
if(bpp > 8)
png_set_strip_16(pPng);
if(ColorType == PNG_COLOR_TYPE_GRAY)
png_set_gray_to_rgb(pPng);
|
unsigned char *BmpBuffer;
unsigned char **Lines;
BmpBuffer = (unsigned char *)malloc(PngWidth * PngHeight * 4);
Lines = (unsigned char **)malloc(sizeof(unsigned char *) * PngHeight);
for(int i = 0; i < PngHeight; i++)Lines[i] = BmpBuffer + PngWidth * 4 * i;
if(!(ColorType & PNG_COLOR_MASK_ALPHA))png_set_filler(pPng, 0, 1);
png_set_bgr(pPng);
png_read_image(pPng, Lines);
free(Lines);
|
HBITMAP hBmp = CreateBitmap(PngWidth, PngHeight, 1, 32, BmpBuffer);
if(!hBmp)return 0;
ktGDIReleaser hbmpreleaser(hBmp);
HDC hDC = CreateCompatibleDC(NULL);
if(!hDC)return 0;
ktGDIReleaser hdcreleaser(hDC);
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);
HDC hWndDC = GetDC(hWnd);
BitBlt(hWndDC, 0, 0, PngWidth, PngHeight, hDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, hWndDC);
SelectObject(hDC, hOldBmp);
|