::TransparentBlt not working properly - c++

I am using ::TransparentBlt to paint a bmp with transparent pixels marked by Magenta RGB(255, 0, 255), but ::TransparentBlt is not behaving properly, some pixels which shouldn't be transparent are transparent in the result.
What am I doing wrong ?
Original Image :
Result from ::TransparentBlt
The grey area in the result image is background image on top of which the original bmp is ::TransparentBlt-ed
Code:
LRESULT jItems::paint ( )
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
::GetClientRect ( hwnd , &rect ) ;
hdc = ::BeginPaint ( hwnd , &ps ) ;
HDC dcSkin = ::CreateCompatibleDC ( hdc ); // memory dc for skin
HDC hMemDc = ::CreateCompatibleDC ( hdc ); // memory dc for painting
HBITMAP hmemBmp = ::CreateCompatibleBitmap ( hdc, rect.right - rect.left, rect.bottom - rect.top ); // Create bitmap to draw on
HBITMAP hOldMemBmp = ( HBITMAP ) ::SelectObject ( hMemDc, hmemBmp ); // select memory bitmap in memory dc
HBITMAP hOldSkinBmp = ( HBITMAP ) ::SelectObject ( dcSkin, this->hbitmap ); //select skin bitmap in skin memory dc
::FillRect ( hMemDc, &rect, ::CreateSolidBrush ( backgroundColor ) );
::BitBlt ( hMemDc, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, dcSkin, 0, 0, SRCCOPY ); // Paint Skin on Memory DC
::SelectObject ( dcSkin, bottomEdge ); // select edge bitmap in skin memory dc
::TransparentBlt ( hMemDc, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, dcSkin,
0, 0, 237, 10, RGB ( 255, 0, 255 ) ); // Paint edge on Memory DC
::BitBlt ( hdc, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, hMemDc, 0, 0, SRCCOPY ); // Paint Skin on Window DC
//<<<... DeleteDC will leak memory if it holds a resource, so lets select the old bitmap back in the memory DCs
::SelectObject ( hMemDc, hOldMemBmp ); // select old bitmaps back to their respective DCs before deleting
::SelectObject ( dcSkin, hOldSkinBmp ); // select old bitmaps back to their respective DCs before deleting
::DeleteObject ( hOldSkinBmp );
::DeleteObject ( hOldMemBmp );
::DeleteObject( hmemBmp );
::DeleteDC ( hMemDc );
::DeleteDC ( dcSkin );
::EndPaint ( hwnd , &ps ) ;
return 0;
};

From the TransparentBlt documentation.
If the source and destination rectangles are not the same size, the source bitmap is stretched to match the destination rectangle.
In your call to TransparentBlt the destination rectangle has size (rect.right - rect.left, rect.bottom - rect.top) and the source rectangle has size (237, 10). So the bitmap is stretched and you don't get the result you expected.
I guess both sizes should be (237, 10).

Related

Creating a new bitmap with given dimensions filled with given color

I'm creating a program using the Win32 API, and I need to create a new bitmap filled with one color and with given dimensions.
Here is my code:
m_hBitmap =( HBITMAP ) CreateCompatibleBitmap(hDC, iWidth, iHeight);
HDC hDCn = CreateCompatibleDC( hDC );
SelectObject( hDCn, m_hBitmap );
ExtFloodFill(hDCn, 0, 0, crColor, FLOODFILLSURFACE);
DeleteDC( hDCn );
The bitmap dimensions match, but the bitmap is always black regardless of the crColor parameter.
Use FillRect() instead of ExtFloodFill().
Also, you need to de-select the bitmap before you delete the DC, otherwise the original bitmap created and selected into the DC by CreateCompatibleDC() will be leaked.
Try this:
m_hBitmap = CreateCompatibleBitmap(hDC, iWidth, iHeight);
HDC hDCn = CreateCompatibleDC(hDC);
HBITMAP hOld = (HBITMAP) SelectObject(hDCn, m_hBitmap); // <-- SAVE OLD BITMAP!
//ExtFloodFill(hDCn, 0, 0, crColor, FLOODFILLSURFACE);
RECT r;
r.left = r.top = 0;
r.right = iWidth;
r.bottom = iHeight;
HBRUSH hBrush = CreateSolidBrush(crColor);
FillRect(hDCn, &r, hBrush);
DeleteObject(hBrush);
SelectObject(hDCn, hOld); // <-- RESTORE OLD BITMAP
DeleteDC(hDCn);

SetDIBits fails on WM_PAINT when trying to draw

