jinglei
jinglei

Reputation: 3363

c++ - Convert an array of float to an array of unsigned char and write to file

I'm writing a PPM file writer. The file format description can be found here. I want to write the file in binary format, which is the P6 type.

The P6 binary format of the same image represents each color component of each pixel with one byte (thus three bytes per pixel) in the order red, green, then blue. The file is smaller, but the color information is difficult to read by humans.

My image buffer is originally an array of Vec3f, which is inside a float[3] so I can manage to convert the Vec3f array to float array.

What I failed to do is convert the float array to an unsigned char array so that I can write to a .ppm file.

Here's my code:

void writePPM(char *fn, Vec3f *buffer, int w, int h) {
        FILE *fp = fopen(fn, "wb");
        unsigned char *char_buffer = new unsigned char[w*h*3];
        for (int i = 0; i < w*h; i+=3) {
            char_buffer[i] = (unsigned char)buffer[i].x();
            char_buffer[i+1] = (unsigned char)buffer[i].y();
            char_buffer[i+2] = (unsigned char)buffer[i].z();
        }
        fprintf(fp, "P6\n%d %d\n\255\n", w, h);
        fwrite(char_buffer, sizeof(unsigned char), w*h*3, fp);
        fclose(fp);
    }

buffer[i].x(), buffer[i].y(), buffer[i].z() range from [0,255]

The generated image is a completely black one, but width and height matches my image buffer, so I thought the fwrite part is wrong. How can I fix it?

I'm also confused how float be converted to char? char is 8-bit and float is bigger so there must be some data loss?

Upvotes: 1

Views: 557

Answers (2)

JeremyP
JeremyP

Reputation: 86701

This is a bit of a guess but I would expect a pixel specified as three floats would have each float in the range [0, 1] with 0 being black and 1 being white. Whereas I would expect your char based pixel would expect each element to be in the range [0, 255] with 0 being black and 255 being white.

The cast (char) someFloat converts a float to an char by truncating the fractional part, so all your pixels will end up black - or very nearly black.

Try multiplying the float by 255 before the cast (and make sure the char is unsigned) i.e. (unsigned char)(float * 255)

Upvotes: 0

Junhee Shin
Junhee Shin

Reputation: 758

buffer index check.

for (int i = 0; i < w*h; i+=3) {
    char_buffer[i] = (unsigned char)buffer[i/3].x();
    char_buffer[i+1] = (unsigned char)buffer[i/3].y();
    char_buffer[i+2] = (unsigned char)buffer[i/3].z();
}

Upvotes: 1

Related Questions