Jump to content

GPIGuide - Bit Maps: Difference between revisions

From EDM2
Created page with "= Bit Maps = Raster output devices, such as display screens, are made up of a number of picture elements, called pixels or pels. By setting the color of the pels, you can create an image on the screen. The screen image can be represented internally by a graphics object called a '''bit map'''. The bit map contains a number of bits that describe the appearance of each pel on the screen. This chapter describes bit maps, their creation, uses, and functions. The following to..."
 
Line 265: Line 265:


==Using Bit Maps==
==Using Bit Maps==
An application can use bit-map functions to:
* Copy an image from a raster device (such as a display screen) to a bit map
* Copy an image from a raster device (such as a display screen) to the same device
* Copy an image from a bit map to a raster device
* Copy an image from a bit map to another bit map
* Copy an image from application memory to a bit map
* Copy an image from application memory to a raster device
* Scale bit-map images
* Create custom fill patterns for area primitives and paths
* Load a bit map created with the Icon Editor
* Draw bit-map images
* Store bit maps in a metafile or application memory
===Copying an Image from a Display Screen to a Bit Map===
To copy an image from a display screen to a bit map:
1.  Associate the memory device context with a presentation space.
2.  Create a bit map.
3.  Select the bit map into the memory device context by calling [GpiSetBitmap](hd res=50211).
4.  Determine the location (in device coordinates) of the image.
5.  Call [GpiBitBlt](hd res=50018) and copy the image to the bit map.
The following figure demonstrates these steps.
<pre>
HDC hdcMem;
PSZ pszData[4] = { "Display", NULL, NULL, NULL };
HPS hpsMem, hps;
HAB hab;
SIZEL sizlPage = {0, 0};
BITMAPINFOHEADER2 bmp;
PBITMAPINFO2 pbmi;
HBITMAP hbm;
SHORT sWidth = 128, sHeight = 128;
POINTL aptl[3];
LONG alData[2];
/*
* Create the memory device context and presentation space so they
* are compatible with the screen device context and presentation space.
*/
hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 4,
    (PDEVOPENDATA) pszData, NULLHANDLE);
hpsMem = GpiCreatePS(hab, hdcMem, &sizlPage,
    PU_PELS | GPIA_ASSOC | GPIT_MICRO);
/* Determine the device's plane/bit-count format. */
GpiQueryDeviceBitmapFormats(hpsMem, 2, alData);
/*
* Load the BITMAPINFOHEADER2 and BITMAPINFO2 structures. The sWidth and
* sHeight fields specify the width and height of the destination
* rectangle.
*/
bmp.cbFix = (ULONG) sizeof(BITMAPINFOHEADER2);
bmp.cx = sWidth;
bmp.cy = sHeight;
bmp.cPlanes = alData[0];
bmp.cBitCount = alData[1];
bmp.ulCompression = BCA_UNCOMP;
bmp.cbImage = (((sWidth *
    (1 << bmp.cPlanes) * (1 << bmp.cBitCount)) + 31) / 32) * sHeight;
bmp.cxResolution = 70;
bmp.cyResolution = 70;
bmp.cclrUsed = 2;
bmp.cclrImportant = 0;
bmp.usUnits = BRU_METRIC;
bmp.usReserved = 0;
bmp.usRecording = BRA_BOTTOMUP;
bmp.usRendering = BRH_NOTHALFTONED;
bmp.cSize1 = 0;
bmp.cSize2 = 0;
bmp.ulColorEncoding = BCE_RGB;
bmp.ulIdentifier = 0;
DosAllocMem((PPVOID)&pbmi, sizeof(BITMAPINFO2) +
    (sizeof(RGB2) * (1 << bmp.cPlanes) * (1 << bmp.cBitCount)),
    PAG_COMMIT | PAG_READ | PAG_WRITE);
pbmi->cbFix = bmp.cbFix;
pbmi->cx = bmp.cx;
pbmi->cy = bmp.cy;
pbmi->cPlanes = bmp.cPlanes;
pbmi->cBitCount = bmp.cBitCount;
pbmi->ulCompression = BCA_UNCOMP;
pbmi->cbImage = ((sWidth+31)/32) * sHeight;
pbmi->cxResolution = 70;
pbmi->cyResolution = 70;
pbmi->cclrUsed = 2;
pbmi->cclrImportant = 0;
pbmi->usUnits = BRU_METRIC;
pbmi->usReserved = 0;
pbmi->usRecording = BRA_BOTTOMUP;
pbmi->usRendering = BRH_NOTHALFTONED;
pbmi->cSize1 = 0;
pbmi->cSize2 = 0;
pbmi->ulColorEncoding = BCE_RGB;
pbmi->ulIdentifier = 0;
/* Create a bit map that is compatible with the display.          */
hbm = GpiCreateBitmap(hpsMem, &bmp, FALSE, NULL, pbmi);
/* Associate the bit map and the memory presentation space.        */
GpiSetBitmap(hpsMem, hbm);
/* Copy the screen to the bit map.                                */
aptl[0].x = 0;      /* Lower-left corner of destination rectangle  */
aptl[0].y = 0;      /* Lower-left corner of destination rectangle  */
aptl[1].x = sWidth;  /* Upper-right corner of destination rectangle */
aptl[1].y = sHeight; /* Upper-right corner of destination rectangle */
aptl[2].x = 0;      /* Lower-left corner of source rectangle      */
aptl[2].y = 0;      /* Lower-left corner of source rectangle      */
hps = WinGetScreenPS(HWND_DESKTOP);
GpiBitBlt(hpsMem, hps,
    sizeof(aptl) / sizeof(POINTL), /* Number of points in aptl      */
    aptl, ROP_SRCCOPY, BBO_IGNORE);
