2012年01月05日

GDI+でBMP/PNG/JPEGの読み込みを簡単に

こんにちは、イワサキです !!
新年明けましておめでとうございます。
今年も技術デモをなるべく多く公開していきたいと思います。よろしくお願いします! ぴかぴか(新しい)

さて、2012年に入って学生の皆さんも就職活動本番に突入してく時期になっていますが
今回はゲーム就職作品に役立てられそうなプログラムをひとつ紹介してみたいと思います。


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で扱うことができる

2010-10-14-0.png


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

【ヘッダ部】

//---------------------------------------------------------------------------
// 最低限必要なプラットフォームが WindowsXPであることを指定します。
// ※ GDI+ APIを利用するため、WindowsXP以降が必要になります。
//---------------------------------------------------------------------------
#define WINVER 0x0501 // 0x0501 = WindowsXP
#define _WIN32_WINNT 0x0501

#include <windows.h>
//---- GDI+ヘッダ関連
#include <gdiplus.h>
#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;
}


2010-10-14-0.png


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

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

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




ヘキサドライブでは先月12月から新卒採用スタートしています。
教育には師弟制度があり、先輩と共に知識や能力を高めあっていく環境づくりをしています晴れ
一緒にゲーム作品を作っていきませんか?採用情報詳細は下記情報を御覧ください。

◎ 株式会社ヘキサドライブ 採用情報 ◎
http://hexadrive.jp/index.php?id=5

学生の皆さんに会えるのを楽しみにしていますぴかぴか(新しい)是非ご応募くださいね。 手(パー)


posted by 管理人 at 23:55 | プログラミング