65.9K
CodeProject is changing. Read more.
Home

Load an HBITMAP into SFML sf::Image container

Jan 14, 2013

CPOL
viewsIcon

16804

Use the standard GDI API to load an HBITMAP into SFML.

Introduction

A simple function to load a bitmap in Win32 GDI to be used by the Sprite-class for SFML.

Using the code

The code is a simple function that you can copy and paste into your Win32 project:

//////////////////////////////////////////////////////////////////////////
// Function created by: Lars Werner - http://lars.werner.no
//////////////////////////////////////////////////////////////////////////
// Inputs:    [in] HBITMAP hBitmap = A HBITMAP handle
//            [out] sf::Image *pPicture = A image in SFML as pointer
//
//////////////////////////////////////////////////////////////////////////
// Return:    True if loaded, False if not!
//            The pPicture is the variable set and to be used further on
//////////////////////////////////////////////////////////////////////////
// Version: 1.0 = Inital Release
//////////////////////////////////////////////////////////////////////////
bool SFMLLoadHBitmapAsImage(HBITMAP hBitmap, sf::Image *pPicture)
{
    //Create a DC to get hBitmap information
    HDC hDC = GetDC( ::GetDesktopWindow() );
 
    //Create BITMAPINFO variable, set size 
    BITMAPINFO MyBMInfo = {0};
    MyBMInfo.bmiHeader.biSize = sizeof( MyBMInfo.bmiHeader );
 
    //Get the BITMAPINFO structure from the bitmap
    if( 0 == GetDIBits(hDC, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
    {
        // error handling
        return false;
    }
 
    //Create the bitmap pixel array each element is [b,g,r]
    BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
 
    //Setting up the structure of the buffer to be received
     MyBMInfo.bmiHeader.biCompression = BI_RGB;  // No-compression
 
    //Now get the actual data from the picture
    if (0 == GetDIBits(hDC, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS))
    {
        // error handling
        return false;
    }
 
    //Now create an array of SFML pixels we want to fill
    sf::Uint8 *lpPixelWithAlpha = new sf::Uint8[ MyBMInfo.bmiHeader.biSizeImage + 
          (MyBMInfo.bmiHeader.biSizeImage/3)/3 ]; //Add room for alpha
 
    //Loop through each pixel, with steps of four RGBA!
    for(int x=0;x<MyBMInfo.bmiHeader.biSizeImage;x+=4)
    {
        lpPixelWithAlpha[x] = lpPixels[x+2];    //lpPixels = r
        lpPixelWithAlpha[x+1] = lpPixels[x+1];    //lpPixels = g
        lpPixelWithAlpha[x+2] = lpPixels[x];    //lpPixels = b
        lpPixelWithAlpha[x+3] = 255;        //Nada alpha (just to adjust if you like)
    }
 
    //Remove old DIBsection
    delete[] lpPixels;
 
    //Load picture, now with correct pixels and alpha channel
    if( false == pPicture->LoadFromPixels(MyBMInfo.bmiHeader.biWidth, 
                  MyBMInfo.bmiHeader.biHeight, lpPixelWithAlpha))
    {
        // error handling
        return false;
    }
 
    //Remove the pixels with alphachannel
    delete[] lpPixelWithAlpha;
 
    //Release the DC
    ReleaseDC(::GetDesktopWindow(), hDC);
 
    //Notify ok!
    return true;
} 

To use the function in your load-procedure, use it like this. Note that the Screenshot function can be located here.

//Create a container for the picture
sf::Image m_mypicture;
 
//Get a HBITMAP (see function from before)
HBITMAP hBitmap = ScreenShot( http://lars.werner.no/?p=627 <--- function and parameters here );
 
//Run the function
if( false == SFMLLoadHBitmapAsImage(hBitmap, &my_picture) )
{
// error handling
}
 
//Load your image into the sprite
sf::Sprite m_mysprite.SetImage(m_mypicture);
 
//The DIB section begins with the last pixels at the beginning.
//Since SFML have flip-functions I didn't care to fix it :)
m_mysprite.FlipY(true); 

Got any other ways to do this? Please comment. If other formats are needed, an integration with GDI+ could be made, it natively supports PNG, GIF, JPG, etc...

History   

  • v1.0 - First release (and probably the only release).