Transparent bounding box of an ellipse - c++

I'm writing some C++ code to draw ellipses. Sometimes these ellipses could be stacked on top of each other in a grouping. When they are stacked on each other, I'd like to have the bounding box of the ellipse be transparent so that I don't see the white corners of the bounding box. See picture below.
Including the SetBkMode or not doesn't seem to make a difference. If I don't do the FillRect, I get a black background on the bounding box.
HBRUSH brush = CreateSolidBrush(RGB(255, 255, 255));
CDC *pDC = CDC::FromHandle(pSprite->hDCMem);
pDC->SetBkMode(TRANSPARENT);
pDC->FillRect(m_SpriteRect, CBrush::FromHandle(brush));
pDC->SelectObject(m_BackBrush);
pDC->Ellipse(m_SpriteRect);
pDC->SetBkMode(OPAQUE);
DeleteObject(brush);
Is there a way to set a transparent background?

If drawing on memory dc, fill the background with a transparent color, then use TransparentBlt to blit the memory dc on to final HDC. Example:
CDC *pDC = CDC::FromHandle(hDCMem);
//fill the background with transparent color
COLORREF clr_transparent = RGB(255, 255, 255); //<- randomly selected color
CBrush brush(clr_transparent);
pDC->FillRect(m_SpriteRect, &brush);
//any drawing
auto oldbrush = pDC->SelectObject(m_BackBrush);
pDC->Ellipse(m_SpriteRect);
pDC->SelectObject(oldbrush);
//transparent blit
TransparentBlt(final_hdc, x_dest, y_dest, width, height,
hDCMem, 0, 0, m_SpriteRect.right, m_SpriteRect.bottom, clr_transparent);

Related

DrawText with outline using GDI (C++)

