user3048457
user3048457

Reputation: 1

Read binary 16bit streamfile and write to 16bit PGM (C++)

this is my first Post as I came along with using the search function so far. But now I wasted a whole day on the following issue:

I recorded a 12bit (written as 16bit) grayscale video and wrote it directly into a binary stream-file (no headers or such).

Now the task is to read the file and output every frame as a 16bit pgm.

The following snipped illustrates what i tried. The output is a valid pgm, but whith "white noise on it".

    ...
    imageBufferShort = new short[imageWidth*imageHeight* sizeof(short)];
    ...
    streamFileHandle.read(reinterpret_cast<char*>(imageBufferShort),2*imageWidth*imageHeight); //double amount because 8bit chars!
    // As .read only takes chars, I thought, that I just read the double amount of char-bytes and when it is interpreted as short (=16bit) everything is ok?!?

    ...now the pgm output:

    std::ofstream f_hnd(fileName,std::ios_base::out |std::ios_base::binary |std::ios_base::trunc);
    // write simple header
    f_hnd.write("P5\n",3);
    f_hnd << imageWidth << " " << imageHeight << "\n4095\n";  //4095 should tell the pgm to use 2 bytes for each pixel

    f_hnd.write(reinterpret_cast<char*>(imageBufferShort),2*imageWidth*imageHeight);
    f_hnd.close();

Again, the file is produced and viewable but contains rubbish. Is the initial guess ok? read 2 "chars" and handle them as one "short"? I also trieb a whitespace after every line but this changes nothing, so I decided to post this shorter code.

Thanks for any help!

Upvotes: 0

Views: 1445

Answers (2)

user3048457
user3048457

Reputation: 1

Problem Solved. Thank you all very much. The Endianess was indeed the Problem. The solution is given below:

    f_hnd << "P5" << " " << imDimensions.GetWidth() << " " << imDimensions.GetHeight() << " " << "4095\n";

    // convert imageBufferShort to Big-Endian format
    unsigned short imageBufferShortBigEndian[imDimensions.GetWidth()*imDimensions.GetHeight()];

    for (int k=0 ; k<imDimensions.GetWidth()*imDimensions.GetHeight() ; k++)
    {
        imageBufferShortBigEndian[k] = ( (imageBufferShort[k] << 8) | (imageBufferShort[k] >> 8) );
    }

    f_hnd.write(reinterpret_cast<char*>(imageBufferShortBigEndian),2*imDimensions.GetWidth()*imDimensions.GetHeight());
    f_hnd.close();

imageBufferShort has also to an unsigned short-array. If signed types are used, the bitshift-conversion gets slightly more difficult.

Thanks again!

Upvotes: 0

Domi
Domi

Reputation: 24528

As @Domi and @JoeZ pointed out: Your endianness is probably screwed up. Meaning, the order of your bytes is wrong.

To fix your problem, you will have to iterate over every pixel and swap it's bytes before writing it back to file.

Upvotes: 1

Related Questions