プログラムTIPS

DEMO PROGRAM ヘキサドライブでは様々な研究開発をしています。その一部を紹介。

GDI+でBMP/PNG/JPEGの読み込みを簡単に(2013年11月28日)

今回はゲーム就職作品に役立てられそうなプログラムをひとつ紹介してみたいと思います。

3D作品にDirectXを使用しているとテクスチャの読み込みに対しては特に不便を感じることなく簡単に読み込むことができます。
DirectXにはD3DX拡張ライブラリにテクスチャロード用の関数が予め用意されているため、
様々な画像形式をテクスチャとしてロードすることができます。
しかしながら、場合によってはOpenGLなどの別のプラットフォームで制作することもあったりすると途端にその恩恵にあずかることができなくなってしまいます。

BMP形式は比較的簡単なフォーマットですので自作してもさほど苦労はしないと思います。
PNGやJPEG形式などはその形式独自の圧縮アルゴリズムがあり、自力で展開して利用するのは非常に骨の折れる実装になってしまいます。
もちろん実際にはそんなことにならないようにオープンソースライブラリでlibpnglibjpegのように展開を肩代わりしてくれるものが提供されています。
これらを活用することで比較的簡単に画像を読み込むことができるようになります。

libpng
http://www.libpng.org/pub/png/libpng.html
→動作にはzlib ( http://www.zlib.net/ )が必要になります。

libjpeg
http://libjpeg.sourceforge.net/
2012-01-05-1.png
【図】それぞれの形式専用の展開ライブラリを適用して読み込み

オープンソース系のライブラリはlibpngのようにライセンス的にも緩く簡単に活用できるものが存在しています。
応用できるところには適切に導入していくことで制作の労力を大幅に軽減できます。

まだプログラミングを始めて経験が浅い時には、このようなライブラリを組み込む事自体にも難易度が高く感じたりすることがあると思います。
もっと敷居が低い方法で簡単に実現できる方法があれば嬉しいですよね。

Windows環境限定になりますが、WindowsXP以降には「GDI+」というグラフィックAPIが拡張新設されています。
そのなかに画像ファイルの読み込みをサポートするモジュールも存在しており、最初から簡単に利用できるようになっています。

GDI+を使用して画像ファイルを読み込む場合は同じロード処理で複数の画像形式に対応することができます。

2012-01-05-2.png
【図】GDI+では様々な画像形式を共通のAPIで扱うことができる

line645

早速ですが、ソースコードを御覧ください。

【ヘッダ部】

//---------------------------------------------------------------------------
// 最低限必要なプラットフォームが WindowsXPであることを指定します。
// ※ GDI+ APIを利用するため、WindowsXP以降が必要になります。
//---------------------------------------------------------------------------
#define WINVER          0x0501      // 0x0501 = WindowsXP
#define _WIN32_WINNT    0x0501
 
#include 
//---- GDI+ヘッダ関連
#include 
#pragma comment (lib, "gdiplus.lib")        // リンク時に必要なライブラリ

【実装部】

bool LoadImage(const char fileName[])
{
    // 文字コードをワイド文字列に変換
    // 【注意】本来はこの箇所は文字列バッファ長の考慮の他に文字列終端コードを処理するよりセキュアな対応が好ましいです。
    wchar_t     path[ MAX_PATH ];
    size_t      pathLength = 0;
 
    if( mbstowcs_s( &pathLength,            // [out]    変換された文字数
                    &path[0],               // [out]    変換されたワイド文字列を格納するバッファのアドレス(変換先)
                    MAX_PATH,               // [in]     出力側のバッファのサイズ(単位:文字数)
                    fileName,               // [in]     マルチバイト文字列のアドレス(変換元)
                    _TRUNCATE ) != 0 ) {    // [in]     出力先に格納するワイド文字の最大数
        return false;
    }
 
    //  GDI+オブジェクト(画像展開に必要)
    Gdiplus::GdiplusStartupInput    gdiplusStartupInput;
    ULONG_PTR                       gdiplusToken;
 
    //---- GDI+の初期設定
    if( Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) !=  Gdiplus::Ok ) {
        return false;
    }
 
    //-------------------------------------------------------------
    // 画像の読み込み
    //-------------------------------------------------------------
    bool    result = false;
    int     width  = 0;         // 画像の幅
    int     height = 0;         //  〃  高さ
 
    //--- 画像ファイルを開く
    //  【対応画像形式】  BMP, JPEG, PNG, GIF, TIFF, WMF, EMF
    Gdiplus::Bitmap*    pBitmap = Gdiplus::Bitmap::FromFile(path);
    if( pBitmap && pBitmap->GetLastStatus() == Gdiplus::Ok ) {
        //---- 画像サイズ分の領域確保
        width  = pBitmap->GetWidth();
        height = pBitmap->GetHeight();
 
        // ■ロードする画像のメモリの解像度を変更/設定(この位置に任意に記述して下さい)
        if( /* createBuffer(width, height)*/ ) {
            result = true;
        }
    }
 
    //---- 画像イメージの読み込み
    if( result == true ) {
        for( int y=0; y<height; y++ ) {
            for( int x=0; x<width; x++ ) {
                Gdiplus::Color  srcColor;
                pBitmap->GetPixel(x, y, &srcColor);
 
                unsigned char r = srcColor.GetR();
                unsigned char g = srcColor.GetG();
                unsigned char b = srcColor.GetB();
                unsigned char a = srcColor.GetA();
 
                // ■ピクセルへの描画(この位置に任意に記述して下さい)
                // setPixel(x, y,  r, g, b, a);
            }
        }
    }
 
    delete pBitmap;
 
    //---- GDI+の解放
    Gdiplus::GdiplusShutdown(gdiplusToken);
 
    return result;
}

 

 
line645

いかがでしょうか?
わずかこれだけのプログラムでBMP形式だけでなく、PNG形式やJPEG形式まで読み込むことができます。
上記の方法ではパレットを持ったデータも全てフルカラー形式に展開されてしまいますのでご注意下さい。
アルファ成分もロード可能ですので、テクスチャのロードに活用出来ると思います。

ソースコード内で■記号をつけた部分にメモリ確保とデータ書き込みの処理を追加して使うことになります。
クラス実装に拡張したりして活用していただけたら幸いです。

 

この方法はWindows環境のみでしか利用できませんので、他の環境の場合はlibpng/libjpegといったオープンソースライブラリで
対応する必要があります。

【免責事項】

本サイトが提供している情報に関しては、安全性等、いかなる保証もされません。 株式会社ヘキサドライブは、これらの情報をあなたが利用することによって生ずるいかなる損害に対しても一切責任を負いません。

【著作権】

本サイトが提供しているコンテンツについては、特に断りのある場合を除き、株式会社ヘキサドライブが著作権を有します。