What is a bitmap?
One of the most important things in creating a user-friendly interface is the use of bitmaps. Without bitmaps, there would be no icons, no fancy buttons, and mouse pointers would have to be made of lines.
The term bitmap is a throwback from when monitors could only display one other color besides black. For two-color data files that store an image, each bit in the data file represents one pixel; a 1 meant the pixel was on, a 0 meant the pixel was off (Figure 13). Therefore, a two-color image is a map of bits.
- Figure 13. A black & white bitmap in memory and on the screen.
The BMP file format
There are many file formats for storing bitmaps, such as RLE, JPEG, TIFF, TGA, PCX, BMP, PNG, PCD and GIF. The bitmaps studied in this section will be 256-color bitmaps, where eight bits represents one pixel.. One of the easiest 256-color bitmap file format is Windows' BMP. This file format can be stored uncompressed, so reading BMP files is fairly simple; most other graphics formats are compressed, and some, like GIF, are difficult to decompress. To learn about other graphics file formats, visit x2ftp.
There are a few different sub-types of the BMP file format. The one studied here is Windows' RGB-encoded BMP format. For 256-color bitmaps, it has a 54-byte header (Table III) followed by a 1024-byte palette table. After that is the actual bitmap, which starts at the lower-left hand corner.
Data | Description |
---|---|
WORD Type; |
File type. Set to "BM". |
DWORD Size; |
Size in BYTES of the file. |
DWORD Reserved; |
Reserved. Set to zero. |
DWORD Offset; |
Offset to the data. |
DWORD headerSize; |
Size of rest of header. Set to 40. |
DWORD Width; |
Width of bitmap in pixels. |
DWORD Height; |
Height of bitmap in pixels. |
WORD Planes; |
Number of Planes. Set to 1. |
WORD BitsPerPixel; |
Number of bits per pixel. |
DWORD Compression; |
Compression. Usually set to 0. |
DWORD SizeImage; |
Size in bytes of the bitmap. |
DWORD XPixelsPerMeter; |
Horizontal pixels per meter. |
DWORD YPixelsPerMeter; |
Vertical pixels per meter. |
DWORD ColorsUsed; |
Number of colors used. |
DWORD ColorsImportant; |
Number of "important" colors. |
Table III. Windows' BMP file format header.
Drawing bitmaps
Once read, displaying the bitmap is relatively easy, and
involves only a few memory copies to display memory. The
following is the code to display a 32x64 image stored in an array
bitmap
:
for(y=0;y<64;y++) for(x=0;x<32;x++) VGA [x+y*320]=bitmap [x+y*32];
Something interesting to note about the BMP file format is
that each scan line is padded to the nearest 4-byte boundry. So,
if the image read has a width that is not divisible by four, say,
21 bytes, there would be 3 bytes of padding at the end of every
scan line. The program bitmap.exe
does not account
for this; it assumes the bitmap's width is divisible by
four.
There are many techniques to implement transparency. One way is to assign one of the 256 colors to be transparent in the program. When drawing the image, a byte with the transparency value is not written to video memory. The following implements this using zero as the transparency value:
for(y=0;y<64;y++) for(x=0;x<32;x++) { data=bitmap [x+y*32]; if (data!=0) VGA [x+y*320]=data; }
The following program bitmap.c
reads a bitmap
file rocket.bmp
(Figure 14) and draws it to the
screen in a tiled fashion, using both opaque and transparent
bitmap drawing functions.
-
Figure 14.
Bitmap
rocket.bmp
.
Program: bitmap.c
- DJGPP 2.0
- View bitmap.c
Download bitmap.zip (Contains bitmap.c, bitmap.exe, rocket.bmp) - Borland C, Turbo C, etc.
- View bitmap.c
Download bitmap.zip (Contains bitmap.c, bitmap.exe, rocket.bmp)
Having trouble compiling or running the program? See the Troubleshooting page.
-
Figure 15.
Output from
bitmap.exe
.
Palette manipulation
The background in the output of bitmap.exe
is a
representation of the VGA's 256-color palette. Fortunately, the
palette is programmable to other colors, so bitmaps are not
forced onto an odd palette. Unfortunatly, the VGA only gives us 6
bits per color channel, so the best you can get is 18-bit color
(but you can only pick 256 of those colors, of course). Palette
information is stored after the header in the BMP file format.
Four bytes define each color: one byte each for blue, green, red,
and one reserved byte. The VGA understands color values in the
order red, green, blue, (reverse of the BMP format) plus the
program needs to change the palette data form 24-bit to 18-bit
(divide each color by four, or right-shift by two).
To set one color in the palette, write the color index to port 0x3C8 and then write the red, green, and blue values, in order, to port 0x3C9
outp(0x03c8, index); outp(0x03c9, red); outp(0x03c9, green); outp(0x03c9, blue);
To set all 256 colors in the palette, write zero to port 0x3C8 and then write all 768 bytes of the palette to port 0x3C9.
outp(0x03c8, 0); for(i=0;i<256;i++) { outp(0x03c9, palette_red[i]); outp(0x03c9, palette_green[i]); outp(0x03c9, palette_blue[i]; }
Note that the palette cannot be set until the 256-color video mode has been set.
The program palette.c
reads in an image, displays
it, and then cycles through all the colors by repeatedly changing
the palette.
Program: palette.c
- DJGPP 2.0
- View palette.c
Download palette.zip (Contains palette.c, palette.exe, mset.bmp) - Borland C, Turbo C, etc.
- View palette.c
Download palette.zip (Contains palette.c, palette.exe, mset.bmp)
Having trouble compiling or running the program? See the Troubleshooting page.
-
Figure 16.
Output from
palette.exe
.
Vertical retrace
Something to note about the program is the function wait_for_retrace
:
void wait_for_retrace(void) { /* wait until done with vertical retrace */ while ((inp(INPUT_STATUS) & VRETRACE)); /* wait until done refreshing */ while (!(inp(INPUT_STATUS) & VRETRACE)); }
If the while
loops in this function were
commented out and the program was run, two things would happen:
the palette would cycle very, very quickly, and the image would
appear to have shearing effect as the palette cycled. The reason
has to do with the VGA's vertical refresh rate.
The VGA refreshes the screen 70 times a second, or 70hz. An
electron gun goes across the screen from left to right, top to
bottom. When it gets to the bottom of the screen, (i.e., it
finished refreshing), the electron gun has to travel from the
bottom right corner of the screen to the upper left corner of the
screen. That time, called the retrace period, is the ideal time
to change the palette. If the program did not wait for the
retrace, the palette would sometimes be changed in the middle of
a refresh, resulting in different colors on the top portion of
the screen for a split second. This is how the shearing effect
happens. To eliminate this, palette.c
uses the wait_for_retrace
function.
The other effect is that the function acts as a timer, which, since the function is called twice, makes the palette cycle at 35 times a second. This is very useful when animating bitmaps, which is a primary focus in the next section.