WinReleasePS(hps);
</pre>
===Scaling and Drawing a Bit-Map Image===
You can scale a bit map by calling [GpiBitBlt](hd res=50018) or [GpiWCBitBlt](hd res=50273) and altering the dimensions of the target rectangle. The following figure shows how to shrink the screen copied in the first example to half its original size, and then redraw it by calling [GpiBitBlt](hd res=50018).
<pre>
POINTL aptl[3];
HPS hpsMem, hps;
HWND hwnd;
SHORT sWidth = 128, sHeight = 128;
/* Target-rectangle dimensions (in device coordinates)          */
aptl[0].x = 0;
aptl[0].y = 0;
aptl[1].x = sWidth / 2;
aptl[1].y = sHeight / 2;
/* Source-rectangle dimensions (in device coordinates)          */
aptl[2].x = 0;
aptl[2].y = 0;
aptl[3].x = sWidth;
aptl[3].y = sHeight;
hps = WinGetPS(hwnd);
GpiBitBlt(hps, hpsMem,
    sizeof(aptl) / sizeof(POINTL),    /* Number of points in aptl */
    aptl, ROP_SRCCOPY, BBO_IGNORE);
WinReleasePS(hps);
</pre>
===Creating a Custom Fill Pattern===
To create a custom fill pattern that the operating system will use to fill area primitives and paths:
* Set an array of bits for a bit map that measures 8-bits-by-8-bits (remember that the operating system pads the bit-map bits on a ULONG (32-bit) boundary).
* Create a bit map in a screen presentation space by calling [GpiCreateBitmap](hd res=50035) and passing it the address of the array of bits from Step 1.
* Assign a local identifier (lcid) to the bit map by calling [GpiSetBitmapId](hd res=50214).
* Set the attribute of the pattern set in the [AREABUNDLE](hd refid=6) structure by calling [GpiSetPattern](hd res=50253).
The following figure shows how to create the pattern.
<pre>
/* Define an array of bytes;  this array creates a grid pattern. */
BYTE abPattern5[] = {
    0xFF, 0xFF, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00 };
    LONG lcidCustom = 1;
HPS hps;
PBITMAPINFO2 pbmi;
BITMAPINFOHEADER2 bmp;
HBITMAP hbm;
PRGB2 prgb2;
/* Create the bit map, passing the address of the array of bytes. */
hbm = GpiCreateBitmap(hps, &bmp, CBM_INIT, (PBYTE) abPattern5, pbmi);
/* Assign a local identifier to the bit map.                    */
GpiSetBitmapId(hps, hbm, lcidCustom);
/* Set the pattern-set attribute in the AREABUNDLE structure.    */
GpiSetPatternSet(hps, lcidCustom);
</pre>
===Loading a Bit Map from a File===
You can load a bit map from a file if the format of the file corresponds to the standard IBM OS/2 bit-map file format. (Any bit map that you create with the Icon Editor is automatically stored in this format.) To load a bit map:
* Copy the bit-map file to the directory that contains your application's resource file and source code.
* Create an entry in your application's resource file, assigning a unique integer identifier to the bit map.
* Call [GpiLoadBitmap](hd res=50074) in your application's source code, passing it the integer identifier that you assigned to the bit map in your application's resource file.
You can actually include your bit map in the application's .EXE file or in a separate resource file. If the bit map is included in a separate resource file, you must specify both the resource ID and the ID of the bit map within the resource file on [GpiLoadBitmap](hd res=50074). If the bit map is to be included in the application's .EXE file, the resource ID is specified as NULL and only the ID of the bit map is required by [GpiLoadBitmap](hd res=50074).
Following is an example of code from an application's resource file that assigns the integer value 200 to a bit-map file called CUSTOM.BMP.
[[Image:BITMAP  200 CUSTOM.BMP]]
The following figure is an example of code from the application that shows how to retrieve a bit-map handle by calling [GpiLoadBitmap](hd res=50074), use the handle to tag the bit map by calling [GpiSetBitmapId](hd res=50214), and then use the local identifier supplied by [GpiSetBitmapId](hd res=50214) to set the bit map as the current fill pattern, using [GpiSetPatternSet](hd res=50255).
<pre>
HPS hps;
HBITMAP hbm;
LONG lcidCustom = 1;
POINTL ptl;
hbm = GpiLoadBitmap(hps,  /* Presentation-space handle        */
    NULLHANDLE,          /* Resource in application's module */
    IDB_PATTERN,          /* Bit-map ID                      */
    16,                  /* Bit-map width                    */
    16);                  /* Bit-map height                  */
/* Assign a local identifier to the bit map.                */
GpiSetBitmapId(hps, hbm, lcidCustom);
/* Set the pattern-set attribute in the AREABUNDLE structure. */
GpiSetPatternSet(hps, lcidCustom);
ptl.x = 100;
ptl.y = 100;
GpiMove(hps, &ptl);
ptl.x = 200;
ptl.y = 200;
GpiBox(hps, DRO_OUTLINEFILL, &ptl, 0, 0);
</pre>
===Storing a Bit Map in a Metafile===
You can draw bit maps in a metafile or segment by calling [GpiWCBitBlt](hd res=50273). The operating system converts this function to a drawing order. The target-rectangle dimensions that you pass to [GpiWCBitBlt](hd res=50273) are in world coordinates, not device coordinates. The following figure shows how to draw a bit map in a metafile, and then play the metafile.
<pre>
DEVOPENSTRUC dop;
HDC hdcMeta;
HPS hps, hpsMeta;
SIZEL sizlPage;
HMF hmf;
HBITMAP hbm;
HAB hab;
HWND hwnd;
POINTL aptl[4];
dop.pszLogAddress = NULL;
dop.pszDriverName = "DISPLAY";
dop.pdriv = NULL;
dop.pszDataType = NULL;
hdcMeta = DevOpenDC(hab, OD_METAFILE, "*", 4L,
            (PDEVOPENDATA) &dop, NULLHANDLE);
