s.gang s.gang - 1 year ago 75
C Question

24bpp to 8bpp conversion C with raw image data

I am currently trying to convert raw binary image data (512 x 512 24bpp) to a 512 x 512 8bpp image by using 3bits for the R channel, 3 for the G channel, and 2 for the B channel. However when using my code my picture comes out grey scale? Can anyone tell me what I'm doing wrong?

/*24 bit per pixel - 8 bit per pixel transformation*/

unsigned char buf[512][512][3];
unsigned char in[512][512][3];
unsigned char out[512][512][3];
unsigned char pix[512][512];

int main(){

FILE *fp, *output;
int i, j;

/*open file*/
if((fp = fopen("LennaRGB512.data", "rb")) == NULL){
printf("error opening file\n");
}

/*read file into buffer*/
for (i = 0; i < 512; i++) {
for (j = 0; j < 512; j++) {
buf[i][j][0] = fgetc(fp); /*r*/
buf[i][j][1] = fgetc(fp); /*g*/
buf[i][j][2] = fgetc(fp); /*b*/

in[i][j][0] = buf[i][j][0];
in[i][j][1] = buf[i][j][1];
in[i][j][2] = buf[i][j][2];
}
}

fclose(fp);

output = fopen("lenna_8bpp.data", "wb");
for(i = 0; i < 512; i++){
char pix[512][512];
for(j = 0; j < 512; j++){
out[i][j][0] = (in[i][j][0] * 8) / 256;
out[i][j][1] = (in[i][j][1] * 8) / 256;
out[i][j][2] = (in[i][j][2] * 4) / 256;
pix[i][j] = (out[i][j][0] << 5) | (out[i][j][1] << 2) | out[i][j][2];
fputc(pix[i][j], output);
}
}



fclose(output);
return 0;
}


There are tons of questions on doing this with .bmp files and others but I can't find any help with manipulating the raw image data pixel by pixel.

cxw cxw
Answer Source

I agree with the commenters. I think the grayscale is very likely an artifact of your viewer rather than your conversion. However, your conversion can also be improved. Try the following output loop:

unsigned char pix;   /* don't need 512*512 of them. */
unsigned char r, g, b;
for(row = 0; row < 512; row++){
    for(col = 0; col < 512; col++){
        r = in[row][col][0] >> 5;   /* keep 3 bits */
        g = in[row][col][1] >> 5;
        b = in[row][col][2] >> 6;   /* keep 2 bits */
        pix = (r << 5) | (g << 2) | b;
        fputc(pix, output);
    }
}

You are only processing one pixel at a time, so you only need one pix value.

For each of the r, g, and b, color components (remember to specify unsigned char throughout), use >> (right shift) to drop all the bits except the most significant. This is simpler and more clear than the *8/256 sequence. Also, I believe *8/256 only works because arithmetic is promoted to int — if it were done in chars, the *8 could cause overflow and lose data.

Edit The problem is indeed in the display. I have posted a palette and instructions on my blog since the full contents are too long for the space here. Yes, I know link-only answers are bad :( . I just saved it into the Archive in case of link rot.

You do need to open the image as Indexed, and then assign the colormap of the image.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download