programming | html tutorial | articles

up ]

Content


Introduction to Bitmap Programming
This tutorial explains what is Bitmap, and how to access them. Readers are encourage to become familiar with File I/O system and Structures. If you can understand the concept you can use any programming language to display bitmap.

There are many kind of bitmaps. Monochrome, 16 color, 256 color or 16 million colour. This tutorial is focused only on 16 colour & 256 colour bitmaps. This tutorial only concern on DOS environment. User for windows environment does not have to follow this tutorial because windows already have the APIs for loading bitmaps, unless you are coding an image editor.

Some of the bitmaps support compression and the bitmaps are used in this tutorial are not compressed. I will not discuss compressed bitmaps.

Bits and Bytes
Consider a binary string. The representation is as follow.
double or long word
  word
      byte
              nibble
11010111 11001010 1111001 1110 1001


name size in bits size in bytes variable size in C
nibble 4 bits ½ byte not available
byte 8 bits 1 byte char
word 16 bits 2 byte unsigned integer
double or long word 32 bits 4 byte unsigned long integer


Note: To read a nibble in C, bitwise operation should be done

What is Bitmap? How do I access them?
A bitmap ( .bmp ) is a binary file. Therefore you should have knowledge of accessing binary formats file. The appropriate file function in C is

 

  • fopen & fclose
  • fread
  • fgetc

Each bitmap file has header which explained what type of bitmap that contained in the file either it's a monochrome bitmaps, 16 colour bitmap, 256 colour bitmap or 16 million colour bitmap. In this tutorial we only concerned about 16 colour and 256 colour bitmaps.

  • The BYTE refers to ONE single Byte.
  • The UINT stands for Unsigned Integer which consist of 2 bytes. It's also known as Word.
  • The DWORD stands for Double Word, consisting of 4 bytes.
  • The LONG also refers to Double Word, consisting of 4 bytes but it is signed.

To read a bitmap, firstly we have to read the file header. The file header will determine whether the file IS A BITMAP FILE, width & height of the image, number of colours contained and so on. To determine whether the file is a bitmap, the bfType must have a value of 19778. This value is taken from 2 byte unsigned integer. If the integer are separated to a single byte. The equivalent value is 'B' for the first byte & 'M' for the second byte, which stand for BitMap. We must first read the BITMAPFILEHEADER, then we read the BITMAPINFOHEADER.

typedef struct tagBITMAPFILEHEADER { /* bmfh */

UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;

} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER { /* bmih */

DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;

} BITMAPINFOHEADER;

Properties of File Header

  Size in bytes data type Name Comment
Bitmap File Header 2 UINT bfType 'B' 'M'
  4 DWORD bfSize size of file
  2 UINT bfReserved1 reserved
  2 UINT bfReserved2 reserved
  4 DWORD bfOffBits byte location in the file which is first byte of IMAGE
Bitmap Info Header 4 DWORD biSize Size of BITMAPINFOHEADER
  4 LONG biWidth width of bitmap
  4 LONG biHeight height of bitmap
  2 WORD biPlanes 1
  2 WORD biBitCount 1 (mono) or 4 (16 clr ) or 8 (256 clr) or 24 (16 Mil)
  4 DWORD biCompression RLE COMPRESSION
  4 DWORD biSizeImage width x height
  4 LONG biXPelsPerMeter  
  4 LONG biYPelsPerMeter  
  4 DWORD biClrUsed Number of palettes used (if less than standard)
  4 DWORD biClrImportant Number of important colour

TOTAL LENGTH OF BITMAP HEADER IS 54 BYTES (NOT NECESSARILY)
depend on size of bitmapinfo header (becareful)

Immediately after the file header is the PALETTES of the bitmaps. It depends on the bitmaps it self. If you are reading 16 colour bitmaps, then the palettes consist of 16 x 4 bytes. If you're reading 256 Colour bitmaps, then the palettes consist of 256 x 4 bytes. For each 4 bytes, the first byte is for RED entries, second is for GREEN entries and the third one is for BLUE entries and the last one is ignored. The reason for this 'ignored byte' is to have a even number of bitmap file size (i.e. multiply of 4). So that the file is more efficient in disk storage terms. The ignored bytes are left unread.

There are some conditions where we have to consider the anomalies of the bitmaps. Some bitmaps does not have completely 16 colour palettes, i.e. less or 4 colour only. Some of the does not have completely 256 colour palettes, may be less. This is because of the program that was used to create the bitmap store only the colour needed to display the image.