hpsMeta = GpiCreatePS(hab, hdcMeta, &sizlPage, PU_PELS | GPIA_ASSOC);
hbm = GpiLoadBitmap(hpsMeta, NULLHANDLE, IDB_PATTERN, 16L, 16L);
aptl[0].x = aptl[0].y = 0; /* Lower-left corner target rectangle      */
aptl[1].x = 150;          /* X coordinate upper-right target rectangle */
aptl[1].y = 300;          /* Y coordinate upper-right target rectangle */
aptl[2].x = aptl[2].y = 0; /* Lower-left corner source rectangle      */
aptl[3].x = aptl[3].y = 16; /* Upper-right corner source rectangle      */
GpiWCBitBlt(hpsMeta, hbm, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);
GpiAssociate(hpsMeta, NULLHANDLE);
hmf = DevCloseDC(hdcMeta);
hps = WinGetPS(hwnd);
GpiPlayMetaFile(hps, hmf, 0L, NULL, NULL, 0L, NULL);
WinReleasePS(hps);
</pre>
You can also store a bit map in a metafile by calling [GpiBitBlt](hd res=50018). In this case, however, the bit map will be stored inside an escape order.

Revision as of 03:42, 4 May 2025

Bit Maps

Raster output devices, such as display screens, are made up of a number of picture elements, called pixels or pels. By setting the color of the pels, you can create an image on the screen. The screen image can be represented internally by a graphics object called a bit map. The bit map contains a number of bits that describe the appearance of each pel on the screen. This chapter describes bit maps, their creation, uses, and functions. The following topics are related to information in this chapter:

  • Presentation spaces and device contexts
  • Coordinate spaces
  • Color and mix modes
  • Area primitives
  • Paths

About Bit Maps

Applications can use bit maps to:

  • Store and display scanned images, icons, and symbols
  • Create fill patterns for area primitives and paths

An application can display a bit-map image on any raster output device. A raster is a rectangular matrix of pels on a video display or dot matrix printer. A raster output device displays an image by setting pels in its matrix to colors specified in a corresponding bit map. An image created in this way is called a 'bit-map image'. Bit maps cannot be sent to vector output devices such as plotters. A bit map is drawn to an output device row by row. Each horizontal line of pels is known as a scan line. There is a 1-to-1 correspondence between the number of rows of pels in a bit-map image and the rows of bits in a bit map. The first pel in a bit-map image is in the lower-left corner, and the last pel is in the upper-right corner. The pels are in left-to-right order inside each row of the image. The following figure shows this relationship between bit map and image.

File:Img8.bmp
Bits and Pels in a Bit-Map Image

When an application creates a bit map by calling GpiCreateBitmap, it specifies the bit-map width and height in terms of pels in the bit-map image. The width is the number of pels within a row; the height is the number of rows. The application must store these dimensions in the BITMAPINFO2 and BITMAPINFOHEADER and pass their addresses to GpiCreateBitmap.

System Implementation

Bit maps are most useful when rapid and frequent movement is required, such as with icons and pointers. They are especially useful for restoring the contents of a window-for example, when an overlying window is removed. If you save the contents of a window in a bit map, you can restore the window contents simply by redisplaying the bit map when the window needs to be redrawn. Using bit maps is also an effective method of erasing some of the screen contents. For example, you can save the image of the screen in a bit map at any time while drawing on the screen. If you continue drawing after saving the screen image, you can 'erase' any drawing done since you saved the screen image by redisplaying the bit map. Bit maps are not, however, the recommended way to store graphics that are going to be changed. Most changes to the bit-map contents mean that you have to re-create the bit map. Bit-map images are device-dependent. Their appearance is affected by the shape of the device's pels and the device's color capabilities. For example, if the pels on one display measure 0.05 mm by 0.1 mm, but 0.1 mm by 0.3 mm on a second display, a circular bit-map pie chart drawn on the first display appears elliptical on the second. The following figure shows how a bit map appears on two types of displays.

File:Img9.bmp
Bit Map Shown on Two Types of Displays

Bit maps, particularly color bit maps, can also occupy large amounts of memory. The actual amount of memory occupied by a bit map is determined by both the size of the bit map and the number of bits used to describe each pel.

Bit Map Functions

The OS/2 operating system provides a set of functions that allow you to:

  • Create bit maps
  • Create and load custom bit maps
  • Store color information on a bit map
  • Draw bit maps
  • Transfer bit maps
  • Change the size of a bit map
  • Specify the mix values for a bit map
  • Convert between monochrome and color data
  • Manipulate single pels
  • Copy images from a display into a bit map
  • Save a bit map
  • Delete a bit map
  • Make a bit map available to other processes

Creating a Bit Map

A bit map can be created by an application or by using the PM Icon Editor.

By an Application

To enable an application to create a bit map:

  1. Create a memory device context.

A memory device context enables an application to treat a bit map in memory as though it were a device. For example, an application can copy color information from another bit map, or copy pels on the display, into a bit map associated with a memory device context. To create the memory device context, call DevOpenDC with:

  • A device type of OD_MEMORY (second argument)
  • A handle to a compatible device context (such as the device context of a device with which the bit map is to be compatible).