I am trying to draw plot using matrix, where each element is DWORD value, that represent pixel ARGB value. Idea behind the application is that one separate thread do the calculation (mat. formula), whose result will be the matrix with ARGB values. When WM_PAINT is raised I will use function to draw, using the filled matrix:
void DrawImage( HDC hDC, WORD wWidth, WORD wHeight )
{
HBITMAP hBitmap;
HDC hMemDC;
BITMAPINFO bi;
int iSize = sizeof( BITMAPINFO );
memcpy( &bi, dwBytes + 3, iSize);
hBitmap = CreateCompatibleBitmap(hDC, wWidth, wHeight);
hMemDC = CreateCompatibleDC( hDC );
if ( 0 == SetDIBits( hDC, hBitmap, 0,
wHeight, dwBytes, &bi, DIB_RGB_COLORS ) )
{
// error MSDN http://msdn.microsoft.com/en-us/library/
//windows/desktop/dd162973%28v=vs.85%29.aspx
}
hBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap);
BitBlt(hDC, 0, 0, wWidth, wHeight, hMemDC, 0, 0, SRCCOPY);
DeleteObject(SelectObject(hMemDC, hBitmap));
DeleteDC(hMemDC);
}
so, when WM_PAINT is raised:
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hDC = BeginPaint( hWnd, &ps );
DrawImage( hDC, iWidth, iHeight );
EndPaint( hWnd, &ps );
return 0L;
}
but nothing happens. The area is black. When SetDIBits returns 0 it means that "One or more of the input parameters is invalid" according to MSDN. I am out of ideas..
sizeof( BITMAPINFO ) includes only 1 pixel. BITMAPINFO is a variable-length structure so you need to compute its size dynamically and allocate sufficient memory dynamically.
You pointed me to investigate handling BITMAPINFO structure, and there it was. After I have changed one plane, 32 bits per pixel and width 800 and height 600 - it worked!
void DrawImage( HDC hDC, WORD wWidth, WORD wHeight )
{
HDC hMemDC;
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biHeight = 600;
bmi.bmiHeader.biWidth = 800;
bmi.bmiHeader.biPlanes = 1;
hMemDC = CreateCompatibleDC( hDC );
HBITMAP hBitmap = CreateDIBSection( hMemDC, &bmi, DIB_RGB_COLORS,
(void**) &dwBytes, NULL, 0);
SetDIBits( hDC, hBitmap, 0, wHeight, dwBytes, &bmi, DIB_RGB_COLORS );
HBITMAP hOldBitmap = (HBITMAP) SelectObject( hMemDC, hBitmap );
BitBlt(hDC, 0, 0, wWidth, wHeight, hMemDC, 0, 0, SRCCOPY);
SelectObject( hMemDC, hBitmap );
DeleteObject( hBitmap );
DeleteDC(hMemDC);
}
I got proper result:

Drawing a child window on top of another child window?

I have different screens serving different purposes in my win32 app, each screen having a different background. The main window have its own static background.
I am drawing screen background on a custom window using following code.
panelBackground = LoadBitmap ( hInstance, MAKEINTRESOURCE ( bitmap ) );
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "jPanel";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;// | CS_HREDRAW | CS_VREDRAW;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ( HBRUSH ) GetStockObject( BLACK_BRUSH );
RegisterClassEx (&wincl);
hwnd = CreateWindowEx ( 0, "jPanel", txt.c_str(), WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0) ;
SetWindowLong( hwnd , 0 , ( LONG ) this ) ;
SetWindowPos ( hwnd , HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ) ;
Then in the WndProc :
view::jPanel* panel = ( view::jPanel* ) GetWindowLong( hwnd , 0 ) ;
case WM_PAINT:
{
if ( ! panel )
return 0 ;
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
GetClientRect( hwnd , &rect ) ;
hdc = BeginPaint( hwnd , &ps ) ;
HDC dcSkin = CreateCompatibleDC ( hdc ); // memory dc for skin
HDC hMemDc = CreateCompatibleDC ( hdc ); // memory dc for painting
HBITMAP hmemBmp = CreateCompatibleBitmap ( hdc, rect.right - rect.left, rect.bottom - rect.top ); // Create bitmap to draw on
HBITMAP hOldMemBmp = (HBITMAP)SelectObject ( hMemDc, hmemBmp ); // select memory bitmap in memory dc
HBITMAP hOldSkinBmp = (HBITMAP)SelectObject ( dcSkin, panel->panelBackground ); //select skin bitmap in skin memory dc
BitBlt ( hMemDc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dcSkin, 0, 0, SRCCOPY ); // Paint Skin on Memory DC
BitBlt ( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hMemDc, 0, 0, SRCCOPY ); // Paint Skin on Window DC
//<<<... DeleteDC will leak memory if it holds a resource, so lets select the old bitmap back in the memory DCs
SelectObject ( hMemDc, hOldMemBmp ); // select old bitmaps back to their respective DCs before deleting
SelectObject ( dcSkin, hOldSkinBmp ); // select old bitmaps back to their respective DCs before deleting
DeleteObject ( hOldSkinBmp );
DeleteObject ( hOldMemBmp );
DeleteObject( hmemBmp );
DeleteDC ( hMemDc );
DeleteDC ( dcSkin );
EndPaint( hwnd , &ps ) ;
}
break ;
Problem : The child windows(buttons, edit controls) belonging to that screen don't show up, I am guessing
that they are below the screen background window. Moving the controls up the z-order with WS_EX_TOPMOST style doesn't work neither moving the screen background window at the bottom of z-order with SetWindowPos ( hwnd , HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ) ; works.
And yes buttons are BS_BITMAP styled.
Add the WS_CLIPCHILDREN style when you create the parent window.