BYTE cRed; /* red component of color */
BYTE cGreen; /* green component of color */
BYTE cBlue; /* blue component of color */
BYTE cIgnore; /* ignore this byte */

For 16 colour & 256 colour we only use the first 6 bits of the bytes to determine the colour of the palettes. for example, consider a byte 01101100. The colour used for this byte is 011011. To access the first 6 bits on a bytes you can use bit shifting " >>" (shift 2 position) or using bitwise routine in the download section.

Note: Some of the programs that were used to create bitmaps does not show the right amount of colour used in a bitmap. Therefore, we can determine the colour used by determine the number of colour by using bitCount property. 4 bit is a 16 colour bitmap while 8 bit is a 256 colour bitmap.

After reading the palettes colour, 16x4 bytes or 256x4 bytes. The rest of file is the IMAGE it self. The bitmap IMAGE has certain properties. The left bottom of the image is the first byte of the IMAGE.

first pixel>> This is a gif file, to support the tutorial. <<last pixel

16 & 256 COLOUR IMAGE PROPERTIES

16 colour image will have half the size used for 256 colour, it is because only 4 BITS (also called a nibble) are used to represent ONE PIXEL. For example a byte 11001011. The first pixel is 1100 and the second pixel is 1011. If we have the remainder of the bitmap width equals to 1. Therefore, the bitmap has the last nibble + three byte in each line unused. User should ignore this nibble. The reason is to have a multiply of 4 image size. Do check for the bitmap biImageSize property. This property tells the user the actual bytes reserved for the IMAGE. The biWidth & biHeight tells the user the size of the IMAGE.

For 256 colour bitmap, the image has different properties. ONE BYTE is used to represent ONE PIXEL. If the width of the bitmap is not devisable by 4. Then the rest of the width is padded with 0. For example, Consider a bitmap, which have width that when been divided by 4, the remainder is 1. Therefore, the width is actually sized width+3, with 3 bytes 0 padded at each end of line.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 first byte>>
assume width % 4 == 1
----------------------------
1112323213123123123123123123
1231231231231231232323232322
1231231231231242143123123123
1231231241232131231231231231
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
1231241231231231231231232131
 
---
000
000
000
000
000
000
000
000
000
000
000
000
000
000
 
 
<<last byte

The condition also applies if the remainder of the bitmaps width is 3. In this case only 1 '0' byte padded at every line. The reason of such characteristic is to make the size of the file multiply of 4. For disk storage efficiency.

For learning purpose, suggest you tried to understand 256 colours bitmap file first. Since it is easier to understand. After that, tried 16 colours bitmap. As a challenge why don't you try reading monochrome bitmaps.

BELOW IS AN EXAMPLE OF 16 COLOUR BITMAP FILE.

BitmapFileHeader

Type 		19778
Size 		3118
Reserved1 	0
Reserved2 	0
OffsetBits 	118
BitmapInfoHeader
Size 		40
Width 		80
Height 		75
Planes 		1
BitCount 	4
Compression 	0
SizeImage 	3000
XPelsPerMeter 	0
YPelsPerMeter 	0
ColorsUsed 	16
ColorsImportant 16
Win3ColorTable
	   B    G   R   Unused
[00000000] 84 	252 84  0
[00000001] 252 	252 84  0
[00000002] 84 	84  252 0
[00000003] 252 	84  252 0
[00000004] 84 	252 252 0
[00000005] 252 	252 252 0
[00000006] 0 	0   0   0
[00000007] 168 	0   0   0
[00000008] 0 	168 0   0
[00000009] 168 	168 0   0
[0000000A] 0 	0   168 0
[0000000B] 168 	0   168 0
[0000000C] 0 	168 168 0
[0000000D] 168 	168 168 0
[0000000E] 84 	84  84  0
[0000000F] 252 	84  84  0
Image
.
. Bitmap data
.

Then.. after knowing all the values needed to display the image. We can simply use our graphics system to display the image.

Graphics System

Our graphics must consist of

  • Palette system - A routine that defines the colour palettes on the graphics system.
  • Pixel routine - A routine that put the pixel you read on the screen.

If you code your program efficiently. If you decided to change to another graphics system, you can do it easily without having much coding.

There are several types of graphics system.

  • Turbo C BGI driver. This driver can only display 256 colour in 320x200 pixel mode and 16 colour in 640x480 mode. These modes are originated from the VGA display adapter. To have a larger resolution we have to use another different graphic system on a SVGA (super VGA) monitor.
  • SVGACC.LIB This library has the mode for SVGA display. The minimum resolution is from 320x200 to maximum of 1048x768 pixels. These library routines have all the graphics system capabilities. The SVGACC can be found in the Download Section.
  • Write Your Own! Why don't write your own graphics system. Have full controls to your monitor. This link has all you will need to write your own graphic system. Click here.