Note: The device device-context handle ideally should be the handle of the actual device to which you will be directing the bit map. Otherwise, it will be necessary to change ownership to the appropriate device driver before the BitBlt operation (which copies the bit map from one presentation space to one associated with a screen device context). As a consequence, the image may appear distorted. If you omit the handle of the compatible device context by specifying NULL, screen compatibility is assumed.

  1. Create a graphics presentation space and associate it with the memory device context.

The operating system requires this association before the application can perform many of the bit map operations. The handle of this graphics presentation space is required as input to subsequent bit-map-creation and manipulation functions.

  1. Create the bit map.

When an application creates a bit map, the handle of the presentation space that you have associated with the memory device context causes the bit map to be created in a format that is compatible with the memory device context. The application also passes two structures: the bit-map information header and the bit-map information table. These structures contain a great deal of information about the bit map. To create the bit map, call GpiCreateBitmap with:

  • The handle of the presentation space (first argument)
  • The bit-map information header, BITMAPINFOHEADER (second argument). (last argument).

The bit-map information table contains similar information, with the addition of the RGB2 array structure. GpiCreateBitmap returns a handle to the bit map, which is used to identify the bit map. To determine which bit-map formats are supported on a particular device, call GpiQueryDeviceBitmapFormats. This returns every format supported on a named device. The data is returned as an array of bit-map plane and bit-count pairs. The first pair of values in the array is the one most suitable for the device. You can think of the bit map at this stage as a rectangular area of memory containing random data. You can initialize the bit map at this stage by providing GpiCreateBitmap with the address in application storage of some initialization data and by setting the CBM_INIT option. This is a useful function if, for example, your application always starts by displaying the same image.

  1. Select the bit map.

Before selecting the bit map, you can disassociate the presentation space from the original memory device context and associate it with a different memory device context. However, the bit-map format must be convertible to a format that is supported by the new device. If you have selected one of the four standard bit-map formats, this compatibility is guaranteed and the conversion is automatic.

Note: When a presentation space is associated with a memory device context, a bit map must be selected into the device context before you can draw in the presentation space. To select the bit map, call GpiSetBitmap with:

  • The presentation-space handle (first parameter)
  • The bit-map handle (second parameter).

The following figure shows the sequence of events when you create and display a bit map.

File:Img10.bmp
Creating and Displaying Bit Maps

The application:

  1. Calls DevOpenDC to create the memory device context.
  2. Creates a graphics presentation space. This is associated with the memory device context.
  3. Calls GpiCreateBitmap to define a bit map.
  4. Calls GpiSetBitmap to designate the bit map as the one currently selected in the memory device context.
  5. Calls drawing instructions to the presentation space to draw to the bit map.

Note: If the bit map is initialized when it is created, this step does not normally exist. Alternatively, this step can be a GpiSetBitmapBits call.

  1. Calls GpiBitBlt to copy the bit map from presentation space 1 to presentation space 2 (associated with a screen device context). The bit map is transferred directly to the screen.
Using the Icon Editor

Using the Icon Editor, you can create monochrome or color bit maps that have a static appearance. This means that the bit maps can be created in advance and then used without change while the application is running. When you use the Icon Editor to create a bit map, the bit map is saved in a resource file that can be loaded whenever it is needed. To load a bit-map file, call GpiLoadBitmap, with the identifier of the resource file that contains the bit map, as the second parameter. If you allow this value to default, the application's .EXE file is assumed to contain the bit map. GpiLoadBitmap lets you specify the x- and y-dimensions (in pels) of the bit map. The loaded bit map is stretched or compressed accordingly. If you supply a 0 value for one of these dimensions, the bit map is sized in the other dimension only, which is likely to cause distortion of the image. If the bit map is to be produced in its original size, specify 0 for both its width and its height. Output from the call to this function is the bit-map handle. To display the loaded bit map on the screen, follow the sequence of steps described in the preceding section, omitting steps 3 (defining the bit map) and 5 (issuing drawing instructions to the presentation space). A bit map created by the Icon Editor is saved in a device-independent format. This format generates an array of bit maps with formats (bits per pel) matching each of the supported display devices.

Creating and Loading a Custom Bit Map

An application can create a custom bit map by setting the bits in an array and passing the array to GpiCreateBitmap or by running the Icon Editor and loading the bit map with GpiLoadBitmap. To create a custom bit map with an array, an application:

  1. Defines an array of bytes that will set pels in an image to the appropriate colors. This array of bytes typically represents the output of a scanned image.
  2. Sets the fields in the BITMAPINFOHEADER to their appropriate values.
  3. Sets the fields in the BITMAPINFO2 structure to their appropriate values.
  4. Calls GpiCreateBitmap, passes it the addresses of the structures and the array of bytes that the application has already defined, and sets the flOptions parameter to CBM_INIT.

If the application is to use this bit map as a fill pattern, it assigns the bit map a local identifier by calling GpiSetBitmapId. To load a custom bit map that was created with the Icon Editor:

  1. Copy the bit map file to the directory in which you compile your application.
  2. Create a BITMAP entry in your application's resource file, assigning a unique integer identifier to the bit map.
  3. Call GpiLoadBitmap, passing it the identifier that you assigned to the bit map in the resource file.

An application can use GpiLoadBitmap to load any bit map from a file that conforms to any of the standard OS/2 bit-map formats or to a device-specific format supported by the device concerned. This means that an application can load a bit map created by another application, if that application created the correct bit-map header and stored the bit-map bits correctly.

Storing Color Information in a Bit Map

Graphics systems use one of two formats for storing color information in bit maps. The first format uses a single plane and a multiple bit count. The second format uses multiple color planes.

Color Planes

