BMP File C implementation

3

I am trying to implement creating an image file in C. The format of the image I want to be is RGB565. I have followed these two websites 1 2 to try and get a viewable image but I do not seem to get it working. Is the problem in the "fwrite" function because of the little endian thing?

For testing purposes I want an image that is 16*4 large and all pixels are of the same color. (The code is a mess as it is just for testing purposes before implementing it in a bigger project.

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

int main() {
    uint16_t myData[64];
    for(int i = 0; i<64; i++)
    {
        myData[i] = 0x241B; //Random Color
    }

    typedef struct                       /**** BMP file header structure ****/
    {
    uint16_t bfType;           /* Magic number for file */
    uint32_t   bfSize;           /* Size of file */
    uint16_t bfReserved1;      /* Reserved */
    uint16_t bfReserved2;      /* ... */
    uint32_t   bfOffBits;        /* Offset to bitmap data */
    } BITMAPFILEHEADER;

    typedef struct                       /**** BMP file info structure ****/
    {
    uint32_t   biSize;           /* Size of info header */
    uint32_t            biWidth;          /* Width of image */
    uint32_t            biHeight;         /* Height of image */
    uint16_t biPlanes;         /* Number of color planes */
    uint16_t biBitCount;       /* Number of bits per pixel */
    uint32_t   biCompression;    /* Type of compression to use */
    uint32_t   biSizeImage;      /* Size of image data */
    uint32_t            biXPelsPerMeter;  /* X pixels per meter */
    uint32_t            biYPelsPerMeter;  /* Y pixels per meter */
    uint32_t   biClrUsed;        /* Number of colors used */
    uint32_t   biClrImportant;   /* Number of important colors */
    } BITMAPINFOHEADER;

BITMAPFILEHEADER myFileHeader = {0x4D42, 198, 0, 0, 70};

BITMAPINFOHEADER myInfoHeader = {40, 16, 4, 1, 16, 0, 0, 1000, 1000, 0, 0};

uint32_t RGB565ColorTable[] = {0x7E00000, 0xF8000000, 0x001F0000, 0}; 



   FILE *fptr;    fptr = fopen("testImage.bmp","w+");

   if(fptr == NULL)    {
      printf("Error!");   
      exit(1);                 }

    fwrite(&myFileHeader, sizeof(BITMAPFILEHEADER), 1, fptr); 
    fwrite(&myInfoHeader, sizeof(BITMAPINFOHEADER), 1, fptr); 
    fwrite(&RGB565ColorTable, sizeof(RGB565ColorTable), 1, fptr); 
    fwrite(&myData, sizeof(myData), 1, fptr); 
    fclose(fptr);

    return 0; }

Hex Output (after adding attribute((packed)) to structs ): enter image description here

c
bmp
asked on Stack Overflow Apr 30, 2018 by Cezar Chirila • edited Apr 30, 2018 by Cezar Chirila

3 Answers

1

You need to pack the file header struct so that the compiler won't pad the entries. You can use __attribute__((packed)) with gcc when defining the structs to accomplish this.

answered on Stack Overflow Apr 30, 2018 by cleblanc
1

I did clean up the code. And it looks like it is working:

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

typedef struct        /**** BMP file header structure ****/
{
    uint16_t bfType;           /* Magic number for file */
    uint32_t bfSize;           /* Size of file */
    uint16_t bfReserved1;      /* Reserved */
    uint16_t bfReserved2;      /* ... */
    uint32_t bfOffBits;        /* Offset to bitmap data */
} __attribute__((packed)) BITMAPFILEHEADER;

typedef struct                       /**** BMP file info structure ****/
{
    uint32_t biSize;           /* Size of info header */
    uint32_t biWidth;          /* Width of image */
    uint32_t biHeight;         /* Height of image */
    uint16_t biPlanes;         /* Number of color planes */
    uint16_t biBitCount;       /* Number of bits per pixel */
    uint32_t biCompression;    /* Type of compression to use */
    uint32_t biSizeImage;      /* Size of image data */
    uint32_t biXPelsPerMeter;  /* X pixels per meter */
    uint32_t biYPelsPerMeter;  /* Y pixels per meter */
    uint32_t biClrUsed;        /* Number of colors used */
    uint32_t biClrImportant;   /* Number of important colors */
} __attribute__((packed)) BITMAPINFOHEADER;

int main()
{
    FILE *fptr;

    BITMAPFILEHEADER myFileHeader = {
        .bfType = 0x4D42,
        .bfSize = 198,
        .bfOffBits = 70
    };

    BITMAPINFOHEADER myInfoHeader = {
        .biSize = 40,
        .biWidth = 16,
        .biHeight = 4,
        .biPlanes = 1,
        .biBitCount = 16,
        .biCompression = 0,
        .biSizeImage = 0,
        .biXPelsPerMeter = 1000,
        .biYPelsPerMeter = 1000,
        .biClrUsed = 0,
        .biClrImportant = 0
    };

    uint32_t RGB565ColorTable[] = {
        0x7E00000, 0xF8000000, 0x001F0000, 0
    };

    uint16_t myData[64];

    for(int i = 0; i<64; i++)
    {
        myData[i] = 0x241B; //Random Color
    }

    fptr = fopen("testImage.bmp","w+");

    if(fptr == NULL) {
        printf("Error!");
        exit(1);
    }

    fwrite(&myFileHeader, sizeof(myFileHeader), 1, fptr);
    fwrite(&myInfoHeader, sizeof(myInfoHeader), 1, fptr);
    fwrite(&RGB565ColorTable, sizeof(RGB565ColorTable), 1, fptr);
    fwrite(&myData, sizeof(myData), 1, fptr);
    fclose(fptr);

    return 0;
}

I do have the following output :

hexdump -C testImage.bmp
00000000  42 4d c6 00 00 00 00 00  00 00 46 00 00 00 28 00  |BM........F...(.|
00000010  00 00 10 00 00 00 04 00  00 00 01 00 10 00 00 00  |................|
00000020  00 00 00 00 00 00 e8 03  00 00 e8 03 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  e0 07 00 00 00 f8 00 00  |................|
00000040  1f 00 00 00 00 00 1b 24  1b 24 1b 24 1b 24 1b 24  |.......$.$.$.$.$|
00000050  1b 24 1b 24 1b 24 1b 24  1b 24 1b 24 1b 24 1b 24  |.$.$.$.$.$.$.$.$|
*
000000c0  1b 24 1b 24 1b 24                                 |.$.$.$|
answered on Stack Overflow Apr 30, 2018 by benjarobin
1

With MSVC you can enclose a struct with

#pragma pack(push, 1)
// struct
#pragma pack(pop)

to make it packed. I have found it is only needed for BITMAPFILEHEADER on a 32-bit compilation.

answered on Stack Overflow Apr 30, 2018 by Weather Vane

User contributions licensed under CC BY-SA 3.0