Click here to Skip to main content
15,886,110 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I have a bitmap which background needs to be replaced with part of another bitmap. Everything works fine until I enable ClearFont on my WindowsXP.

In order to explain my problem better, let us label first bitmap as bmpDestination and second as bmpSource.

Here[^] is how the bmpSource looks like.

Here[^] is how bmpDestination looks like.

And here[^] is the incorrect result of their combining when ClearType is on.

ClearType alters some parts of the text background color, so they aren't white anymore ( RGB( 255, 255, 255 ) ) but a combination of white and text color.

I am using BitBlt() and monochrome bitmap to create a mask, and to simulate transparency. I have tried using TransparentBlt() too, but got the same result.

How can I combine bmpSource and bmpDestination, when ClearType is enabled, so I can create correct result ?

Thank you for your help.

Best regards.
Posted

I added this to your previous post it got messy so you probably missed it.

There are ways around it but they are all slow and give different results which you have to choose between. There is no perfect solution because it is a bug or over-sight in windows Cleartype implementation.

I played around and I came to the exact same conclusions as this author

http://theartofdev.wordpress.com/2014/04/21/text-rendering-methods-comparison-or-gdi-vs-gdi-revised/[^]

Conclusions

-GDI text rendering provides the best visual quality but doesn’t support transparent background.
-Native GDI rendering provides the best performance.
-GDI+ with anti-aliasing and typographic format provides the best performance and visual quality for transparent background rendering.
-GraphicsPath rendering method visual quality4 and performance is disappointing.
-Text rendered in each rendering method is visually different.
-As Microsoft will improve their fonts and display resolution (DPI) will raise, GDI+ text rendering will improve to a point where GDI has no significant visual benefit.
 
Share this answer
 
v4
Comments
AlwaysLearningNewStuff 11-May-14 4:43am    
I have looked at all of my posts you have answered and was not able to find the link you posted here. Also, I saw no updated content you mention. Weird... Could you please tell me where did you post this link? In which answer / comment ?

After reading through the submitted article, I believe my best bet is to create font with antialiased quality instead of ClearType and just set it as tree's font.

I have studied carefully the code from your previous answer and managed to handle WM_WINDOWPOSCHANGED properly for multiple windows but I can not handle slight flickering.

As for the subclassing article, I still am not able to download files, but I have copy/pasted the code and managed to successfully build exe. I will study the code once I deal with the treeview.

In your previous comments you offered to show me easy way of attaching/deleting the font. I am interested to learn more about it if it isn't much of a trouble for you.

So far I am creating font like this:

