Color Depth Conversion Using GDI

Home | Up | Search | X-Zone News | Services | Book Support | Links | Feedback | Smalltalk MT | The Scrapyard | FAQ | Technical Articles

 

Written by Robert Dunlop
Microsoft DirectX MVP

In DirectDraw applications, it will often be necessary to load bitmaps that do not match the color depth of the screen. With a growing number of available pixel formats, and no way to know what new formats the future may hold, this leaves us with a bit of a problem - How to convert the color depth of an image, in such a way that we can insure compatibility with a wide range of hardware?

The easiest way to achieve this is by using the graphics functions provided by Window - GDI. While these routines are slower than DirectDraw operations, they provide an easy means to convert your images to match the pixel format of the screen. And if we do this conversion when loading the image there is no impact to the performance, as it never needs to be repeated unless we change the pixel format of the display.

The function provided below loads an image from a bitmap file, creates an offscreen surface that matches the pixel format of the primary surface, and copies the image to the surface. Optionally, the function can set the key color for the offscreen surface as well. Some additional notes on this function:

  1. The function assumes that a DirectDraw4 object has been created and a pointer is stored in the external variable lpDD.
  2. The function creates an offscreen surface, which you can then use for later blitting. When you are finished with the surface, you must release the surface in your application.
  3. This function does not convert the pixel format of the color key.

LPDIRECTDRAWSURFACE4 bitmap_surface(LPCTSTR file_name, DWORD *keycolor = NULL)
{
    HDC hdc;
    HBITMAP bit;
    LPDIRECTDRAWSURFACE4 surf;

    // load the interface bitmap

    bit = (HBITMAP)LoadImage(NULL,file_name,IMAGE_BITMAP,
                             0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);

    // return if we failed to load the bitmap

    if (!bit)

        return NULL;

    // get bitmap dimensions

    BITMAP bitmap;
    GetObject(bit,sizeof(BITMAP),&bitmap);
    int surf_width=bitmap.bmWidth;
    int surf_height=bitmap.bmHeight;

    // create surface

    HRESULT ddrval;
    DDSURFACEDESC2 ddsd;
    ZeroMemory(&ddsd,sizeof(ddsd));
    ddsd.dwSize = sizeof(DDSURFACEDESC2);
    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth = surf_width;
    ddsd.dwHeight = surf_height;

    // attempt to create surface

    ddrval=lpDD->CreateSurface(&ddsd,&surf,NULL);

    // created ok?

    if (ddrval!=DD_OK) {

        // no, clear pointer

        surf=NULL;

    } else {

        // yes, get a DC for the surface

        surf->GetDC(&hdc);

        // generate a compatible DC

        HDC bit_dc=CreateCompatibleDC(hdc);

        // blit the interface to the surface

        SelectObject(bit_dc,bit);
        BitBlt(hdc,0,0,surf_width,surf_height,bit_dc,0,0,SRCCOPY);

        // release the DCs

        surf->ReleaseDC(hdc);
        DeleteDC(bit_dc);

        // set up the color key

        if (keycolor) {

            DDCOLORKEY key;
            key.dwColorSpaceLowValue=*keycolor;
            key.dwColorSpaceHighValue=*keycolor;
            surf->SetColorKey(DDCKEY_SRCBLT,&key);

        }

    }

    // unload bitmap

    DeleteObject(bit);

    // return pointer to caller

    return surf;
}

This site, created by DirectX MVP Robert Dunlop and aided by the work of other volunteers, provides a free on-line resource for DirectX programmers.

Special thanks to WWW.MVPS.ORG, for providing a permanent home for this site.

Visitors Since 1/1/2000: Hit Counter
Last updated: 07/26/05.