Bit maps are arranged in one or more color planes. A color plane is an array of bit-map bits that contains color information. The bit maps in each of the previous illustrations use the single bit-map plane format, which is the standard format for bit maps in OS/2 applications. In this format, a specified number of adjacent bit-map bits contains indexes to either a special color table of RGB values or actual RGB2 structures. Whether the application maps bits into an RGB or RGB2 structure depends on the bit-map format. All of the color information resides in a single plane. The second color format uses more than one color plane. A common multiplane bit-map format is the three-plane format, in which one plane corresponds to the red pels, another to the green pels, and a third to the blue pels. Multiplane bit-map formats are rare in PM applications. Most bit maps are stored externally in a single-plane format, although the device driver (such as VGA) may internally convert them to the multiplane format. The single-plane format can be converted internally to any multiplane format used by a device. You also can use a nonstandard number of bits to describe each pel, if supported by your output device. If you write your own presentation driver, it must be able to convert the standard bit-map formats to its own internal format. An application can determine which color-plane format a device supports by calling GpiQueryDeviceBitmapFormats.

Standard Bit-Map Formats

On a monochrome device, you need only one bit to describe a single pel, and that bit is switched on or off. Color devices require more bits. For example, an eight-color picture requires three bits to describe a single pel, because each component of the RGB mix (red, green, blue) that gives a pel its color must be described. A bit count is a value that specifies how many adjacent bit-map bits correspond to each pel in a bit-map image. There are four standard bit-map formats, each with a different bit count. The formats are shown in the following table.

Standard Bit-Map Formats
Format Bits per pel Size of 640 x 480 image in bytes (uncompressed)
Monochrome 1 38 400
16 color 4 153 600
256 color 8 307 200
16.7 million color 24 921 600

Note: The bits are stored consecutively in the bit-map plane. If you have four bits for each pel, the four bits for pel 1 are followed by the four bits for pel 2, and so on. The bits that describe pel 1 are stored beginning in the most-significant bits of the first byte. The data for each scan line is packed together, and the bottom scan line appears first in memory with the leftmost pel first. Each scan line, however, is padded at the end so that each line begins on a ULONG (32-bit) boundary. If the device supports a bit count of one bit per pel, the color table contains two entries. A device that supports a bit count of n bits per pel, has a corresponding color table with 2n entries. However, a bit count of 24 bits per pel indicates that there is no color table, because each pel is a direct RGB value. The following figure shows a bit map using a bit count of four bits per pel and an associated color table:

File:Img11.bmp
A Bit Map and Its Associated Color Table

If a device uses a bit count of one, four or eight bits per pel, the bit-map bits contain index values for a bit-map color table. If the device supports a bit count of 24 bits per pel, the bit-map bits contain the bRed, bGreen, and bBlue fields of RGB2 structures. No color table is associated with a bit map on a device that supports a format of 24 bits per pel-such a device can support over 16 million colors. Instead of using a color table, the BITMAPINFO2 structure consists of only the header, and the red, green, and blue color values are provided directly by the bit-map data. An application can determine the bit-count format that a device supports by calling GpiQueryDeviceBitmapFormats.

Drawing Bit Maps

An application can draw bit-map images on a raster printer or display screen, or into metafiles associated with a raster device. Any GPI drawing requests (including those that produce graphics text), issued to a presentation space associated with a memory DC containing a selected bit map, cause the bit map to receive raster images of your drawings. The following table describes the bit map drawing functions:

Bit Map Drawing Functions
Function Input Output
WinDrawBitmap The handle of a bit map. A bit-map image on a raster display.
GpiImage A buffer containing bit map image data. A special monochrome bit-map image on a raster display or printer.
GpiDrawBits A buffer containing bit map image data. A bit-map image on a raster display or printer.
GpiBitBlt The handle of a presentation space containing a bit map. A bit-map image on a raster display or printer, or a bit-map image into a metafile (albeit in an escape order).
GpiWCBitBlt The handle of a bit map. A bit-map image on a raster display or printer, or a bit-map image into a metafile.
WinDrawBitmap

WinDrawBitmap draws a bit-map image by copying it into a window linked to a target presentation space. A call to this function is valid only in draw mode (DM_DRAW), and only for a screen device context. This function does not require an application to select a bit map into a presentation space before the application draws the corresponding image. An application can use WinDrawBitmap to scale bit maps by specifying DBM_STRETCH as the last argument, and the address of a RECTL structure as the fourth argument. The coordinates in this structure are always device coordinates. WinDrawBitmap draws both color and monochrome bit maps. Color bit maps require no color conversion. Monochrome bit maps can be drawn in any two colors which can be explicitly specified as parameters to the call or taken from the image bundle. These parameters will be color table indexes or RGB values, depending on the color table mode of the target presentation space. The current image bundle mix modes are used and, for certain mix values, will affect color. You can call WinDrawBitmap in retain mode, but the bit-map image will only be drawn and not recorded in the segments.

Note: An application can determine the current colors and their corresponding mix modes by calling GpiQueryAttrs. The application can set them by calling GpiSetAttrs. An inverted bit map is a bit map in which the colors have been inverted; white becomes black and black becomes white. An application can draw inverted bit maps by calling WinDrawBitmap and passing it DBM_INVERT as the last argument. An application can draw halftone bit maps by calling WinDrawBitmap and passing it DBM_HALFTONE as the last argument. Before drawing the bit map, clear the presentation space to CLR_BACKGROUND using GpiErase.

GpiImage

GpiImage draws a nonstandard, monochrome (two-color) bit map called an image primitive. The bit-map bits in an image are stored in the opposite order from the bits in a standard bit map-the first bit in the bit map corresponds to the pel in the upper-left corner of the bit-map image, and the last bit in the bit map corresponds to the pel in the lower-right corner of the bit-map image. The following figure shows the correspondence between the bits in an image primitive and the pels in the drawing produced by GpiImage.

