How to get real text dimensions when ClearType is on? - windows

I have a Win32 GUI application that uses GDI havily. It needs to draw text over a bitmap at specified coordinates and later erase it and substitute with the original bitmap.
I proceed as follows:
select font (GetStockObject( DEFAULT_GUI_FONT)), brush, other stuff into the device context
call GetTextExtentPoint32() to compute the size of the text
now having the text starting point I can compute the expected text rectangle and store it
call TextOut() for the same device context with the same starting point and the same text
and later restore the bitmap for the store rectangle.
It works fine when ClearType antialiasing is off. But with ClearType on the size returned by GetTextExtentPoint32() is slightly smaller than the size actually occupied by the text when TextOut() is called. So when I later restore the original bitmap some small stripes of the text remain in place and I have artifacts.
Is there any cure to this without disabling ClearType?

You could also try DrawText with DT_CALCRECT to compute the string size. Maybe it works better.
Also you can then write the string with DrawText inside a rectangle with the sizes equal to the one you get with DT_CALCRECT and it will clip the text in case it is a bit larger.

Related

How does bitmaps draw pixel on window?

So I followed a few tutorials on how to draw on window using windows.h library, the part of the tutorial that I don't really understand is the bitmap part. They used createbitmap() and StrechBit() functions to draw on window. Do window references bitmap to draw pixels on the screen accordingly and bitmap is basically a chunk of memory large enough to store pixel's position and color value. If so, does bitmap automatically generate every time you created a window, because it seems that you don't really need to declare bitmap or use createbitmap() functions to type word on the window you created, you only need to create bitmap when you want to draw a custom pixel.
A window will receive the WM_PAINT message when it needs to be painted. This can happen because InvalidateRect was called, the window was resized etc.
Where the pixels are stored ("in" the HWND) is an implementation detail you don't have to worry about. On some versions/configurations the GDI functions are hardware accelerated and the result might be stored directly in the GPU, in others everything might be implemented in software and run on the CPU. When using a layered window I'm guessing everything older than Vista will use an internal bitmap to store the pixels.
GDI/GDI+ is the classic way to draw windows. If you need per-pixel alpha transparency you would draw to a bitmap and call UpdateLayeredWindow, otherwise you would just draw using any GDI function you want in WM_PAINT. This might include drawing one or several bitmaps, text, and lines/curves directly to the HWNDs HDC. As this can cause flicker in certain cases (if any area is drawn to more than once in one paint cycle), so people might draw to their own bitmap first and then BitBlt this bitmap to the window, this is called double-buffering.
The new way to draw is Direct2d/DirectComposition.

StretchBlt a bitmap without overwriting what's already drawn at the destination

I have a drawing application that draws many lines, polygons etc. on a device context. I'm also drawing background bitmaps that come from an external source and take a long time to load.
When drawing a new frame I first start threads that load the bitmaps, then draw my vector data, and at the end would like to draw the loaded bitmaps while preserving the vector data. I need the bitmaps "under" the vector data but I can't draw them first because they're not loaded, and waiting for them to load would slow things down a lot.
My idea was to apply the "bitmap with transparency" technique:
Copy the portion of my device context that would be covered by
the bitmap into a monochrome image, anything drawn with the
background color should be drawn on, everything else is off-limits.
Copy the image over the bitmap (with the proper ROP code) to mark
what needs to be transparent in the bitmap
StretchBlt the modified bitmap onto the device context
The bitmap needs to be transformed to fit properly on my device context, so I use SetWorldTransform to apply an affine transformation to my device context. The transformation has both a rotation and a shear.
Unfortunately, this fails at step 1 because, as per the documentation of StretchBlt:
If the source transformation has a rotation or shear, an error occurs.
Now, I did try setting the inverse transformation on my monochrome DC, which would transform my sheared data into a proper rectangle, but the function still fails.
So I guess my question is: how do I bitblit a raster image without deleting my data (a function where I give a transparent color in the destination, not the source, would be perfect), OR is there an easy way to extract the color data from a device context that has a rotate and shear transform on it?

Using Win32 TextOut to draw text at an angle

I'm using GDI to draw text onto a device context, and I noticed that the kerning or character placement is different if the angle is exactly 0, 90, 180, or 270. As soon as I increase the angle by 1, the character placement differs noticeably.
Rather than creating an HFONT with the angle, I am using ModifyWorldTransform to transform the device context's world coordinates, and then I use TextOut to draw the text onto the device context.
I think that GDI is using font hints or some other special technique when the text is being drawn at exact multiples of 90 degrees, but not for any other angle.
Is there a way to disable this hinting, so that text rendered at 0 degrees does not differ significantly from text rendered at 1 degree?
Here's an example of what I mean (Monotype Corsiva font):
0 degrees:
1 degree:
For some fonts, such as Arial or Tahoma, it is not as noticeable, but I would like to get rid of the difference entirely, even if it means the text is not rendered as best it can.
I think this is due to anti-aliasing rather than font hints. You could try the following:
Disable (font) AA, but this will not yield acceptable results.
Create font handles for every possible angle and see if the problem persists. I assume it doesn't, but it's not a pretty solution.
Render the text to a bitmap (e.g. using CreateCompatibleBitmap() ) render the text to it and then render the rotated bitmap. This depends on how often you need different rotations / different text.
Play with fdwOutputPrecision and fdwQuality in CreateFont(). This could be the easiest solution, but you'd have to experiment a little bit I guess.
hth