INT_PTR CALLBACK SomeDialogProc(...)
{
static HFONT MyFont;

// I initialize it in WM_CREATE
case WM_INITDIALOG:
{
MyFont = CreateFont(...);
}
// and I delete it in dialog's WM_DESTROY


I really hate this type of approach, but being inexperienced I have no idea about other alternatives.

Thank you for helping.

Best regards.
I have studied carefully the code from your previous answer and managed to handle WM_WINDOWPOSCHANGED properly for multiple windows but I can not handle slight flickering.

What is causing the flicker is the way the listbox draws each item you need to do you own drawing to solve the problem there are plenty of articles on listbox flicker and solving it.

Ok to do the font simply attach the font if you need to the window .. so lets look at specific code.

First make a text string we are going to call the property in out case "FONT"
//this is the property title of the FONT to attach to our window
#define TEXTPROP TEXT("FONT")

Next handle WM_FONT
case WM_SETFONT:
LOGFONT lf;
HFONT OldFont, Newfont;
GetObject((HFONT)wParam, sizeof(lf), &lf);                  // Get proposed font
if (lf.lfQuality != NONANTIALIASED_QUALITY){                // If its antialiased we can't use
	lf.lfQuality = NONANTIALIASED_QUALITY;              // So change it to non antialiased
	Newfont = CreateFontIndirect(&lf);                  // Create a new font 
	OldFont = (HFONT) GetProp(hwnd, TEXTPROP);	    // Get the old font
	if (OldFont != 0) DeleteObject(OldFont);            // If valid delete it
	SetProp(hwnd, TEXTPROP, (HANDLE)Newfont);           // Set new font to window property
} else Newfont = (HFONT) wParam;                            // Use the font provided
return ::DefSubclassProc( hwnd, WM_SETFONT, (WPARAM)Newfont, lParam); // Treat it as usual


Your responsibility to delete any font WM_SETFONT created in NCDESTROY
case WM_NCDESTROY: 
   HFONT Font = (HFONT) GetProp(hwnd, TEXTPROP);           // Fetch the font property
   if (Font != 0) DeleteObject(Font);                      // If valid delete the font 
   RemoveProp(hwnd, TEXTPROP);                             // Remove the window property   
   ::RemoveWindowSubclass(hwnd, TreeProc, 0 );
   return ::DefSubclassProc( hwnd, message, wParam, lParam);


It now handles the WM_FONT like any normal window.

Finally I put all the creation stuff into a helper function
// ** LdB Consolidate function to create a listbox and do all the repeat stuff
HWND CreateListBox (HWND parent,    // Parent window to insert this control in
		    TCHAR* title,   // List box title text
		    int x, int y,   // x,y co-ordinate of parent for the insert
		    int cx, int cy, // Width and Height of the control
		    int id,	    // Id of the control
 		    HFONT hFont) {  // Handle to any special font (0 = default)
DWORD dwStyle;
HWND TreeView;
  
   TreeView = CreateWindowEx(0, WC_TREEVIEW, title, 
		WS_VISIBLE | WS_CHILD | WS_BORDER 
		| TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT, 
		x, y, cx, cy,	parent, (HMENU)id, 0, NULL);

   dwStyle = GetWindowLong( TreeView , GWL_STYLE);
   dwStyle |= TVS_CHECKBOXES;
   SetWindowLongPtr( TreeView , GWL_STYLE, dwStyle );
   SetWindowSubclass( TreeView, TreeProc, 0, 0 );
   TreeView_SetBkColor(TreeView, RGB(0xFF, 0, 0xFF));
   // This checks font is not aliased by our handling of WM_FONT
   if (hFont == 0) hFont = (HFONT) SendMessage(TreeView, WM_GETFONT, 0, 0);
   SendMessage(TreeView, WM_SETFONT, (WPARAM)hFont, FALSE);
   return (TreeView);
};

Your creation now looks this simple
HWND TreeView = CreateListBox(hwnd, (TCHAR*)TEXT("Tree View"),
    50, 10, 200, 200, ID_LISTBOX, 0);
 
Share this answer
 
v8
Oh I forgot I further improved your redraw and made it compliant to handling WM_PRINTCLIENT itself.

case WM_PAINT:
    {
    // usual stuff
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint( hwnd, &ps );
    // Simply get printclient to paint  
    ::SendMessage(hwnd, WM_PRINTCLIENT,(WPARAM) hdc, (LPARAM)(PRF_CLIENT) ); 
    EndPaint( hwnd, &ps );
    }
    return 0L;
case WM_PRINTCLIENT:
    {
    BITMAPINFO bmi;
    // Get parent client co-ordinates
    RECT rc;
    GetClientRect(GetParent(hwnd), &rc);
    // Create a memory DC
    HDC memDC = CreateCompatibleDC(0);
    // Create a DIB header for parent
    memset(&bmi, 0, sizeof(bmi));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = rc.right - rc.left;
    bmi.bmiHeader.biHeight = rc.bottom - rc.top;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biCompression = BI_RGB;
    // Create a DIB bitmap
    HBITMAP tempBmp = CreateDIBSection(0, &bmi, DIB_RGB_COLORS, 0, 0, 0);
    // Select tempBmp onto DC to force size and DIB change on the DC
    SelectObject(memDC, tempBmp );
    // Put parent background on our memory DC
    ::SendMessage( GetParent(hwnd), WM_PRINTCLIENT, (WPARAM) memDC,  (LPARAM)(PRF_CLIENT));
    // Now we can dispose of the DIB bitmap no longer needed
    DeleteObject(tempBmp);
    // map tree's coordinates to parent window
    POINT ptTreeUL;
    ptTreeUL.x = 0;
    ptTreeUL.y = 0;
    ClientToScreen( hwnd, &ptTreeUL );
    ScreenToClient( GetParent(hwnd), &ptTreeUL );
    GetClientRect( hwnd, &rc);
    // Transfer parent background to given DC
    BitBlt((HDC)wParam, 0, 0,  rc.right-rc.left, rc.bottom-rc.top,
	memDC, ptTreeUL.x, ptTreeUL.y, SRCCOPY );
    // Okay get treeview to draw on our memory DC
    DefSubclassProc(hwnd, WM_PRINTCLIENT, (WPARAM)memDC,  (LPARAM)(PRF_CLIENT));
    // Transfer the treeview DC onto finalDC excluding pink
    TransparentBlt((HDC)wParam, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
	memDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, RGB(0xFF, 0x00, 0xFF));
    // Finished with MemDC 
    DeleteObject(memDC);
    return (0); 
}
 
Share this answer
 
Comments
AlwaysLearningNewStuff 13-May-14 7:36am    
I have successfully implemented all of your suggestions!

Furthermore, instead of using nonantialiased quality I tried to use aliased quality as a flag when creating font. Seems that everything works fine.

I just had to double buffer in printclient because you draw twice in tree's device context.

I guess there is no way to solve this problem using ClearType...
AlwaysLearningNewStuff 4-Jul-14 9:40am    
My pardon for disturbing, but I am facing an interesting problem regarding printing in WinAPI. I have searched online for a solution, but nothing came out despite my high expectations for successfully solving it on my own. Can you please take a look at the following question:

http://www.codeproject.com/Questions/791103/Calculate-ideal-font-size-based-on-the-paper-size?loginkey=false

Thank you.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900