2

私は現在、OpenGL フレームワーク用の BMP スクリーンショット関数を作成しており、データを書き出すという奇妙な問題が発生しています。glReadPixelsBMP ヘッダーと一緒に取り込まれるデータはすべて正しいですが、ofstream.write操作によって無効な値がランダムに挿入されているようです。

画像 (ペイントで作成) の正しい BMP からの抜粋と、私の関数で作成されたものの抜粋が続き、正しくないバイトが強調表示されます。正しい行は常に最初の行になります。


行 0x08C

3B 0D 4A 3A 0A 48 38 08 45 36
3B 0D 4A 3A 0D 0A 48 38 08 45
            ^^

行 0x0DC (この時点で既に 1 つオフ)

3E 2F 07 3D 2E 0A 3F 31 0E 44
07 3E 2F 07 3D 2E 0D 0A 3F 31
                  ^^

行 0x0E68 (すぐ次の行で、2 つずれています)

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(Imgurがもちろん破損していると訴えたため、ペイントに再保存されました)

4

1 に答える 1

6

CRLF 変換std::ios::binaryを回避するフラグを追加して、ファイルをバイナリ モードで開く必要があります。Windows では、改行は 2 バイト 0x0D 0x0A (キャリッジ リターン + ラインフィード、または CR LF) として表されます。C および C++ ランタイムは、入力時にこれらを単純な改行に自動的に変換し、出力時に単純な改行を CRLF ペアに自動的に変換します。ファイルがデフォルトのテキストモードで開かれたとき。'\n'

これらの改行変換を抑制するには、ランタイムに変換しないように指示する必要があります。C++ の ではiostream、これはstd::ios::binaryフラグで行われます。C のFILE*ストリームでは、これは"b"モード フラグで行われます。たとえば"rb"、読み取りまたは"wb"書き込み用です。

于 2012-08-05T04:41:32.340 に答える