File:Img12.bmp
Image-Primitive Bits and Pels

A call to GpiImage also is valid only in draw mode (DM_DRAW), but can provide output to a screen or printer. An application cannot scale bit-map images by using GpiImage.

Transferring Bit Maps

The three remaining bit-map drawing functions operate in very similar ways. GpiDrawBits copies a bit-map image from application memory to a device or a device context. GpiBitBlt directs bit maps to devices other than the screen. GpiWCBitBlt enables you to retain the bit-map data in the segment store of the target presentation space. The similarities are discussed first. Their differences are discussed in the sections that follow. An application should use GpiDrawBits, GpiBitBlt, or GpiWCBitBlt to draw bit maps that use a color table or RGB2 structures color formats of 1, 4, 8, or 24 bits per pel. An application can draw inverted bit maps for any of these three functions by calling the function and passing ROP_NOTSRCCOPY as the raster operation.

GpiDrawBits

GpiDrawBits copies bit map image data from storage into a bit map that has been selected into a device context associated with a presentation space. It can also copy bit-map image data to a device. An application can use this function to draw a bit map without first selecting the bit map into a presentation space. This function is valid in all draw modes. Set the draw mode to DM_RETAIN or DM_DRAWANDRETAIN to create retained segments; otherwise, the default mode, DM_DRAW, is selected.

GpiBitBlt

GpiBitBlt requires an application to use device coordinates for the dimensions of the source and target rectangles. GpiBitBlt allows you to direct bit maps to devices other than the screen. It is independent of the drawing mode, but it operates as if in draw mode. At its simplest, GpiBitBlt copies a whole bit map, unaltered, from a device or bit map source to a device or bit map target. At its most powerful, GpiBitBlt can take a part of or a whole bit map, and alter both its size and appearance in the process of copying it to another device context. A bit map can be copied:

  • From one memory device context to another memory device context
  • From a memory device context to the device context of an output device (screen window or printer) that supports raster operations
  • From the device context of an output device to a memory device context
  • From the device context of an output device to another device context of the same output device. In both cases, the screen device can be a PM window.

A memory device context (whether it is the source or the target of the GpiBitBlt operation) must have a bit map selected when GpiBitBlt is called. GpiBitBlt has a number of input parameters, two of which are the handles of two presentation spaces: the source presentation space and the target presentation space. Both of these presentation spaces must be associated with an appropriate device context. Unless the associated device is a banded printer, a single presentation space can be both source and target. This allows you to copy a bit map within a single PM window, or to update the bit map. The source and target rectangles are specified in device coordinates in GpiBitBlt. GpiBitBlt, consequently, is very device-dependent, and should be avoided when creating data for interchange.

GpiWCBitBlt

GpiWCBitBlt enables you to retain the bit-map data in the segment store of the target presentation space. It is a valid in all three drawing modes:

  • DM_DRAW-display, printer, or into metafile
  • DM_RETAIN-into metafile or segment
  • DM_DRAWANDRETAIN-display, printer, then into associated segment or metafile.

Most of the bit-map drawing operations occur in an application's device space. GpiWCBitBlt, however, lets an application draw in its world space, but requires that you use device coordinates for the source rectangle, and world coordinates for the target rectangle. An application can use GpiWCBitBlt to draw a bit map with consistent dimensions on devices with different aspect ratios. The aspect ratio is the ratio of a pel's width to its height. When creating data for interchange, use GpiWCBitBlt. GpiWCBitBlt provides the same function as GpiBitBlt, with the following exceptions:

  • The target rectangle is specified in world coordinates, and all four coordinates (the two source-rectangle coordinates and the two target-rectangle coordinates) must be specified.
  • The source handle must be a bit-map handle. It must not be the handle of a source presentation space. The bit map identified by the source handle must not be selected into a memory device context when you call GpiWCBitBlt.
  • GpiWCBitBlt conforms to the current drawing mode in the target presentation space. If the drawing mode is retain or draw-and-retain, the bit map is retained in segment store.

Changing the Size of the Bit Map

You can specify the sizes of the rectangular bit blocks in both the source and the target presentation spaces. To do this, provide an array of up to four device-coordinate positions as input to the call. The first two positions define the lower-left and upper-right corners of the target rectangle; the second two define the same two corners of the source rectangle. If you want the two rectangles to be of equal size, do not specify the device coordinates of the upper-right corner of the source rectangle. The correct amount of data is automatically transferred to fill the target rectangle. The following figure shows the points count for bit-block transfers.

File:Img13.bmp
Points Count for Bit-Block Transfers

Equal-size rectangles can be built

Using Bit Maps

An application can use bit-map functions to:

  • Copy an image from a raster device (such as a display screen) to a bit map
  • Copy an image from a raster device (such as a display screen) to the same device
  • Copy an image from a bit map to a raster device
  • Copy an image from a bit map to another bit map
  • Copy an image from application memory to a bit map
  • Copy an image from application memory to a raster device
  • Scale bit-map images
  • Create custom fill patterns for area primitives and paths
  • Load a bit map created with the Icon Editor
  • Draw bit-map images
  • Store bit maps in a metafile or application memory

Copying an Image from a Display Screen to a Bit Map

To copy an image from a display screen to a bit map:

1. Associate the memory device context with a presentation space. 2. Create a bit map. 3. Select the bit map into the memory device context by calling [GpiSetBitmap](hd res=50211). 4. Determine the location (in device coordinates) of the image. 5. Call [GpiBitBlt](hd res=50018) and copy the image to the bit map.

