Reading and Plotting BMP Image In C from Scratch

Viewed 91

I am developing my own OS, with GNU-EFI, I am written a small BMP Image loader program.

I can Successfully read its headers and data ( not sure ) when I plot that on my Screen that is only showing blue color on pixels.

// Blue Pixels are Plotted BMP Image This is the Image! of My Output

How can I load this with Colours?

PlotPixel(x,y,color) Color takes Value as 0xFFFFFFFF;

Following is my bmp loader:

BMP.h

// bmp.h

#define WIN_BITMAP_SIGNATURE 0x4D42           // BM [ASCII]
#define BMP_HEADER_SIZE 54
#define DIB_HEADER_SIZE 40

#pragma pack(push, 1)

typedef struct
{
    
    uint16_t bfType;            //  The characters "BM"                 - 2 Bytes
    uint32_t bfSize;            //  The size of the file in bytes       - 4 Bytes
    uint16_t bfReserved1;       //  Unused - must be zero               - 2 Bytes
    uint16_t bfReserved2;       //  Unused - must be zero               - 2 Bytes
    
    uint32_t bfOffBits;         //  Offset to start of Pixel Data       - 4 Bytes

    uint32_t biSize;        //  DIB Header Size                         - 4 Bytes
    int32_t biWidth;           //  Width                               - 4 Bytes
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPexelsPerMeter;
    int32_t biYPexelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;

} BITMAP_HEADER;


typedef struct
{
    
    BITMAP_HEADER* header;
    uint8_t* data;

} BITMAP_IMG;


typedef struct
{
    uint32_t    red_mask;
    uint32_t    green_mask;
    uint32_t    blue_mask;
    uint32_t    alpha_mask;
    uint32_t    color_space_type;
    uint32_t    unused[16];
} BMPColorHeader;


#pragma pack(pop)


unsigned long createRGBA(int r, int g, int b, int a);

unsigned long createRGB(int r, int g, int b);

BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable);

BMP.c

// bmp.c

#include "bmp.h"

unsigned long createRGB(int r, int g, int b)
{   
    return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff);
}

unsigned long createRGBA(int r, int g, int b, int a)
{   
    return ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8)
           + (a & 0xff);
}

BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)
{
    EFI_FILE* BMPImage = LoadFile(Directory, Path, ImageHandle, SystemTable);

    if(BMPImage == NULL) return NULL;

    BITMAP_HEADER* BMPImageHeader;

    SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_HEADER), (void**)&BMPImageHeader);
    
    UINTN size = sizeof(BITMAP_HEADER);

    BMPImage->Read(BMPImage, &size, BMPImageHeader);

    // Verify Signature
    if(BMPImageHeader->bfType != WIN_BITMAP_SIGNATURE)
    {
        // Signature not Matched
        Print(L"Signature Not Matched!");
        Print(L"BMP Type [ Signature ] : ", BMPImageHeader->bfType);
        return NULL;
    }
    else
    {
        Print(L"Signature Found");
    }

    if(BMPImageHeader->biBitCount == 32)
    {
        Print(L"BMP 32 Bit");

        BMPColorHeader* BmpColor;
        
        SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BMPColorHeader), (void**)&BmpColor);
    
        UINTN size = sizeof(BITMAP_HEADER);

        BMPImage->Read(BMPImage, &size, BmpColor);

        // Check Color Header

        if(0x00ff0000 != BmpColor->red_mask || 0x000000ff != BmpColor->blue_mask || 0x0000ff00 != BmpColor->green_mask)
        {
            Print(L"Unexpected Color Format");
        }

        if(0x73524742 != BmpColor->color_space_type)
        {
            Print(L"Unexcepted Color Space Type : %d", BmpColor->color_space_type);
        }

    }
    else
    {
        Print(L"BMP Not 32 Bit : %d", BMPImageHeader->biBitCount);
    }

    uint8_t* BMPData;
    {
        BMPImage->SetPosition(BMPImage, sizeof(BITMAP_HEADER));
        SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&BMPData);
        BMPImage->Read(BMPImage, &size, BMPData);
    }

    BITMAP_IMG* finishedImage;

    SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_IMG), (void**)&finishedImage);
    finishedImage->header = BMPImageHeader;
    finishedImage->data = BMPData;


    int offset = 0;
    int channels = finishedImage->header->biBitCount / 8;

    for (int i = 0; i < finishedImage->header->biHeight; i++)
    {
        for (int j = 0; j < finishedImage->header->biWidth; j++)
        {
            //// I thinks following are wrong

            // Red
            int red = finishedImage->data[offset] & 0xFF;
            int green = finishedImage->data[offset+1] & 0xFF;
            int blue = finishedImage->data[offset+2] & 0xFF;
            int alpha = 0x00;

            // I thinks CreateRGBA can be also wrong
            int hex_calculated = createRGBA(red, green, blue, alpha);

            // This function is surely right ; It takes color value as 0xFFFFFFFF
            PlotPixel(120+i, 120+j, hex_calculated);
            
            
            offset += 3;
        }
        
    }

    return finishedImage;
}
0 Answers
Related