Transparency to text in GDI

i have created a Bitmap using GDI+.I am drawing text on to that bitmap using GDI Drawtext.Using Drawtext i am unable to apply tranparency.
Any help or code will be appreciated.
If you want to draw text without a background fill, SetBkMode(hdc,TRANSPARENT) will tell GDI to leave the background when drawing text.
To actually render the foreground color of the text with alpha... is going to be more complicated. GDI does not actually support alpha channels all that widely in its APIs. Outside of AlphaBlend actually all it does is preserve the channel. Its actually not valid to set the upper bits of a COLOREF to alpha values as the high byte is actually used for flags to indicate whether the COLOREF is (rather than an RGB value) a palette entry.
So, unfortunately, your only real way forward is to:
Create a 32bit DIBSection. (CreateDIBSection). This gives you an HBITMAP that is guaranteed to be able to hold alpha information. If you create a bitmap via one of the other bitmap creation functions its going to be at the device colordepth that might not be 32bpp.
DrawText onto the DIBSection.
When you created the DIBSection you got a pointer to the actual memory. At this point you need to go through the memory and set the alpha values. I don't think that DrawText is going to do anything to the alpha channel by itself at all. Im thinking a simple check of the RGB components of each DWORD of the bitmap - if theyre the forground color, rewrite the DWORD with a 50% (or whatever) alpha in the alpha byte, if theyre the background color, rewrite with a 100% alpha in the alpha byte. *
AlphaBlend the bitmap onto the final destination. AlphaBlend requires the alpha channel in the source to be pre-multiplied.
*
It might be sufficient to simply memset the DIBSection with a 50% alpha before doing the DrawText, and ensure that the BKColor is black. I don't know what DrawText might do to the alpha channel though. Some experimentation is called for.
SIMPLE and EASY solution:)
Had this problem, i tried to change alpha values and premultiply, but there was another problem - antialiased and cleartype fonts where not shown correctly (ugly edges). So what i did...
Compose your scene (bitmaps, graphics, etc.)
BitBlt required rectangle from this scene (same as your text rectangle, from the place where you want your text to be) to memory DC with compatible bitmap selected at 0,0 destination coordinates
Draw Your text to that rectangle in memory DC.
Now AlphaBlend that rectangle without AC_SRC_ALPHA in the BLENDFUNCTION and with desired SourceConstantAlpha from this memory DC back to your scene DC.
I think You got it :)
Hmmmm - trying to do same here - wondering - I see that when you create a dib section youi specify the "masks" that is a R,G,B (and alpha) mask.
IF and thats a big if it really does not alter the alpha chhannel, then you might specify the mask differently for two bitmap headers. ONe specifies thr RGB in the proper places, the other makes them all have their bits assigned to the alpha channel. (set the text color to white in this case) then render in two passes, one to load the color values, the other to load the alpha values.
???? anyway just musing :)
While this question is about making text semi-transparent, I had the opposite problem.
DrawText was making the text in my layered window (UpdateLayeredWindow) semi-transparent ... and I didn't want it to be.
Take a look at this other question ... since in the other question I post some code that you could easily modify ... and is almost exactly what Chris Becke suggests in his answer.
A limited answer for a specific situation:
If you have a graphic with alpha channel and you want to draw opaque text over a locally opaque background, first prepare your 32 bit bitmap with 32 bit brushes created with CreateDIBPatternBrushPt. Then scan through the bitmap bits inverting the alpha channel, draw your text as you normally would (including SetBkMode to TRANSPARENT), then invert the alpha in the bitmap again. You can skip the first inversion if you invert the alpha of your brushes.

How to draw a selected text in win32 using only gdi call?

I tried to draw a selected text using two TextOut call and TA_UPDATECP flag but when I move the selected area, the characters are moving a bit.
Does someone know the correct way to do that ?
According to the MSDN documentation, when you have set the TA_UPDATECP flag using SetTextAlign(), TextOut() ignores its position parameters in favor of the device context's current position. Without seeing your code, I suspect that your drawing algorithm calls TextOut() with a current position that differs slightly based on the selection.
As a debugging strategy, you can call GetCurrentPositionEx() just before you call TextOut() to obtain the current position and make sure it matches your expectation for where the text should be drawn.
I believe that antialiasing and ClearType can draw text at fractional pixel positions. If you draw a string of text, and then try to redraw a portion of the middle, there might not be a way for you to draw text starting at exactly the same position as those characters in the middle. The trick seems to be to redraw the entire string, but with a clipping region for the selected text.
Chapter 4 in this tutorial on writing a Win32 text editor goes into quite some detail on how to draw selected text.

Resources