How to display text in system tray icon with win32 api C++ - part 2

I have a question similar to this, How to display text in system tray icon with win32 API?
I tried his solution but it's not working for me. I get a small 4x16 white image as the system icon instead of text and I can't understand why.
I'm not using MFC/.NET just win32 api.
void UpdateIcon(HWND hWnd){
NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 100;
nid.hIcon = CreateSmallIcon(hWnd);
nid.uFlags = NIF_ICON;
Shell_NotifyIcon(NIM_MODIFY, &nid);
}
HICON CreateSmallIcon( HWND hWnd )
{
static TCHAR *szText = TEXT ( "100" );
HDC hdc, hdcMem;
HBITMAP hBitmap = NULL;
HBITMAP hOldBitMap = NULL;
HBITMAP hBitmapMask = NULL;
ICONINFO iconInfo;
HFONT hFont;
HICON hIcon;
hdc = GetDC ( hWnd );
hdcMem = CreateCompatibleDC ( hdc );
hBitmap = CreateCompatibleBitmap ( hdc, 16, 16 );
hBitmapMask = CreateCompatibleBitmap ( hdc, 16, 16 );
ReleaseDC ( hWnd, hdc );
hOldBitMap = (HBITMAP) SelectObject ( hdcMem, hBitmap );
PatBlt ( hdcMem, 0, 0, 16, 16, WHITENESS );
// Draw percentage
hFont = CreateFont (12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
TEXT ("Arial"));
hFont = (HFONT) SelectObject ( hdcMem, hFont );
TextOut ( hdcMem, 0, 0, szText, lstrlen (szText) );
SelectObject ( hdc, hOldBitMap );
hOldBitMap = NULL;
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = hBitmapMask;
iconInfo.hbmColor = hBitmap;
hIcon = CreateIconIndirect ( &iconInfo );
DeleteObject ( SelectObject ( hdcMem, hFont ) );
DeleteDC ( hdcMem );
DeleteDC ( hdc );
DeleteObject ( hBitmap );
DeleteObject ( hBitmapMask );
return hIcon;
}
I don't have windows installed currently so i cannot check if this will work better, but i found potential problem - from MSDN documentation of CreateIconIndirect function:
The application must continue to manage the original bitmaps and delete them when they are no longer necessary.
Seems like you are deleting bitmaps too soon.
You need to set background and possibly foreground colors:
SetTextColor( hdcMem, 0x00FF0000 ); // 0x00bbggrr, not rrggbb !!
SetBkMode( hdcMem, TRANSPARENT ); // VERY IMPORTANT
I think DeleteDC ( hdc ); is not needed here as you used GetDC().

How to save the client area of a child Window to a Bitmap file?

I have created a windows application using core WIN32 and VC++. In my parent window I have a child window and two buttons "save" and "send".
When user clicks the "save" button I want the savefileDialog to be opened and user should be able to save the image as a bitmap file.
The same file should be sent to a remote user using WinSock API.... My problem is, I don't know how to save the screen shot of the window to a bitmap file...
please help me out of this ... I have not used MFC, ATL or WTL....
thanks in advance,
RECT rect = {0};
GetWindowRect( hwnd, &rect );
ATL::CImage* image_ = new CImage();
image_ -> Create( rect.right - rect.left, rect.bottom - rect.top, 32 );
HDC device_context_handle = image_ -> GetDC();
PrintWindow( hwnd, device_context_handle, PW_CLIENTONLY );
image_ -> Save( filename );
image_ -> ReleaseDC();
delete image_;
PrintWindow() should do the trick.
To save as HBITMAP:
HDC hDC = GetDC( hwnd );
HDC hTargetDC = CreateCompatibleDC( hDC );
RECT rect = {0};
GetWindowRect( hwnd, &rect );
HBITMAP hBitmap = CreateCompatibleBitmap( hDC, rect.right - rect.left,
rect.bottom - rect.top );
SelectObject( hTargetDC, hBitmap );
PrintWindow( hwnd, hTargetDC, PW_CLIENTONLY );
SaveBMPFile( filename, hBitmap, hTargetDC, rect.right - rect.left,
rect.bottom - rect.top );
DeleteObject( hBitmap );
ReleaseDC( hwnd, hDC );
DeleteDC( hTargetDC );
I will leave the implementation of SaveBMPFile up to you ; )