2016-06-26 1 views
0

私は、OpenGLからの画面領域をビットマップに保存しようとしています。私はFreeImageとSDL_Imageを使ってみましたが、両方とも赤と青のチャンネルを交換する必要があります。私は手動でCreateRGBSurfaceFromを呼び出した後、赤と青のチャンネルを入れ替えない限り、その色が行っているglReadPixelsが青と赤を入れ替えます

bool CaptureScreenRegionToFile (uint32_t In_X, uint32_t In_Y, uint32_t In_Width, uint32_t In_Height, std::string In_Filename) 
{ 
GLubyte* ImageData = (GLubyte*) malloc (In_Width * In_Height * 3); 
glPixelStorei (GL_PACK_ALIGNMENT, 1); 
glReadPixels (In_X, In_Y, In_Width, In_Height, GL_RGB, GL_UNSIGNED_BYTE, ImageData); 

if (CheckError() == false) 
    { 
    free (ImageData); 
    return false; 
    } 

SDL_Surface *Surface; 

// JTP TODO Known bug here. Red and blue are swapped, for some reason... 
Surface = SDL_CreateRGBSurfaceFrom (ImageData, In_Width, In_Height, 3 * 8, In_Width * 3, 0x00FF0000, 0x0000FF00, 0x000000FF, 0); 
SDL_SaveBMP (Surface, In_Filename.c_str()); 
SDL_FreeSurface (Surface); 
free (ImageData); 

return true; 
} 

:もちろん、それは私がこのサンプルコードを持っている ... glReadPixelsは問題がここにあることを疑うに私をもたらしますBMP上でスワップされます。 glReadPixelsはこれを行う必要がありますか?私はそれを正しく呼んでいますか? ここに何が問題なのですか?

+0

[おそらく関連する質問](http://stackoverflow.com/questions/5123387/loading-a-bmp-into-an-opengl-textures-switches-the-red-and-blue-colors-c-win )。 – DarkDust

答えて

8

glReadPixelsは意図したとおりに完全に動作します。あなたはGL_RGBとしてデータをリードバックするときは、メモリに

0 1 2 3 4 5 6 7 8 
+---------------------+ 
|R|G|B|R|G|B|R|G|B|...| 
+---------------------+ 

を以下のレイアウトを取得します今、あなたは、ピクセルあたり24ビットでSDL_CreateRGBSurfaceFromを使用しています。これにより、3バイトのすべてのグループが1つのピクセルとして解釈されます。しかし、これはrmask,gmask,bmask、 `amaskという大きな整数の1つとして扱われます。どのビットがどの画像チャネルに属するかを記述するパラメータ。例えば

は、あなたはビット16〜23を意味し、赤いマスクとして0x00FF0000を使用(ゼロから始まる、最下位ビットから数えて)読んで含まれています:

3  2|  1|  0|  0 bit 
1  4|  6|  8|  0 number 
+-----------------------------------+ 
|00000000|11111111|00000000|00000000| 
+-----------------------------------+ 
    byte 3 byte 2 byte 1 byte 0 

はしかし、あなたが最も可能性が高いのですlittle endianマシンでは、最下位バイトが最下位メモリ位置に格納されます。そう、それはあなたがからピクセルデータを読み込む形式と一致しない

0 1 2 byte number 
+--------------+ 
+ 00 | 00 | FF | 
+--------------+ 
    R G  B 

:それはあなたのrmaskとして保存されることを意味します。また、あなたのコードは移植可能ではないことに注意してください。ビッグエンディアンアーキテクチャでは、意図的な結果が得られます。 1

あなたには、いくつかのエンディアンdependend #ifdefsを追加せずに、できるだけprotableこのコードを書きたい場合は

UPDATEは、あなたはピクセルあたり3バイトのフォーマットを使用することはできません。ただし、GL_UNSIGNED_INT_8_8_8_8またはGL_UNSIGNED_INT_8_8_8_8_REVを使用できます。各ピクセルは32ビット整数として扱われ、マシンのネイティブエンディアンを使用して格納されます。 _REVは、フォーマットの最初のコンポーネント(たとえば、GL_RGBAに赤)を最下位バイトに格納し、_REVバリアントを最上位バイトに格納します。いずれの場合も、適切なマスクを設定することができ、エンディアンとは独立して動作します。

+0

Argh!私はそれほど疑っていましたが、SDLが私のためにエンディアンの世話をすることを期待しました...それで、私はすべてのパラメータ(ドキュメンテーションによれば、内部的にマスクを扱う)でも0で試してみましたが、まあ.... ....ありがとう:)どのようにこのマシンに依存しないように簡単に任意のアイデアですか? –

+0

@ JoaoPincho:私はそれに対処しようと私の答えを更新しました。 – derhass

関連する問題