There are many others system that you can use. You can search them in the SimTelnet or Garbo. Go to links page

Algorithm for displaying Bitmap
The algorithm for displaying the bitmap file.
  1. Specify which bitmap file to load
  2. Check the bitmap whether it is a valid bitmap.
  3. Read Length of BitmapInfoHeader
  4. Read types of bitmaps
  5. Determine number of colours in the palettes, IMAGE height, IMAGE width ignoring the other.
  6. Read the palettes using the number of colours used.
  7. Save current screen mode. Initialise Graphics System.
  8. Store the palette information on the graphics system.
  9. Read bitmap by determining the offset from OffsetBits.
  10. Draw the pixels on the screen depending on bitmap type.
  11. Deinitiliase graphics system. Restoring old screen mode

Bitmap Viewer Source Code
Click here to view the C Source Code.

ICONS
If you understand how the bitmaps work then to read icons is a very easy task.

typedef struct ICONDIR {

WORD idReserved;
WORD idType;
WORD idCount;

} ICONHEADER;

The ICONHEADER is the first thing we have to read. The idType is set to 1. IdCount refers to number of icons in the icon file. This is because some icon file have more than one icons stored in the file, this type of file consist of icons sized 16x16, 32x32 and so on. Next is the IconsDirectoryEntry, it tell the characteristic of the individual icons stored in the icon file.

typedef struct IconDirectoryEntry {

BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;

}ICONDIRENTRY;

The dwImageOffset points to first byte of BITMAPINFOHEADER from the beginning of the file. The BITMAPINFOHEADER has the same characteristic of the bitmap file *.bmp which have been discussed earlier.

typedef struct tagBITMAPINFOHEADER { /* bmih */

DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;

} BITMAPINFOHEADER;

RGB PALETTE : same as bitmap palette characteristic

XOR MASK
This is the XOR MASK for the icons. It is actually the bitmap IMAGE itself. If you have read & understand the bitmap section earlier, this would not be a problem to you.

AND MASK
This is the AND mask of the bitmaps and we apply these mask before applying the XOR mask. It is actually the BACKGROUND LAYER of the ICON. If you don't previously apply AND mask, your icon will be overlapped (transparent) with the original background on the SCREEN. The mask is in Monochrome format, i.e. EACH BIT in the AND mask represent ONE PIXEL of the BACKGROUND layer.

Example of an ICO file with 3 IconDirectoryEntries

Size in Bytes   Object
6   Icons Header
16   Icon Directory Entry 1
16   Icon Directory Entry 2
16   Icon Directory Entry 3
48 ICON IMAGE 1 Icon1 Bitmap Info Header
depends   Icon1 Palette
depends   Icon1 XOR mask
depends   Icon1 AND mask
48 ICON IMAGE 2 Icon2 Bitmap Info Header
depends   Icon2 Palette
depends   Icon2 XOR mask
depends   Icon2 AND mask
48 ICON IMAGE 3 Icon3 Bitmap Info Header
depends   Icon3 Palette
depends   Icon3 XOR mask
depends   Icon3 AND mask

Algorithm for displaying ICON
The Algorithm to read & draw the Icon
  1. Read ICONHEADER determine the number of icons stored
  2. Read ICONDIRENTRY
  3. For each icon stored....
  4. Read BITMAPINFOHEADER
  5. Read RGB Palettes.
  6. Read XOR Mask.
  7. Read AND Mask.
  8. Save current screen mode. Initiliase Graphic System
  9. Set the RGB palette in the graphic system
  10. Apply the AND mask
  11. Apply the XOR mask
  12. Deinitiliase Graphic System. Restore Old screen mode.

ICON Viewer Source Code
Click here to view the C Source code for icons.

CURSORS
This section is still under construction:

typedef struct tagCURSORDIR {

WORD cdReserved;
WORD cdType;
WORD cdCount;
CURSORDIRENTRY cdEntries[];

} CURSORDIR;

typedef struct tagCURSORDIRENTRY {

BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wXHotspot;
WORD wYHotspot;
DWORD lBytesInRes;
DWORD dwImageOffset;

} CURSORDIRENTRY;

BITMAPINFOHEADER

PALLETTE

XOR MASK

AND MASK

 


c programming | html tutorial | articles | home
about me | links | search | guestbook | photo album
Hosted by www.Geocities.ws

1