Direct2D - Emulating Color Keyed Transparent Bitmaps
Asked Answered
U

1

6

I'm currently updating a Windows GDI application to use Direct2D rendering and I need to support "transparent" bitmaps via color-keying for backwards compatibility.

Right now I'm working with a HWND render target and a converted WIC bitmap source (to GUID_WICPixelFormat32bppPBGRA). My plan so far is to create a IWICBitmap from the converted bitmap, Lock() it, and then process each pixel setting it's alpha value to 0 if it matches the color key.

This seems a bit "brute force" - Is this the best method of approaching this or is there a better way?

Edit: In the interests of completeness here's an extract of what I went with - looks like it's working fine but I'm open to any improvements!

// pConvertedBmp contains a IWICFormatConverter* bitmap with the pixel 
// format set to GUID_WICPixelFormat32bppPBGRA

IWICBitmap* pColorKeyedBmp = NULL;
HRESULT hr    = S_OK;
UINT    uBmpW = 0;
UINT    uBmpH = 0;

pConvertedBmp->GetSize( &uBmpW, &uBmpH );

WICRect rcLock = { 0, 0, uBmpW, uBmpH };

// GetWIC() returns the WIC Factory instance in this app
hr = GetWIC()->CreateBitmapFromSource( pConvertedBmp, 
                                       WICBitmapCacheOnLoad, 
                                       &pColorKeyedBmp );
if ( FAILED( hr ) ) {
   return hr;
}

IWICBitmapLock* pBitmapLock = NULL;
hr = pColorKeyedBmp->Lock( &rcLock, WICBitmapLockRead, &pBitmapLock );
if ( FAILED( hr ) ) {
   SafeRelease( &pColorKeyedBmp );
   return hr;
}

UINT  uPixel       = 0;
UINT  cbBuffer     = 0;
UINT  cbStride     = 0;
BYTE* pPixelBuffer = NULL;

hr = pBitmapLock->GetStride( &cbStride );
if ( SUCCEEDED( hr ) ) {
   hr = pBitmapLock->GetDataPointer( &cbBuffer, &pPixelBuffer );
   if ( SUCCEEDED( hr ) ) {

      // If we haven't got a resolved color key then we need to
      // grab the pixel at the specified coordinates and get 
      // it's RGB

      if ( !clrColorKey.IsValidColor() ) {
         // This is an internal function to grab the color of a pixel
         ResolveColorKey( pPixelBuffer, cbBuffer, cbStride, uBmpW, uBmpH );
      }

      // Convert the RGB to BGR
      UINT   uColorKey = (UINT) RGB2BGR( clrColorKey.GetRGB() );
      LPBYTE pPixel    = pPixelBuffer;

      for ( UINT uRow = 0; uRow < uBmpH; uRow++ ) {

         pPixel = pPixelBuffer + ( uRow * cbStride );

         for ( UINT uCol = 0; uCol < uBmpW; uCol++ ) {

            uPixel = *( (LPUINT) pPixel );

           if ( ( uPixel & 0x00FFFFFF ) == uColorKey ) {
              *( (LPUINT) pPixel ) = 0;
           }
           pPixel += sizeof( uPixel );
        }
     }
   }
}

pBitmapLock->Release();

if ( FAILED( hr ) ) {
   // We still use the original image
   SafeRelease( &pColorKeyedBmp );
}
else {
   //  We use the new image so we release the original
   SafeRelease( &pConvertedBmp );
}

return hr;
Urogenital answered 30/1, 2013 at 18:22 Comment(0)
R
1

If you only need to "process" the bitmap to render it, then the fastest is always GPU. In Direct2D there are effects (ID2D1Effect) for simple bitmap processing. You can write your own [it seems comparatively complicated], or use one of the built-in effects [which is rather simple]. There is one called chroma-key (CLSID_D2D1ChromaKey).

On the other hand, if you need to do further processing on CPU, it gets more complex. You might be better off optimizing the code you have.

Robertoroberts answered 2/5, 2017 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.