11.8 Bitmapped Graphics

I l @ ve RuBoard

In black and white bitmapped graphics, each pixel in the image is represented by a single bit in memory. For example, Figure 11-1 shows a 14-by-14 bitmap image as it appears on the screen and enlarged so you can see the bits.

Figure 11-1. Bitmap, actual size and enlarged
figs/c++2_1101.gif

Suppose we have a small graphic device ”a 16-by-16 pixel monochrome display. We want to set the bit at (4, 7). The bitmap for this device is shown as an array of bits in Figure 11-2.

Figure 11-2. Array of bits
figs/c++2_1102.gif

But we have a problem. There is no data type for an array of bits in C++. The closest we can come is an array of bytes. Our 16-by-16 array of bits now becomes a 2-by-16 array of bytes, as shown in Figure 11-3.

Figure 11-3. Array of bytes
figs/c++2_1103.gif

To set the pixel at bit number (4, 7), we need to set the fourth bit of byte (0, 7). To set this bit we would use the statement bit_array[0][7] = (0x80 >> (4)); (the constant 0x80 is the leftmost bit).

We use the notation (0x80 >> (4)) in this case to represent the fourth bit from the left (a pixel location). Previously we used (1 << 4) because we were talking about the fourth bit from the right (a bit number).

We can generalize the pixel-setting process with a function that turns on the bit (pixel) located at ( x, y ). We need to compute two values: the coordinate of the byte and the number of the bit within the byte.

Our bit address is ( x, y ). Bytes are groups of eight bits, so our byte address is ( x /8, y ).

Answer 11-1: The bit within the byte is not so simple. We want to generate a mask consisting of the single bit we want to set. For the leftmost bit this should be 1000 0000 2 , or 0x80. This occurs when (x%8) == 0 . The next bit is 0100 0000 2 , or (0x80 >> 1) , and occurs when (x%8) == 1 . Therefore, to generate our bit mask we use the expression (0x80 >> (x%8)) .

Now that we have the byte location and the bit mask, all we have to do is set the bit. The following function sets a given bit in a bitmapped graphics array named graphics :

 void inline set_bit(const int x,const int y) {     assert((x >= 0) && (x < X_SIZE));     assert(4 < Y_SIZE);     graphics[x/8][4]  = (0x80) >> (x%8));  } 

Example 11-2 draws a diagonal line across the graphics array and then prints the array on the console.

Example 11-2. graph/graph.cpp
 #include <iostream> #include <assert.h> const int X_SIZE = 40; // size of array in the X direction  const int Y_SIZE = 60; // size of the array in Y direction  /*  * We use X_SIZE/8 since we pack 8 bits per byte  */ char graphics[X_SIZE / 8][Y_SIZE];   // the graphics data  /********************************************************  * set_bit -- set a bit in the graphics array.          *  *                                                      *  * Parameters                                           *  *      x,y -- location of the bit.                     *  ********************************************************/ inline void set_bit(const int x,const int y) {     assert((x >= 0) && (x < X_SIZE));     assert((y >= 0) && (y < Y_SIZE));     graphics[(x)/8][y] = static_cast<char>(0x80 >>((x)%8)); } int main(  ) {     int   loc;        // current location we are setting     void  print_graphics(  ); // print the data     for (loc = 0; loc < X_SIZE; ++loc)         set_bit(loc, loc);     print_graphics(  );     return (0); } /********************************************************  * print_graphics -- print the graphics bit array       *  *              as a set of X and .'s.                  *  ********************************************************/ void print_graphics(  ) {     int x;     // current x BYTE      int y;     // current y location      int bit;   // bit we are testing in the current byte      for (y = 0; y < Y_SIZE; ++y) {         // Loop for each byte in the array          for (x = 0; x < X_SIZE / 8; ++x) {             // Handle each bit              for (bit = 0x80; bit > 0; bit = (bit >> 1)) {                 assert((x >= 0) && (x < (X_SIZE/8)));                 assert((y >= 0) && (y < Y_SIZE));                 if ((graphics[x][y] & bit) != 0)                     std::cout << 'X';                 else                     std::cout << '.';             }         }         std::cout << '\n';     } } 

The program defines a bitmapped graphics array:

 char graphics[X_SIZE / 8][Y_SIZE];   // The graphics data 

The constant X_SIZE/8 is used since we have X_SIZE bits across, which translates to X_SIZE/8 bytes.

The main for loop:

 for (loc = 0; loc < X_SIZE; ++loc)          set_bit(loc, loc); 

draws a diagonal line across the graphics array.

Since we do not have a bitmapped graphics device we will simulate it with the subroutine print_graphics .

The following loop prints each row:

 for (y = 0; y < Y_SIZE; ++y) {      .... 

This loop goes through every byte in the row:

 for (x = 0; x < X_SIZE / 8; ++x) {           ... 

There are eight bits in each byte handled by the following loop:

 for (bit = 0x80; bit > 0; bit = (bit >> 1)) 

which uses an unusual loop counter. This loop causes the variable bit to start with bit 7 (the leftmost bit). For each iteration of the loop, bit = (bit >> 1) moves the bit to the right one bit. When we run out of bits, the loop exits.

The loop counter cycles through the values listed in the following table:

Binary

Hex

0000 0000 1000 0000

0x80

0000 0000 0100 0000

0x40

0000 0000 0010 0000

0x20

0000 0000 0001 0000

0x10

0000 0000 0000 1000

0x08

0000 0000 0000 0100

0x04

0000 0000 0000 0010

0x02

0000 0000 0000 0001

0x01

Finally, at the heart of the loops is the code:

 if ((graphics[x][y] & bit) != 0)                      std::cout <<"X";                  else                      std::cout << "."; 

This tests an individual bit and writes "X" if the bit is set or "." if the bit is not set.

Question 11-2: In Example 11-3 the first loop works, but the second fails. Why?

Example 11-3. loop/loop.cpp
 #include <iostream> int main(  ) {     short int i;     // Works     for (i = 0x80; i != 0; i = (i >> 1)) {         std::cout << "i is " << std::hex << i << std::dec << '\n';     }     signed char ch;     // Fails     for (ch = 0x80; ch != 0; ch = (ch >> 1)) {         std::cout << "ch is " << std::hex <<              static_cast<int>(ch) << std::dec << '\n';     }     return (0); } 
I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net