我目前正在为 OpenGL 框架编写 BMP 屏幕截图功能,并且在写入数据时遇到了一个奇怪的问题。与 BMP 标头一起引入的数据glReadPixels
都是正确的,但似乎该ofstream.write
操作是随机插入无效值。
以下是图像的正确 BMP(由 Paint 创建)和我的函数制作的 BMP 的摘录,突出显示了不正确的字节。正确的行将永远是第一行。
行 0x08C
3B 0D 4A 3A 0A 48 38 08 45 36
3B 0D 4A 3A 0D 0A 48 38 08 45
^^
第 0x0DC 行(此时已减一)
3E 2F 07 3D 2E 0A 3F 31 0E 44
07 3E 2F 07 3D 2E 0D 0A 3F 31
^^
第 0x0E68 行(非常下一行,并关闭两个)
35 13 48 3A 10 44 36 0A 3F 31
0E 44 35 13 48 3A 10 44 36 0D
^^
所以似乎有一种模式,其中无效值始终是0x0D
并且它被插入到前面0x0A
。我不知道为什么会发生这种情况,因为我已经确认来自的标题和数据glReadPixels
都是正确的。该方法的代码如下。
bool captureScreen( const char* name, unsigned originX, unsigned originY, unsigned width, unsigned height )
{
//...
GLubyte* imageData = new GLubyte[ width * height * 3 ];
glReadPixels( originX, originY, width, height, GL_BGR, GL_UNSIGNED_BYTE, imageData );
//...
captureAsBMP( imageData, width, height, path.c_str( ) );
//...
}
bool captureAsBMP( GLubyte* data, GLuint width, GLuint height, const char* path )
{
std::ofstream stream( path, std::ios_base::out );
if( !stream.is_open( ) )
return false;
unsigned char BMPHeader[ 14 ] = { /* cut for brevity */ };
unsigned char DIBHeader[ 40 ] = { /* cut for brevity */ };
unsigned char padding[ 4 ] = { 0x00, 0x00, 0x00, 0x00 };
unsigned int paddingLength = 4 - (( width * 3 ) % 4);
paddingLength = ( paddingLength == 4 ? 0 : paddingLength );
long fileSize = ( width * height * 3 ) + ( paddingLength * height ) + 54;
long dataSize = fileSize - 54;
memcpy( &BMPHeader[ 2 ], &fileSize, sizeof( long ) );
memcpy( &DIBHeader[ 4 ], &width, sizeof( unsigned int ) );
memcpy( &DIBHeader[ 8 ], &height, sizeof( unsigned int ) );
memcpy( &DIBHeader[ 20 ], &dataSize, sizeof( long ) );
stream.write( reinterpret_cast< char* >( BMPHeader ), 14 );
stream.write( reinterpret_cast< char* >( DIBHeader ), 40 );
unsigned pos = 0;
// Write out one row at a time
for( int i = 0; i < height; i++ )
{
stream.write( reinterpret_cast< char* >( &data[ pos ] ), ( width * 3 ) );
// Is there padding that needs to be added?
if( paddingLength != 0 )
stream.write( reinterpret_cast< char* >( padding ), paddingLength );
// Update where we are in data
pos += width * 3;
}
stream.close( );
return true;
}
另外值得注意的是,有问题的图像是 800x600,因此此错误发生在行的第一次流写入期间,在填充和pos
递增之前。
最后,它应该如何出现:http: //imgur.com/oziid
以及它是如何工作的:http: //imgur.com/SrXgA(重新保存在 Paint 中,因为 Imgur 抱怨它当然被损坏了)