myesilbagli
myesilbagli

Reputation: 1

Wrong pixel data of bitmap file

I am trying to code a program that works to downscale a bitmap file. I can read successfully the size of the file and height and width values but I have to get RGB values of pixels and assign them into pixels array. But I get irrelevant values and I couldn't understand why I'm not getting the exact values of pixels. Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include "bitmap.h"

int main()
{
    FILE *bmp_input;

    bmp_input=fopen("itu.bmp","rb");

    BITMAPFILEHEADER fh;
    BITMAPINFOHEADER fi;

    fread(&fh, sizeof(fh),1,bmp_input);
    fread(&fi, sizeof(fi),1,bmp_input);

    int *pixels;
    pixels= malloc(sizeof(fh.bfSize-54));

    fread(pixels, sizeof(pixels),1,bmp_input);

    fclose(bmp_input);


    printf("bfSize: %d\n", fh.bfSize);
    printf("Width: %d\n", fi.biWidth);
    printf("Height: %d\n",fi.biHeight);
    printf("First pixel data: %d %d %d",*pixels,*pixels+1,*pixels+2);
    return 0;
}

And the values that i get are here in the picture:

values

Header File:bitmap.h

#include <stdint.h>

typedef struct
{
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} __attribute__((__packed__)) BITMAPFILEHEADER;

typedef struct
{
    uint32_t biSize;
    int32_t  biWidth;
    int32_t  biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t  biXPelsPerMeter;
    int32_t  biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
} __attribute__((__packed__)) BITMAPINFOHEADER;

Thanks for your help.

Upvotes: 0

Views: 189

Answers (1)

Paul Hankin
Paul Hankin

Reputation: 58251

You need to read the data into a byte buffer rather than an int buffer. The colors in a BMP file are stored using 1, 2, 4, 8, 16, 24 or 32 bits per pixel, so you need to extract the red, green and blue components more carefully than you're doing. It looks like your particular bmp uses 24 bits per pixel (because size is roughly three times the width and height). Thus you can read the components as single bytes, with each pixel three bytes long. For bytes, I use uint8_t from stdint.h although unsigned char could be used instead.

The components in 24bpp are stored in the order blue, green, red.

Here's some example code that prints out the colours of every pixel in the image, assuming it's 24 bpp. It would be better to check the bpp field of bitmap header to handle the pixel access correctly. Sorry, I don't know what the exact name of the field is in your header, because you don't provide it. More error checking would also be desirable. The code is untested, because I don't have access to your header file.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "bitmap.h"
 
int main(){
    FILE *bmp_input;

    bmp_input=fopen("itu.bmp","rb");

    BITMAPFILEHEADER fh;
    BITMAPINFOHEADER fi;

    fread(&fh, sizeof(fh),1,bmp_input);
    fread(&fi, sizeof(fi),1,bmp_input);

    size_t pix_size = fh.bfSize-54;
    uint8_t *pixels = malloc(pix_size);
    if (!pixels) return 2;
    fclose(bmp_input);

    if (fread(pixels, 1, pix_size, bmp_input) != pix_size) return 1;
    int row_width = (3 * fe.biWidth + 3) & ~3; // round up to multiple of 4
    for (int j = 0; j < fi.biHeight; j++) {
        for (int i = 0; i < fi.biWidth; i++) {
            int index = row_width * j + 3 * i;
            printf("pix[%d,%d]=RGB(%02X, %02X, %02X)\n", i, j, pixels[index+2], pixels[index+1], pixels[index]);
        }
    }
    free(pixels);
    return 0;
}

Note that from a software-engineering point of view, reading binary file formats by reading in data directly into a struct invites security and portability problems (for example, you probably implicitly depend on integers being 32 bits, and little-endian, and structs being packed a certain way). But I guess that this is just a learning exercise.

Upvotes: 1

Related Questions