SDL単体ではBMP形式のみ対応しており、png,jpgやtiff等の別形式の画像の読み込みを行う場合SDL_imageを導入します。
SDL_imageで画像を読み込む場合は以下のようにIMG_Load関数を呼び出します。
[cpp]
if( GetFileAttributes( "test.png" ) != -1 )
{
SDL_Surface* image;
image = IMG_Load( "test.png" );
if( image == NULL )
{
sprintf( aszMessage, TEXT("画像の読み込みに失敗しました:%s"), SDL_GetError() );
OutputDebugString( aszMessage );
exit(1);
}
}
[/cpp]
IMG_Load関数が成功するとSDL_Surfaceオブジェクトへのポインタが返ってきます。このオブジェクト内に読み込んだファイルの画像データが保存されています。
このSDL_SurfaceオブジェクトをSDLのBlitSurface等に指定することで、画面に描画することができます。
少し話が変わりますが、各画像形式の読み込み処理を全て実装するのは手間なので、ライブラリ側に任せたいと考えてSDLに手を出した方もいらっしゃるかもしれません。
これは私がそうなのですが。GDI+を使用するという選択しもあったんですが、音関連の処理もライブラリに任せて本体のロジックのみ集中したい、そしていくつもライブラリをかき集めて管理するのが面倒ということでSDLを選択したわけなんですが、SDLには画像の読み込みだけしてもらってデータだけ欲しいと期待していました。
しかし、IMG_Loadを実行して帰ってくるのは隠蔽されたオブジェクトであるSDL_Surface。まぁ当然ですよね。 これを何とかしてデータだけ抽出したいと思い、SDL_Surfaceの構造を調査したところ割と簡単に見つけました。
結論からいうとSDL_Surface:Pixelsに画像データの先頭アドレスが格納されています。
これにwidth,heightの画像情報を合わせてビットマップを作成してやれば、異なる画像形式のファイルでも必要な画像データと画像情報が手に入ります。
そんなわけで、SDL_Surface::Pixelsの内容をSetPixel()関数を使用して画像に直接描画した画像が下図になります。
[cpp]
if( m_image != NULL )
{
int r, g, b;
for ( int i = 0; i < m_image->h; i++ ) {
for ( int j = 0; j < m_image->w; j++ ) {
// 1画素の R, G, B 成分は1バイトであること.画像データは隙間無くならんでいること.R, G, B の順に並んでいることを仮定している.
unsigned char* p = (unsigned char*)m_image->pixels;
int pixel_at = (i * (m_image->w) + j ) * m_image->format->BytesPerPixel;
r = p[pixel_at];
g = p[pixel_at + 1];
b = p[pixel_at + 2];
SetPixel( hdc, j, i, RGB( r, g, b ) );
}
}
}
[/cpp]
どこかでみた構図と画像ですが、これはpng画像を読み込んで画像データに直接操作できたことを証明できたことになるため、検証としては大きな成果です。
ただ、pngでは画像データの並びが"RGB,RGB,RGB,RGB..."と続くので何も問題はないのですが、bmpを読み込むと画像データの並びが"BGR,BGR,BGR,BGR..."と逆転しているので、読み込み後は拡張子に基づいて自前で調整処理を実装しないといけなさそうです。
描画処理についてはこちらのサイトのソースコードを参考に改変いたしました。
Linux で動く,SDL_image を用いて画像ファイルを読み込むプログラム例
12/09/13追記
SDLからRawデータを取得して画像処理を行い、再びSDL_Surfaceに押し込むことで画像処理のみ記述するという使い方も用途としてはお手軽にできるかもしれない。
0 件のコメント:
コメントを投稿