The following figure demonstrates these steps.

HDC hdcMem;
PSZ pszData[4] = { "Display", NULL, NULL, NULL };
HPS hpsMem, hps;
HAB hab;
SIZEL sizlPage = {0, 0};
BITMAPINFOHEADER2 bmp;
PBITMAPINFO2 pbmi;
HBITMAP hbm;
SHORT sWidth = 128, sHeight = 128;
POINTL aptl[3];
LONG alData[2];

/*
 * Create the memory device context and presentation space so they
 * are compatible with the screen device context and presentation space.
 */

hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 4,
    (PDEVOPENDATA) pszData, NULLHANDLE);

hpsMem = GpiCreatePS(hab, hdcMem, &sizlPage,
    PU_PELS | GPIA_ASSOC | GPIT_MICRO);

/* Determine the device's plane/bit-count format. */

GpiQueryDeviceBitmapFormats(hpsMem, 2, alData);

/*
 * Load the BITMAPINFOHEADER2 and BITMAPINFO2 structures. The sWidth and
 * sHeight fields specify the width and height of the destination
 * rectangle.
 */

bmp.cbFix = (ULONG) sizeof(BITMAPINFOHEADER2);
bmp.cx = sWidth;
bmp.cy = sHeight;
bmp.cPlanes = alData[0];
bmp.cBitCount = alData[1];
bmp.ulCompression = BCA_UNCOMP;
bmp.cbImage = (((sWidth *
    (1 << bmp.cPlanes) * (1 << bmp.cBitCount)) + 31) / 32) * sHeight;
bmp.cxResolution = 70;
bmp.cyResolution = 70;
bmp.cclrUsed = 2;
bmp.cclrImportant = 0;
bmp.usUnits = BRU_METRIC;
bmp.usReserved = 0;
bmp.usRecording = BRA_BOTTOMUP;
bmp.usRendering = BRH_NOTHALFTONED;
bmp.cSize1 = 0;
bmp.cSize2 = 0;
bmp.ulColorEncoding = BCE_RGB;
bmp.ulIdentifier = 0;


DosAllocMem((PPVOID)&pbmi, sizeof(BITMAPINFO2) +
    (sizeof(RGB2) * (1 << bmp.cPlanes) * (1 << bmp.cBitCount)),
    PAG_COMMIT | PAG_READ | PAG_WRITE);

pbmi->cbFix = bmp.cbFix;
pbmi->cx = bmp.cx;
pbmi->cy = bmp.cy;
pbmi->cPlanes = bmp.cPlanes;
pbmi->cBitCount = bmp.cBitCount;
pbmi->ulCompression = BCA_UNCOMP;
pbmi->cbImage = ((sWidth+31)/32) * sHeight;
pbmi->cxResolution = 70;
pbmi->cyResolution = 70;
pbmi->cclrUsed = 2;
pbmi->cclrImportant = 0;
pbmi->usUnits = BRU_METRIC;
pbmi->usReserved = 0;
pbmi->usRecording = BRA_BOTTOMUP;
pbmi->usRendering = BRH_NOTHALFTONED;
pbmi->cSize1 = 0;
pbmi->cSize2 = 0;
pbmi->ulColorEncoding = BCE_RGB;
pbmi->ulIdentifier = 0;

/* Create a bit map that is compatible with the display.           */

hbm = GpiCreateBitmap(hpsMem, &bmp, FALSE, NULL, pbmi);

/* Associate the bit map and the memory presentation space.         */

GpiSetBitmap(hpsMem, hbm);

/* Copy the screen to the bit map.                                 */

aptl[0].x = 0;       /* Lower-left corner of destination rectangle  */
aptl[0].y = 0;       /* Lower-left corner of destination rectangle  */
aptl[1].x = sWidth;  /* Upper-right corner of destination rectangle */
aptl[1].y = sHeight; /* Upper-right corner of destination rectangle */
aptl[2].x = 0;       /* Lower-left corner of source rectangle       */
aptl[2].y = 0;       /* Lower-left corner of source rectangle       */

hps = WinGetScreenPS(HWND_DESKTOP);

GpiBitBlt(hpsMem, hps,
    sizeof(aptl) / sizeof(POINTL), /* Number of points in aptl      */
    aptl, ROP_SRCCOPY, BBO_IGNORE);

WinReleasePS(hps);


Scaling and Drawing a Bit-Map Image

You can scale a bit map by calling [GpiBitBlt](hd res=50018) or [GpiWCBitBlt](hd res=50273) and altering the dimensions of the target rectangle. The following figure shows how to shrink the screen copied in the first example to half its original size, and then redraw it by calling [GpiBitBlt](hd res=50018).


POINTL aptl[3];
HPS hpsMem, hps;
HWND hwnd;
SHORT sWidth = 128, sHeight = 128;
/* Target-rectangle dimensions (in device coordinates)          */
aptl[0].x = 0;
aptl[0].y = 0;
aptl[1].x = sWidth / 2;
aptl[1].y = sHeight / 2;

/* Source-rectangle dimensions (in device coordinates)          */
aptl[2].x = 0;
aptl[2].y = 0;
aptl[3].x = sWidth;
aptl[3].y = sHeight;

hps = WinGetPS(hwnd);

GpiBitBlt(hps, hpsMem,
    sizeof(aptl) / sizeof(POINTL),    /* Number of points in aptl */
    aptl, ROP_SRCCOPY, BBO_IGNORE);

WinReleasePS(hps);

Creating a Custom Fill Pattern

