[RESOLVED] PictureBox, etc. and Non-smoothed Fonts
Does anyone know of any pre-built VB6 code to create a font with no smoothing (neither ClearType nor greyscale) and select it into the hDC of a Form, PictureBox, etc.?
Ideally I'd want to be able to use the Print pseudo-method after setting the font as well as DrawText/DrawTextEx but I could live with just using the APIs to print if that becomes an issue.
I don't want to disable ClearType or smoothing globally, just on particular "canvases" within a program.
This looks pretty easy but might take some tweaking, so I was hoping somebody had some tested code already that is close to "drop-in ready." Searches haven't turned anything up yet.
I'm writing a program that does some text rendering with highlights, shadows and such and the anti-aliasing is troublesome.
Well I know I need to use CreateFont(), SelectFont(), and DeleteObject() calls but I was pretty sure the rest of that stuff isn't required because the PictureBox.hDC is already set up.
I suppose what I was looking for was a simple "set this PictureBox's Font to face X, size Y, and weight Z with no smoothing" operation.
Thanks for the effort though, it's more than I was finding on my own in the way of pre-existing VB examples. I'll work with this myself and see what I can put together.
That guy seemes to have been doing all sorts of nutty redundant things, almost as if he just "transliterated" a C example blindly w/o understanding it. We'll see, maybe the joke is on me.
Yes of course there are some extras but all you need is create font and then TextOut...
With your experience I thought it would be quite easy to sort it out.
There is a second link as well...
Is font important? If not, you can use system fonts (cleartype antialising only "for TrueType fonts and OpenType fonts with TrueType outlines"). Toggling option on/off, on-demand, may be desirable. Here's more
Insomnia is just a byproduct of, "It can't be done"
Sadly I have a lot going on this week, short work week here and short-handed as well.
I need to be able to use several non-System fonts, and I can't toggle Cleartype and smoothing globally because other applications running alongside mine have to look normal.
Yes, throwing together a few API calls is no big deal, but the program I'm reworking uses things like PictureBox.Print a lot as well as .CurrentX, .CurrentY, .TextWidth() and .TextHeight(). Just setting the hDC's font by calling SetFont (SetObject) doesn't adjust for these things.
I'm close now though (I think).
I wanted to make something reusable rather than an ad-hoc hack for this one program. That may be a vain hope, due to the stuff VB objects are doing behind the scenes.
Ok, here is an example of a way to get around the antialiasing artifacts. This particular example doesn't show the color-fringing I'm trying to eliminate, but this code does eliminate it in the large application I'm fixing.
It works fine except for the issue of updating CurrentX and CurrentY properly (seen here as screwed up "line leading" after using the Print pseudo-method).
The large program also makes use of the TextHeight() method but that seems to be working "well enough" right now. I suspect it is still off a bit though and I need to evaluate that yet.
Ideally the "right column" text would be printed with the same vertical spacing as the "left column" which was done using the Font property.
Prior to printing each line, ensure the picturebox .font.size is the same as what you are creating via API. VB appears to be using whatever its .font.size is to increment .CurrentY
Edited: Memory leak though. By setting the .font.size, the previous API font selected into the picturebox is leaked. So...
- Set .Font.Size = x
- Create API font of size x & select into DC, then print
- Immediately unselect, replace previous font, & delete unselected API font
- rinse & repeat
Last edited by LaVolpe; Dec 29th, 2011 at 06:41 PM.
Insomnia is just a byproduct of, "It can't be done"
Yeah I played with that but didn't get it quite right.
Sounds as if you are suggesting I need to wrap each Print (or group of Prints) with this font-flipping though. I'd rather just do something only when I need to change the font size (the program mostly uses a single font face), but if this is what it takes... so be it.
Sadly it isn't quite that easy since the program is using both Print and WriteText() calls but it shouldn't take too long to find all of the Print statements and replace them with formatting logic and a call to a wrapped WriteText() call. Or wrap both methods of printing.
Caching the hFont in the Tag property (as a decimal String value) is hokey but I was trying to make the thing a little more self-contained (multiple PictureBoxes, and/or Forms). If I wrap Print I can just use a local variable instead - freeing me of that abomination anyway.
Still doable I think. Just know that when you change a font property, VB appears to be unselecting whatever font is in the DC and replacing it with the updated font. Also you'll not want to refresh an AutoRedraw DC while API items are selected into it -- leaks
Insomnia is just a byproduct of, "It can't be done"
Ouch, I'll go make sure that (AutoRedraw) isn't required. Somehow I think it may break things for me though, so perhaps I was dreaming this was going to be so easy.
Just an idea... a class per picturebox. Possible methods
ChangeFont: calls UnselectFont method & destroys API font. Modifies VB font & creates API font of same size
SelectFont: select API font into DC
UnselectFont: unselects API font if in DC
Terminate: Calls unselect font & destroys API font as needed
Now for memory leak concerns. Before modifying the picturebox in any way that would create a new DC, unselect API font as needed. Some actions that will create new DC when autoredraw=true: resizing, backcolor, CLS, maybe a couple others
Last edited by LaVolpe; Dec 29th, 2011 at 07:23 PM.
Insomnia is just a byproduct of, "It can't be done"
Just curiosity. Wouldn't you get similar results by offsetting the 'shadow' by 2 additional pixels? If so, you'll not only get smoother result, but wouldn't need to use the API fonts either?
Insomnia is just a byproduct of, "It can't be done"
Well, only the heading line has a shadow. The rest of the lines are "faded in" over time with a second darker printing done over the top of the first lighter-colored printing.
The problem is those color fringes on the non-shadowed lines. I assume you can see the pinky & greenie fringing?
If I could get them to abandon this "fade in" effect the problem is gone. The antialiasing works very well for the fonts created expecting it.
Is there another easy "fade in text" technique that comes to mind?
So a fading is being done; that explains it. A way to get around that would be to clear the area being faded; then print the faded text. This obviously isn't desirable due to flicker. However, using a hidden picturebox with autoredraw=true, you can fade the text to that picturebox, clearing the destination area first, then PaintPicture it over to your visible picturebox. Just another idea
Insomnia is just a byproduct of, "It can't be done"
Hmm, worth exploring though there are a bunch of these PictureBoxes to wrestle with.
Not only is there a fade out to gray, but a fade-in "animation" effect through gray to white on these lines of text first. So the lines of text get painted 3 times (3 different colors) before finally being settled.
Actually the specific colors can vary, they aren't all gray-scaled shades - but there is a fade-in color, a "white" color, and a "faded out" color.
Think "4 across and 3 high tiled PowerPoint screens" driven by real-time input. Bleh. I kinda hate kiosk-style work.
Last edited by dilettante; Dec 29th, 2011 at 11:12 PM.
The idea is similar for any animation effort... backbuffer. The hidden picturebox would be the backbuffer. It can be used for all your pictureboxes and needs to be as wide as the widest and as tall as the tallest line of text be printed. The logic would be something like this:
- ensure buffer (hidden picturebox) contains any background image of destination picturebox
- ensure buffer has same backcolor as destination
- ensure buffer has same scalemode & font as destination
- ensure buffer autoredraw is true
- clear it
- fade your text to the buffer using desired .CurrentX of destination and at .CurrentY of 0
- PaintPicture the result to source; something like:
I was still hung up on the shadow effect required for the heading line at the top, and I wasn't seeing how this would help.
That clearly eliminates fade animation woes. I can probably even just paint a background-color rectangle over the text for fading.
Now all I need is a cleaner shadowing, but that might be working ok without playing any games suppressing antialiasing. As I mentioned above in post #21, the overprinting to produce a shadow effect was clean enough with ClearType on.
I guess this thread could be taken as an instance of a common problem that occurs here when asking for help:
Failure to state the problem requiring solution rather than asking blindly "How can I implement this specific solution?"
The real problem at hand was "How can I cure ClearType/smoothing induced color fringing when Printing text over pre-existing text in Forms and PictureBoxes to produce an animated fade-in and fade-back effect?"
Trying the existing program with ClearType and smoothing shut off at the system level got rid of the color fringes, so I had grabbed for that as an answer. Needing other things running to display normally (with ClearType), I believed what I needed was non-ClearType fonts to print with.
Nothing wrong with that, but where I failed here was in not explaining the context in which I was pursuing this solution. If I had done this I might have gotten a fast and easy fix from somebody fairly quickly.
Live and learn, "don't do as I do," etc.
Solution
I was able to quickly resolve the actual problem without playing with fonts by following LaVolpe's suggestions - made once he dragged a better problem description out of me.
In my case this overprinting causing fringing was only occurring where the "page" gets cleared and then lines of text are Printed downward, very much like a PowerPoint slide being revealed point-by-point. This simplified my solution to the following.
New line arrives to be printed:
If this line needs a new page:
Clear the page: Pic.Cls
Set line counter to 1
Print the heading and leave .CurrentX and .CurrentY sitting where we want line 1 to print.
So the X & Y are always left sitting at the previous line. Before printing a line over the same line in another color, I draw a filled rectangle (background color) from that point through the end of the canvas (blanking out the previous printing).
Simple, works great. Not the most general solution but it covers the case at hand (printing downward only, no random access).