November 22, 2014
Hot Topics:

Performing Graphics Operations with BREW Bitmaps

  • March 20, 2007
  • By Ray Rischpater
  • Send Email »
  • More Articles »

Bitmaps are the lifeblood of many graphics applications. Although BREW has a host of graphics primitives for two- and three-dimensional drawing, as well as a plethora of image decoders, there remain times where you just need to have access to the raw bits of an image. In this article, I take you on a quick tour of the kinds of bitmaps provided by BREW, as well as how to manipulate bitmaps and their contents. You'll learn how to create bitmaps, the difference between a conventional bitmap and a device-independent bitmap, how to blit bitmaps, and manipulate individual pixels within a bitmap.

Understanding the Difference Between Bitmaps

BREW bitmaps come in two basic types: device-independent bitmaps and device-dependent bitmaps. As their names imply, device independent bitmaps are inherently portable between devices, although this can come at the cost of performance when manipulating the bitmap. Device dependent bitmaps, on the other hand (also sometimes simply called native bitmaps), are in a format highly tuned to meet the needs of a specific handset's graphics architecture. Speaking of performance, it's important to realize which kinds of bitmap you're working with, because while BREW can convert bitmaps from one format to another (say, when performing a bit blit from one bitmap to another), this format conversion incurs a performance penalty. Regardless of the kind of bitmap you're accessing, you perform bitmap operations using the IBitmap interface.

A specific example of a device-independent bitmap is the IDIB, an interface that has an interesting property; it has fields associated with it. When working with an IDIB, you can obtain references to the pixel map itself as well as the palette map, and other sundries such as the bitmap's width, height, and color depth. I'll say a little more about the IDIB in "Accessing All the Pixels in a Bitmap," later in this article.

Creating Bitmaps

Unlike most BREW interfaces, you won't create a bitmap using ISHELL_CreateInstance. That's because the bitmap has some additional properties you need to set, such as the width and height of the bitmap. Instead, you typically use a factory, such as another bitmap, to create the bitmap using the CreateCompatibleBitmap method. This method creates another bitmap in the same format as the originating bitmap, letting you blit with high performance between the existing and new bitmaps.

Probably the most common pattern that occurs when working with bitmaps is to obtain a bitmap from the display—either the display's bitmap itself, or to create a new compatible bitmap from the display's bitmap. To do this, you write:

IDisplay *piDisplay = p->a.m_pIDisplay
IBitmap *piBitmap, *piScreenBitmap;
IDISPLAY_GetDeviceBitmap( piDisplay, &piScreenBitmap );
IBITMAP_CreateCompatibleBitmap( piScreenBitmap, &piBitmap, WIDTH,
                                HEIGHT );
IBITMAP_Release( piScreenBitmap );

After declaring local variables to contain the screen's bitmap and the new bitmap, this code:

  1. Obtains a reference to the bitmap used by the screen.
  2. Creates a bitmap in a format and color depth compatible with the screen bitmap of dimensions WIDTH and HEIGHT pixels.
  3. Releases the screen's bitmap.

If you need a device-independent bitmap, the process is a little different. You can obtain one in one of two ways: by getting one from the display, or by using IBITMAP_QueryInterface to get the device-independent analogue of an existing bitmap. The first way is better if you just need a device independent bitmap; the second is more useful if you need to capture the contents of an existing bitmap. Using IDisplay, your code might read:

IDisplay *piDisplay = p->a.m_pIDisplay
IDISPLAY_CreateDIBitmap( piDisplay, &piDIB, 16, WIDTH, HEIGHT );

Using IBITMAP_QueryInterface is just as easy:

IBitmap *piBitmap;    // This has to be initialized before we use
IDIB    *piDIB;       // it, of course
IBITMAP_QueryInterface( piBitmap, AEECLSID_DIB, (void **)&piDIB );

Manipulating Bitmaps

There are a variety of things you can do to bitmaps, including blit the contents of one bitmap into another, get or set the value of pixels in the bitmap, or set an entire scan line of pixels to a specific value. Here's some code that sets some random pixel values within a bitmap, and then blits that bitmap back to the screen:

#define NUM_PIXELS  60
#define WIDTH       60
#define HEIGHT      60

void BitmapExample( CApp *p )
{
   IDisplay *piDisplay = p->a.m_pIDisplay;
   IBitmap *piBitmap, *piScreenBitmap;
   byte abyRand[ 60 * ( 3 + 2 ) ];    // Sixty pixels, three colors,
   int i, r, g, b;                    // two axes
   NativeColor nativeColor;
   AEEPoint point;

   GETRAND( abyRand, sizeof( abyRand ) );

   IDISPLAY_ClearScreen( piDisplay );
   IDISPLAY_GetDeviceBitmap( piDisplay, &piScreenBitmap );
   IBITMAP_CreateCompatibleBitmap( piScreenBitmap, &piBitmap,
                                   WIDTH, HEIGHT );
   IBITMAP_Release( piScreenBitmap );
   for ( i = 0; i < NUM_PIXELS; i++ )
   {
      point.x = abyRand[ i * 5 + 0 ] % WIDTH;
      point.y = abyRand[ i * 5 + 1 ] % HEIGHT;
      r       = abyRand[ i * 5 + 2 ];
      g       = abyRand[ i * 5 + 3 ];
      b       = abyRand[ i * 5 + 4 ];

      nativeColor = IBITMAP_RGBToNative( piBitmap,
                                         MAKE_RGB( r, g, b ) );
      IBITMAP_SetPixels( piBitmap, 1, &point, nativeColor,
                         AEE_RO_COPY );
   }

   // Update the display bitmap.
   IDISPLAY_BitBlt( piDisplay, 0, 0, WIDTH, HEIGHT, piBitmap, 0, 0,
                    AEE_RO_COPY );
   IBITMAP_Release( piBitmap );
   IDISPLAY_Update( piDisplay );
}

The code begins by getting the display's bitmap, from which I derive a compatible bitmap, just as I showed in the previous section. Next, I loop for a predetermined number of pixels, using the random data to determine both the coordinate and the RGB value of a pixel to change. I can't use this RGB value directly, however; first, I must convert it to the bitmap's native representation for the color using IBITMAP_RGBToNative. (There's a corresponding API, IBITMAP_NativeToRGB, that converts the internal representation to a RGB triplet.) Then, I set the selected pixel's color directly, using IBITMAP_SetPixels. SetPixels takes an array of pixels, and sets all the pixels in the array to the preset value; a more efficient way to do this if I had a lot of pixels of the same color would be to first generate pixel lists by color and then use one call to IBITMAP_SetPixels for each color. Finally, I update the display directly by bit blitting the mutated bitmap directly to the screen at the origin. IDISPLAY_BitBlt takes arguments specifying the destination rectangle of the bit blit first, followed by the source bitmap, and the offset into the source bitmap, and then the drawing mode used for the bit blit operation. Once complete, I need only clean up the bitmap I created in the first step and update the display.

Of course, you can also bit blit directly from one bitmap to another. This is done by using the destination bitmap's IBITMAP_BltIn method, which takes the same arguments as IDISPLAY_BitBlt (although, of course, the first argument is a valid bitmap, not an instance of IDisplay!). Bitmaps also offer the IBITMAP_BltOut method, which is used to blit bits out of the provided display; you don't normally use this directly, although BREW may invoke it on the source bitmap when you invoke IBITMAP_BltIn.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel