Bitmap Image Format

 

 

The BMP file format has been created by Microsoft and IBM. The BMP files are the way, Windows stores bit mapped images. The BMP image data is bit packed but every line must end on a dword boundary - if that’s not the case, it must be padded with zeroes. BMP files are stored bottom-up, that means that the first scan line is the bottom line.


BMP Format Contents

The following table contains a description of the contents of the BMP file. For every field, the file offset, the length and the contents will be given. For a more detailed discussion, see the following chapters.

Offset

Field Name

Size

Description

0000h

Identifier

2 chars

The characters identifying the bitmap. The following entries are possible:

‘BM’ - Windows 3.1x, 95, NT, …

‘BA’ - OS/2 Bitmap Array

‘CI’ - OS/2 Color Icon

‘CP’ - OS/2 Color Pointer

‘IC’ - OS/2 Icon

‘PT’ - OS/2 Pointer

0002h

File Size

1 dword

Complete file size in bytes.

0006h

Reserved

1 dword

Reserved for later use.

000Ah

Bitmap Data Offset

1 dword

Offset from beginning of file to the beginning of the bitmap data.

000Eh

Bitmap Header Size

1 dword

Length of the Bitmap Info Header used to describe the bitmap colors, compression, … The following sizes are possible:

 

28h - Windows 3.1x, 95, NT, …

0Ch - OS/2 1.x

F0h - OS/2 2.x

0012h

Width

1 dword

Horizontal width of bitmap in pixels.

0016h

Height

1 dword

Vertical height of bitmap in pixels.

001Ah

Planes

1 word

Number of planes in this bitmap.

001Ch

Bits Per Pixel

1 word

Bits per pixel used to store palette entry information. This also identifies in an indirect way the number of possible colors. Possible values are:

1 - Monochrome bitmap

4 - 16 color bitmap

8 - 256 color bitmap

16 - 16bit (high color) bitmap

24 - 24bit (true color) bitmap

32 - 32bit (true color) bitmap

001Eh

Compression

1 dword

Compression specifications. The following values are possible:

0 - none (Also identified by BI_RGB)

1 - RLE 8-bit / pixel (Also identified by BI_RLE4)

2 - RLE 4-bit / pixel (Also identified by BI_RLE8)

3 - Bitfields  (Also identified by BI_BITFIELDS)

0022h

Bitmap Data Size

1 dword

Size of the bitmap data in bytes. This number must be rounded to the next 4 byte boundary.

0026h

HResolution

1 dword

Horizontal resolution expressed in pixel per meter.

002Ah

VResolution

1 dword

Vertical resolution expressed in pixels per meter.

002Eh

Colors

1 dword

Number of colors used by this bitmap. For a 8-bit / pixel bitmap this will be 100h or 256.

0032h

Important Colors

1 dword

Number of important colors. This number will be equal to the number of colors when every color is important.

0036h

Palette

N * 4 byte

The palette specification. For every entry in the palette four bytes are used to describe the RGB values of the color in the following way:

1 byte for blue component

1 byte for green component

1 byte for red component

1 byte filler which is set to 0 (zero)

0436h

Bitmap Data

x bytes

Depending on the compression specifications, this field contains all the bitmap data bytes which represent indices in the color palette.

The following sizes were used in the specification above:

Size

# bytes

Sign

char

1

signed

word

2

unsigned

dword

4

unsigned

 

Palette content is used for lower than 24-bit images. In 24-bit image this content does not make any sense. Just ignore it. That means in 24-bit BMP image data starts from offset 0036h.


 

Sample C Source Code

 

Nowadays smaller than 24-bit BMP formats are used rarely. So here I wrote only 24-bit uncompressed BMP code. Enjoy it. Functions use dynamically allocated matrices.

 

/*

 *   Give a reference to this site if you like to use this code.

 *
 *                               Written by Chasan Chouse, 2004

 */

 

// Bitmap Structure
typedef struct {

    long    FileSz;
    long    Reserved;
    long    BmpOffset;
    long    BmpSzHead;
    long    X;
    long    Y;
    unsigned int    Planes;
    unsigned int    BitsPPixel;
    long    Comp; // compression
    long    BmpSzData;
    long    HRes;
    long    VRes;
    long    Colors;
    long    ImpColors;
} BMPHEADER;

 

#define UCHAR unsigned char
#define USHORT unsigned short
#define ULONG unsigned long

 

/*

 *   24-bit full color bitmap files

 *   Read Header and fill the structure.
 */