To create a custom fill pattern that the operating system will use to fill area primitives and paths:

  • Set an array of bits for a bit map that measures 8-bits-by-8-bits (remember that the operating system pads the bit-map bits on a ULONG (32-bit) boundary).
  • Create a bit map in a screen presentation space by calling [GpiCreateBitmap](hd res=50035) and passing it the address of the array of bits from Step 1.
  • Assign a local identifier (lcid) to the bit map by calling [GpiSetBitmapId](hd res=50214).
  • Set the attribute of the pattern set in the [AREABUNDLE](hd refid=6) structure by calling [GpiSetPattern](hd res=50253).

The following figure shows how to create the pattern.


/* Define an array of bytes;  this array creates a grid pattern. */

BYTE abPattern5[] = {
    0xFF, 0xFF, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00 };

    LONG lcidCustom = 1;
HPS hps;
PBITMAPINFO2 pbmi;
BITMAPINFOHEADER2 bmp;
HBITMAP hbm;
PRGB2 prgb2;

/* Create the bit map, passing the address of the array of bytes. */
hbm = GpiCreateBitmap(hps, &bmp, CBM_INIT, (PBYTE) abPattern5, pbmi);

/* Assign a local identifier to the bit map.                     */
GpiSetBitmapId(hps, hbm, lcidCustom);

/* Set the pattern-set attribute in the AREABUNDLE structure.     */
GpiSetPatternSet(hps, lcidCustom);

Loading a Bit Map from a File

You can load a bit map from a file if the format of the file corresponds to the standard IBM OS/2 bit-map file format. (Any bit map that you create with the Icon Editor is automatically stored in this format.) To load a bit map:

  • Copy the bit-map file to the directory that contains your application's resource file and source code.
  • Create an entry in your application's resource file, assigning a unique integer identifier to the bit map.
  • Call [GpiLoadBitmap](hd res=50074) in your application's source code, passing it the integer identifier that you assigned to the bit map in your application's resource file.

You can actually include your bit map in the application's .EXE file or in a separate resource file. If the bit map is included in a separate resource file, you must specify both the resource ID and the ID of the bit map within the resource file on [GpiLoadBitmap](hd res=50074). If the bit map is to be included in the application's .EXE file, the resource ID is specified as NULL and only the ID of the bit map is required by [GpiLoadBitmap](hd res=50074). Following is an example of code from an application's resource file that assigns the integer value 200 to a bit-map file called CUSTOM.BMP.

File:BITMAP 200 CUSTOM.BMP

The following figure is an example of code from the application that shows how to retrieve a bit-map handle by calling [GpiLoadBitmap](hd res=50074), use the handle to tag the bit map by calling [GpiSetBitmapId](hd res=50214), and then use the local identifier supplied by [GpiSetBitmapId](hd res=50214) to set the bit map as the current fill pattern, using [GpiSetPatternSet](hd res=50255).


HPS hps;
HBITMAP hbm;
LONG lcidCustom = 1;
POINTL ptl;

hbm = GpiLoadBitmap(hps,  /* Presentation-space handle        */
    NULLHANDLE,           /* Resource in application's module */
    IDB_PATTERN,          /* Bit-map ID                       */
    16,                   /* Bit-map width                    */
    16);                  /* Bit-map height                   */

/* Assign a local identifier to the bit map.                 */
GpiSetBitmapId(hps, hbm, lcidCustom);

/* Set the pattern-set attribute in the AREABUNDLE structure. */
GpiSetPatternSet(hps, lcidCustom);

ptl.x = 100;
ptl.y = 100;
GpiMove(hps, &ptl);
ptl.x = 200;
ptl.y = 200;
GpiBox(hps, DRO_OUTLINEFILL, &ptl, 0, 0);

Storing a Bit Map in a Metafile

You can draw bit maps in a metafile or segment by calling [GpiWCBitBlt](hd res=50273). The operating system converts this function to a drawing order. The target-rectangle dimensions that you pass to [GpiWCBitBlt](hd res=50273) are in world coordinates, not device coordinates. The following figure shows how to draw a bit map in a metafile, and then play the metafile.

DEVOPENSTRUC dop;
HDC hdcMeta;
HPS hps, hpsMeta;
SIZEL sizlPage;
HMF hmf;
HBITMAP hbm;
HAB hab;
HWND hwnd;
POINTL aptl[4];

dop.pszLogAddress = NULL;
dop.pszDriverName = "DISPLAY";
dop.pdriv = NULL;
dop.pszDataType = NULL;

hdcMeta = DevOpenDC(hab, OD_METAFILE, "*", 4L,
            (PDEVOPENDATA) &dop, NULLHANDLE);
hpsMeta = GpiCreatePS(hab, hdcMeta, &sizlPage, PU_PELS | GPIA_ASSOC);

hbm = GpiLoadBitmap(hpsMeta, NULLHANDLE, IDB_PATTERN, 16L, 16L);

aptl[0].x = aptl[0].y = 0; /* Lower-left corner target rectangle      */
aptl[1].x = 150;           /* X coordinate upper-right target rectangle */
aptl[1].y = 300;           /* Y coordinate upper-right target rectangle */
aptl[2].x = aptl[2].y = 0; /* Lower-left corner source rectangle      */
aptl[3].x = aptl[3].y = 16; /* Upper-right corner source rectangle      */

GpiWCBitBlt(hpsMeta, hbm, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);

GpiAssociate(hpsMeta, NULLHANDLE);
hmf = DevCloseDC(hdcMeta);

hps = WinGetPS(hwnd);

GpiPlayMetaFile(hps, hmf, 0L, NULL, NULL, 0L, NULL);

WinReleasePS(hps);

You can also store a bit map in a metafile by calling [GpiBitBlt](hd res=50018). In this case, however, the bit map will be stored inside an escape order.