I'm using this code to sign a frame from webcam:
Font = CreateFont(18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, "times");
...
HDC hDC = CreateCompatibleDC(NULL);
unsigned char * img = 0;
HBITMAP hBitmap = CreateDIBSection(hDC, &BMI, DIB_RGB_COLORS, (void**)&img, NULL, 0);
memcpy(img, CameraFrame.data, CameraFrame.size());
free(CameraFrame.data);
CameraFrame.data = img;
SelectObject(hDC, hBitmap);
SelectObject(hDC, Font);
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(255,255,255));
string Text = "Test";
DrawTextA(hDC, Text.c_str(), Text.size(), &rect, DT_CENTER | DT_WORDBREAK);
DeleteDC(hDC);
Of course the color scale of frames will differ, and I need the text to be visible anyway.
How to DrawText with outline? For example, white text with black outline.
Two approaches:
Draw the Text in black, but scaled slightly larger by 2 pixels (good luck) and offset by (-1,-1) then normally in white in the center.
Draw the Text in black, but offset { (-1,-1), (1,1), (-1,1), (1,-1) } and then in white in the center.
With GDI, you can use BeginPath, DrawText, EndPath, and then StrokeAndFillPath, as long as you're using an "outline" font (like TrueType or OpenType).
::BeginPath(ps.hdc);
RECT rc;
GetClientRect(&rc);
::DrawTextW(ps.hdc, L"Hello", 5, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
::EndPath(ps.hdc);
::StrokeAndFillPath(ps.hdc);
The StrokeAndFillPath will use the currently selected pen for the outline and the currently selected brush to fill it in. You can use TextOut or other GDI calls inside the BeginPath/EndPath.
You won't get any anti-aliasing like you'd have with regular text output, so it won't be as crisp as your regular ClearType text. At larger sizes, this isn't a big issue.
Here is what I would recommend:
Create a custom pen with a dashed style using CreatePen or ExtCreatePen with PS_DASH.
DrawText using DT_CALCRECT and your desired styles to see where the text will actually go.
SelectObject the HPEN from #1 into your HDC
Use MoveToEx and LineTo to draw the 4 edges of your frame based on the rectangle retrieved in #2 (adding some padding as needed). Sample code here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd145182(v=vs.85).aspx
Step 1 happens when initializing. Steps 2-4 happen each time you paint.

How to draw only black color from a bitmap image to window (filter colors out except black)

I am trying to make a Paint program that enables the user change background, while foreground color (that is used in drawing shapes) is always black.
Now, when the user changes background color, the HBRUSH paints the whole window with the chosen color and consequently clears all the shapes that were drawn.
To solve the problem I made 3 steps (note that the problem lies in the third step):
saveBeforeBackcolorChange() : a function that saves the window to bitmap before backColor is changed
FillRect(hdc, rect, color): paints the whole window with the new color
loadAfterBackcolorChanged(): ought to take only black pixels from the bitmap (which represent drawings) and consider any color transparent
Here is my implementation for the third step:
void loadAfterBackcolorChanged(HDC hdc){
ULONG_PTR m_gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
Graphics graphics(hdc);
wchar_t* filePathString = new wchar_t[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, TEMP_FILE.c_str(), -1, filePathString, 4096);
Image image(filePathString);
Gdiplus::ImageAttributes imAtt;
imAtt.SetColorKey(
Color(1, 1, 1),
Color(255, 255, 255),
ColorAdjustTypeBitmap);
graphics.DrawImage(
&image,
Rect(0, 0, image.GetWidth(), image.GetHeight()), // dest rect
0, 0, image.GetWidth(), image.GetHeight(), // source rect
UnitPixel,
&imAtt);
}
Unfortunately, the result is that it considers only white color transparent. Which means that it works well if the background is white (which is the initial backColor). Consequently the user can change backColor successfully only once!
I will be grateful if anyone could help.

When I use DirectWrite to draw text on a GDI hdc, how to set a transparent back ground?

Now I am working on a legacy product which use GDI to draw text in screen. Now I try to use DirectWrite to draw text for better appearance and accurancy of font. I am very curious that has anyone done this before?
I meet a problem that when I use DirectWrite to draw text on a GDI hdc, the background color is always white, I need a transparent background, is it possible? it seems that the SetBkMode is useless
The sample code is as below,
SetBkMode(hdc, TRANSPARENT); //hDC is the target GDI dc
SIZE size = {};
HDC memoryHdc = NULL;
memoryHdc = g_pBitmapRenderTarget->GetMemoryDC();
SetBkMode(memoryHdc, TRANSPARENT);
hr = g_pBitmapRenderTarget->GetSize(&size);
Rectangle(memoryHdc, 0, 0, size1.cx , size1.cy );
if (SUCCEEDED(hr)) {
hr = g_pTextLayout->Draw(NULL, g_pGdiTextRenderer, 0, 0);
}
BitBlt(hdc, x, y, width + 1, height + 1, memoryHdc, 0, 0, SRCCOPY | NOMIRRORBITMAP);
Default (Stock) brush for freshly created GDI device context is white solid brush, which is why you have white rectangle in output. See GetStockObject
GDI doesn't work with transparent images, BitBlt will replace all pixels inside destination rectangle in target DC. You have to copy contents of target DC destination rectangle in memory DC, then draw text and copy result back to achieve desired effect.
SetBkMode(hdc, TRANSPARENT); //hDC is the target GDI dc
SIZE size = {};
HDC memoryHdc = g_pBitmapRenderTarget->GetMemoryDC();
BitBlt(memoryHdc, 0, 0, width+1, height+1, hdc, x, y, SRCCOPY);
if (SUCCEEDED(hr)) {
hr = g_pTextLayout->Draw(NULL, g_pGdiTextRenderer, 0, 0);
}
BitBlt(hdc, x, y, width + 1, height + 1, memoryHdc, 0, 0, SRCCOPY | NOMIRRORBITMAP);
Make sure you use smallest possible update region, since moving large chunks of bitmaps in memory will surely dwindle performance.
If application uses back buffer to draw windows, memory DC of IDWriteBitmapRenderTarget could be used instead of allocating another one - in that case you solve problem of transparent text background automatically.

C++ Win32 Draw to a DC and Keeping It

I am trying to draw a simple few rectangles and store the result, I only need to draw it once. So, keeping the HDC (hdcBackround) at the top "globaly."
void drawBackground(HWND hwnd) { // hwnd is the main windows handle
// dimensions
RECT rect;
GetWindowRect(hwnd, &rect);
HDC hWinDC = GetDC(hwnd);
hdcBackground = ::CreateCompatibleDC(hWinDC); // "global"
HBITMAP hbm = ::CreateCompatibleBitmap(hWinDC, rect.right, rect.bottom);
::SelectObject(hdcBackground, hbm);
SetBkMode(hdcBackground, TRANSPARENT);
SelectObject(hdcBackground, hFont[HF_DEFAULT]);
SelectObject(hdcBackground, hBrush[HB_TOPBG]);
SelectObject(hdcBackground, hPen[HP_THINBORDER]);
// draw
Rectangle(hdcBackground, 0, 0, rect.right, 20);
SelectObject(hdcBackground, hBrush[HB_LOWBG]);
Rectangle(hdcBackground, 50, 20, rect.right, 40);
// ??? clean up after it works
ReleaseDC(hwnd, hWinDC);
}
I call that function once, and in a timer I BitBlt() hdcBackground to the screens HDC. When I test it out, it draws both the rectangles, with a 1px border (as the pen is set as,) but there is no color, it is just black and white.
The brushes and such are all fine, it is just that I am not getting color. The RGB on the brushes are (25,25,25) and (65,65,65), dark grey.
Any ideas?
Thanks.

How to draw text with transparent background using c++/WinAPI?

How to draw text with transparent color using WinAPI?
In usual way I used SetBkMode(hDC, TRANSPARENT), but now I need to use double buffer.
In this way images draws correct, but text draws not correct (with black background).
case WM_PAINT:
{
hDC = BeginPaint(hWnd, &paintStruct);
SetBkMode(hDC, TRANSPARENT);
HDC cDC = CreateCompatibleDC(hDC);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);
HANDLE hOld = SelectObject(cDC, hBmp);
HFONT hFont = (HFONT)SelectObject(hDC, font);
SetTextColor(cDC, color);
SetBkMode(cDC, TRANSPARENT);
TextOut(cDC, 0, 0, text, wcslen(text));
SelectObject(cDC, hFont);
BitBlt(hDC, 0, 0, width, height, cDC, 0, 0, SRCCOPY);
SelectObject(cDC, hOld);
DeleteObject(hBmp);
DeleteDC(cDC);
EndPaint(hWnd, &paintStruct);
return 0;
}
SetBkMode(dc, TRANSPARENT) should work fine still. Make sure you're using the correct DC handle when drawing to your back buffer.
When you create a bitmap, the color isn't specified. The documentation doesn't state how it's initialized, but solid black (all zeros) seems likely. Since you're drawing the text on the bitmap, the background of the bitmap remains black. You then copy the entire bitmap to the DC and all the pixels come along, the background along with the text.
To fix this you must copy the desired background into the bitmap before you draw the text.