bool BMP_24_Get_Header(char FlName[], BMPHEADER *BmpHdr)
{
    char ch1, ch2;
    unsigned short  s1, s2;
    FILE *f;

    f =fopen(FlName,"rb");
    ch1 = fgetc(f);
    ch2 = fgetc(f);
    if( (ch1 != 'B') && (ch2 != 'M') )  //  Supports only Windows 3.1x, 95, NT  BMP format
        return (false);

    fread(&BmpHdr->FileSz, 41, f);

    fread(&BmpHdr->Reserved, 41, f);
    fread(&BmpHdr->BmpOffset, 41, f);

    fread(&BmpHdr->BmpSzHead, 41, f);

    fread(&BmpHdr->X, 41, f);
    printf("\nWidth         : %ld", BmpHdr->X);

    fread(&BmpHdr->Y, 41, f);
    printf("\nHeigth        : %ld", BmpHdr->Y);

    s1 = fgetc(f);
    s2 = fgetc(f);
    s2 <<=8;
    BmpHdr->Planes = 0;
    BmpHdr->Planes |= s1;
    BmpHdr->Planes |= s2;

    s1 = fgetc(f);
    s2 = fgetc(f);
    s2 <<=8;
    BmpHdr->BitsPPixel = 0;
    BmpHdr->BitsPPixel |= s1;
    BmpHdr->BitsPPixel |= s2;

    fread(&BmpHdr->Comp, 41, f);

    fread(&BmpHdr->BmpSzData, 41, f);

    fread(&BmpHdr->HRes, 41, f);

    fread(&BmpHdr->VRes, 41, f);

    fread(&BmpHdr->Colors, 41, f);

    fread(&BmpHdr->ImpColors, 41, f);

    fclose(f);
    return (true);
}
 

/* 
 *  - Read actual bitmap data. Note that bitmap lines are organized

 *    reversely. List line is placed in the first scan line.

 *  - Look at Dynamic Memory Allocation for double pointer(**RRed) Matrices.
 */
bool
 BMP_24_Get_Data(char FlName[],

                    BMPHEADER *BmpHdr,

                    UCHAR **RRed, 

                    UCHAR **GGreen,

                    UCHAR **BBlue)
{
    long i, j;
    unsigned long BmpPix, k;
    FILE *f;

    f=fopen(FlName,"rb");

    fseek(f,BmpHdr->BmpOffset, SEEK_SET);
    for(i=(long)BmpHdr->Y-1;i>=0;i--)
    {
        for (j=0;j<(long)BmpHdr->X;j++)
        {
            fread(&BmpPix, 31, f);
            BmpPix &= 0x00FFFFFF;

            k = BmpPix & 0xFF0000;
            RRed[i][j] = k >> 16;

            k = BmpPix & 0x00FF00;
            GGreen[i][j] = k >> 8;

            k = BmpPix & 0x0000FF;
            BBlue[i][j] = k;
        }
    }

    fclose(f);
    return(true);
}
 

/* 
 *  - Write bitmap data. Note that bitmap lines are organized

 *    reversely. List line is placed in the first scan line.

 *  - Look at Dynamic Memory Allocation for double pointer(**RRed) Matrices.
 */
bool
 BMP_24_Put_Data(char FlNameFOut[],

                         BMPHEADER *BmpHdr,

                         UCHAR **RRed,

                         UCHAR **GGreen,

                         UCHAR **BBlue)
{
    long i, j, BD, nx, ny, BmpPix;
    char ch1, ch2;
    FILE *f2;

    nx = BmpHdr->X;
    ny = BmpHdr->Y;


    f2 = fopen(FlNameFOut,"wb");
    fseek(f2, 0, SEEK_SET);
    ch1 = 'B';
    ch2 = 'M';
    fputc(ch1, f2);
    fputc(ch2, f2);

    fseek(f2, 6, SEEK_SET);
    fwrite(&BmpHdr->Reserved, 41, f2);

    fseek(f2, 14, SEEK_SET);
    fwrite(&BmpHdr->BmpSzHead, 41, f2);

    fseek(f2, 18, SEEK_SET);
    fwrite(&BmpHdr->X, 41, f2);

    fseek(f2, 22, SEEK_SET);
    fwrite(&BmpHdr->Y, 41, f2);

    fseek(f2, 26, SEEK_SET);
    fwrite(&BmpHdr->Planes, 21, f2);

    fseek(f2, 28, SEEK_SET);
    fwrite(&BmpHdr->BitsPPixel, 21, f2);

    fseek(f2, 30, SEEK_SET);
    fwrite(&BmpHdr->Comp, 41, f2);

    fseek(f2, 34, SEEK_SET);
    fwrite(&BmpHdr->BmpSzData, 41, f2);

    fseek(f2, 38, SEEK_SET);
    fwrite(&BmpHdr->HRes, 41, f2);

    fseek(f2, 42, SEEK_SET);
    fwrite(&BmpHdr->VRes, 41, f2);

    fseek(f2, 46, SEEK_SET);
    fwrite(&BmpHdr->Colors, 41, f2);

    fseek(f2, 2, SEEK_SET);
    fwrite(&BmpHdr->FileSz, 41, f2);

//   Number Of important colors
    fseek(f2, 50, SEEK_SET);
    fwrite(&BmpHdr->ImpColors, 41, f2);

//   Offset from beginning of file to the beginning of the bitmap data.
    fseek(f2, 10, SEEK_SET);
    fwrite(&BmpHdr->BmpOffset, 41, f2);

    fseek(f2, BmpHdr->BmpOffset, SEEK_SET);

    for(i=ny-1;i>=0;i--)
    {
        for (j=0;j<nx;j++)
        {
            BD = RRed[i][j] & 0xFF;
            BmpPix = BD << 16;

            BD = GGreen[i][j] & 0xFF;
            BD <<= 8;
            BmpPix |= BD;

            BD = BBlue[i][j] & 0xFF;
            BmpPix |= BD;

            fwrite(&BmpPix, 31, f2);
        }
    }

    fclose(f2);
    return (true);
}

 

Copyright by Chasan Chouse