SetCompatibleTextRenderingDefault(true) and Graphics.DrawString() text rendering - c#

I'm writing a C# (ActiveX) plugin for an application that uses SetCompatibleTextRenderingDefault(true) (forces .net 1.1 text rendering style) This setting mangles some of the text I output with Graphics.DrawString() causing it to look slightly smudged and bolded. Unlike individual controls neither the Graphics class nor the BitMap have UseCompatibleTextRendering properties that can be used to override the individual behavior. Short of fiddling around to try and figure out what's special about the places where I'm drawing text that doesn't get mangled is there anything I can do about this?
The app my plugin is for belongs to a third party so simply changing the SetCompatibleTextRenderingDefault call it inflicts on me is not an option.
Edit: The 'special' thing appears to be the color of the background and how it's affecting the anti-aliasing used; so fiddling to fix it by how I setup the rectangles doesn't seem to be an option.

I'd advise using TextRenderer.DrawText instead of Graphics.DrawString - even with compatible text rendering disabled, it seems to produce crisper, more consistent results.

I found a fix for my problem by changing the TextRenderingHint to SingleBitPerPixelGridFit which is the default when not using compatible text rendering. When it's instead set to true it uses a the ClearType enumeration except that for whatever reason unlike normal cleartype text the results are ugly and extremely hard to read.
textGraphics.TextRenderingHint =
System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;

Related

Check if Control.Text is to long to be shown

I'm trying to do some automatic tests if the strings of a translated Application still fits the existing UI. The translation process just takes an existing resource assembly translates the contained resources and creates a new resources assembly for the new language. Easy but that way there is no garantee that the translations still fits into the UI (the UI is not involved in the translation process) and might get truncated all over the place. So for an automatic check i would need an idea on how to find truncated Text on the UI.
I tried so far:
Measuring the client size of a control, measuring the text length and
compare them. Doesn't work since there seem to be no way to find out
the ~real~ client size of a control that is used for putting text on
it (For a Button its not just Size minus Padding for example)
Setting AutoSize to true and checking if the control grows. That
would only work for non-wordwrapping controls and there seem to be
no sharp limit here. A control might grow to fit the Text on its
surface when setting autosize but the Text was fitting before
also. The margins might have been pretty narrow but the Text where
fitting.
Are there more idea that might work? Or are there some tweeks that might make the above mentioned ways work? Would be great if there where a simple Win API method i could call that would just give me the actual shown text of a control not the text a programmer/programm whishes to be shown on a control.
Get the amount of the characters from the non translated version and differentiate them against the length of the translated version then multiply the current controls width by the difference. It could look something like this.
float scalingAmount = 0.1 //This is just an example value, you'd probably want to adjust this yourself
float difference = oldLabel.Text.Length - label.Text.Length;
label.Width = oldLabel.Width * (difference/scalingAmmount)

Typesetting text with .NET

I'm writing a WinForms .NET program that needs to lay some text out on a page (with a few basic geometric/vector graphics). Is there an equivalent of OS X's Core Graphics and/or Core Text? So far, I am just using a PrintDocument and using the Graphics object provided by the PrintPageEventArgs to draw text on the page, but there's very little control over things such as interword spacing, interline spacing etc. and a lot of stuff has to be done manually.
I feel like I'm missing something; is there a better way for typesetting text on a page? I don't mind using 3rd party solutions as long as they are free for personal use.
This will be used for typesetting a small variety of documents, including one-page brochures/fliers (where most text is variable but images are static), award certificates (where most text and images are static but some text is variable), timetables, etc.
WinForms
When you use WinForms it is close to impossible to do proper type setting and yes, almost everything must be done manually. There are a couple of reasons for this:
You don't get detailed glyph information
The text measurement is horrible inaccurate, both the GDI+ and the GDI based version.
Windows Presentation Foundation
If you use WPF this is an entirely different matter as you get detailed geometrical information about each glyph.
However, you can interleave the two, a bit messy, but possible. Although, I do not recommend it as the graphics and bitmaps are not directly interchangeable which can result in slow performance.
If you want to look at the possibility you need to import the System.Windows.Media into your project to access the typeface and glyph capability of WPF.
You will meet a couple of other challenges as well:
The font lists between WinForm and WPF are not identical (more font and font types with WPF).
You cannot just use a WPF glyph and draw it to a WinForm bitmap.
The values from the glyph are, as expected, in em so they need to be converted to pixels based on point size.
However, you can get this (not limited to) information:
All details (too many to list here):
http://msdn.microsoft.com/en-us/library/system.windows.media.glyphtypeface.aspx
Conclusion
But if you stick with GDI+ and WinForms the best approach you can take is probably to use the GDI based TextMetrics class.
You will in any case experience possibly padding issues, you cannot set char spacing and so forth.
You will have to calculate baseline for each typeface and size by using top + ascent:
FontFamily ff = myFont.FontFamily;
float lineSpace = ff.GetLineSpacing(myFont.Style);
float ascent = ff.GetCellAscent(myFont.Style);
float baseline = myFont.GetHeight(ev.Graphics) * ascent / lineSpace;
PointF renderPt = new PointF(pt.X, pt.Y - baseline));
ev.Graphics.DrawString("My baselined text", myFont, textBrush, renderPt);
I do not know of any third-party library that can do this within the WinForm environment, I believe for the reasons mentioned here and the pain it would cause.
In conclusion I can only recommend you to take a look at Windows Presentation Foundation/WPF for a better ground to achieve proper type setting as you will get stuck in a lot of compromises using WinForms for this (I made a font viewer which is where I came across WPF as I wanted to show glyphs and detailed information about it including black-box and so forth - that was painful enough).
UPDATE:
WebBrowser as type-setting engine
A possible work-around of this is to use the WebBrowser control to do the setting. It's not an actual hack, but a bit hack-ish as it establish a initially unnecessary dependency on the IE browser on the user's computer.
However, this can turn out to be flexible when it comes to type setting as you have the same simple controls over text as with any HTML page.
To get a result you attach the HTML with styles and attributes for the text. You can even combine it with images and so forth (obviously).
The control can be for example on another hidden form not visible to the user.
After dropping in the WebControl on the form or creating it manually setting HTML is done in a single step:
WebBrowser1.DocumentText = "<span style='font-size:24px;'>Type-setting</span> <span style='font-family:sans-serif;font-size:18px;font-style:italic;'>using the browser component.</span>";
Next step is to grab what you render as HTML as an image which can be done as this:
using mshtml;
using System.Drawing;
using System.Runtime.InteropServices;
[ComImport, InterfaceType((short)1), Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
private interface IHTMLElementRenderFixed
{
void DrawToDC(IntPtr hdc);
void SetDocumentPrinter(string bstrPrinterName, IntPtr hdc);
}
public Bitmap GetImage(string id)
{
HtmlElement e = webBrowser1.Document.GetElementById(id);
IHTMLImgElement img = (IHTMLImgElement)e.DomElement;
IHTMLElementRenderFixed render = (IHTMLElementRenderFixed)img;
Bitmap bmp = new Bitmap(e.OffsetRectangle.Width, e.OffsetRectangle.Height);
Graphics g = Graphics.FromImage(bmp);
IntPtr hdc = g.GetHdc();
render.DrawToDC(hdc);
g.ReleaseHdc(hdc);
return bmp;
}
From: Saving images from a WebBrowser Control
Now you can place the bitmap on to your normal page. ..Or just use the control directly on the form with reduced interactive capability (right-click menu could easily become a problem if not).
Not knowing the exact usage that this is for, this may or may not be a suitable solution but it gives some powerful options and can be in place of a third-party solution.
Components
Looking high and low it seem that this area is not so much targeted. I could find one component that comes close but the pattern continues: one will be hitting a nail with a sledgehammer. It ends up in the same category as the WebBrowser work-around.
This component is really a full fledged editor but by disabling most of it it can perhaps be used to simply display formatted text/graphics with type setting sort of at hand:
http://www.textcontrol.com/en_US/products/dotnet/overview/
Another possibility is to use a PDF component to set up the content and use a component to render the PDF as graphics (commercial):
http://www.dynamicpdf.com/Generate-PDF-.NET.aspx
http://www.dynamicpdf.com/Rasterizer-PDF-.NET.aspx
Non-commercial:
http://www.pdfsharp.net/?AspxAutoDetectCookieSupport=1
Using GhostScript to get image:
http://www.codeproject.com/Articles/32274/How-To-Convert-PDF-to-Image-Using-Ghostscript-API
The obvious static alternative
..and corky perhaps, but in any case I'll include it as simplicity sometimes works best -
If it is not a absolute requirement to be able to create these pages dynamically, generate all the text and graphics in Illustrator/Photoshop/inDesign etc. and save the result as images to be displayed.
In order to lay down text: there are several possibilities:
A simple label, that lets you simple text manipulation (like font, placement, color, etc.)
A rich text document that you may change the properties of the control to suite your needs, keep in mind that this one may present some simple images, etc.
An image -> that you may create dynamically, with the graphics object, with the onpaint event. this is not recomended, as its a very low level approach, but as you know as low level as you get, the more power you gain.
Combination of many controls, in a custom control you create, that you hold the information you want to draw / write in local members -> then keeping cont to when you change something, then set a flag (_needToBeRepainted = true;), and then on repainting, if(_needToBeRepainted) draw everything.
please let me know if you need further assistance solving this one.

make Label control text look as good as it does in VS form designer

In VS2008 I designed a form for a C# dll. The dll is a plugin for a somewhat older app (ca. 2005): let's call it "OldApp". In VS form designer, the text in Label controls on my form is nicely rendered: antialiased and properly kerned. But when I bring up this form within OldApp (where the C# dll runs as a plugin), the text in Label controls looks ugly. It's legible, but the kerning is poor: the letters are spaced further apart and at seemingly random offsets. Anything I can do to make the text labels from within OldApp look as good as they do in VS's form designer? I doubt the specific font matters, but it's Arial, 7.2 pt (VS2008 default). I tried playing with the two relevant lines in Program.cs (see below), to no effect.
Application.EnableVisualStyles(); // tried using it and commenting it out
Application.SetCompatibleTextRenderingDefault(true); // tried true and false
I found a similar problem on MSDN forums that mentions adding the following line after the EnableVisualStyles() method.
Application.DoEvents()
Seems to be a bug in older .NET versions...which version are you using?
After an investigation I have some findings, so I'll just answer my own question:
The bad news: the old-style text rendering used by OldApp is what's causing the problem. I verified it by toggling the UseCompatibleTextRendering property for the label control in VS. The font distortion I see is the same one I see in OldApp. Which means that the Application.SetCompatibleTextRenderingDefault(false) line in my code has no effect. OldApp will ignore it and do old-style rendering anyway.
As suggested by DeviantSeev using a bigger font helps a bit. It doesn't get rid of the bad kerning, it just makes it less noticeable. I increased the font from 7.2pt to 8pt only (not 12pt), because the dialog box becomes too big otherwise. The way to do this is in the form's Font property (not the control's). This way, you'll change all controls uniformly (if their Font property is set to default).
The font sizes in VS appear to be discrete rather than continuous, or maybe there's an int() rounding off involved. Increasing the font from 7.2pt to 7.4pt results in very little change, while at 7.5pt the font makes a sudden jump in size.
Forms have an AutoScaleMode property. If it's set to Font and the form is resizeable, the form will resize in VS in proportion to the change in font size. This way, in VS you can find an acceptable middle ground between a (legible) font size and a bloated dialog. However, be careful: the auto-scale operation can suddenly go awry, for example if you change the Font units from points to pixels, inches, etc. You may suddenly end up with microscopic controls or a form bigger than your screen and hitting undo won't fix it. You really don't want to re-design your form again, so save it before any font unit change and then again when you're happy with what you see.

Want to bold few characters of a word get bold in treenode in winforms using c#

i have "search TextBox" to search in treeview, i give result very well. But i want to get those parts get Bold which i typed in "search TextBox" of my winform.
Ex: i Typed Ram then it gives *Ram*esh .
The TreeNode class doesn't support that, its Text is always drawn with one font, the TreeView.Font. Making parts of the text bold is technically possible but very hard to get right. You need to enable custom drawing with the TreeView.DrawMode property and DrawItem event, there's a good example of it in the MSDN Library article.
That's the easy part, the hard problem is that the node is too small to fit the text after you draw parts of it in a bold font. TreeView is missing a "MeasureNodeText" event that would allow you to ask for enough space. The only workaround for that is to lie about the node text and make it artificially wider by prefixing characters. Which you then don't draw in the DrawItem event. Very hard to get consistently right, you'll want to consider a fixed pitch font instead.
I cannot recommend you pursue this unless the feature is really important to you. This otherwise explains why you never see this feature in other programs. Consider changing the color instead of the font weight too. Still hard to glue the pieces together btw.

Smooth Text On Glass

I have seen many other samples out there that draw smooth text on glass. But I can't use them. I need every single label that gets added at runtime to be smooth. I can't just "draw" text onto the screen.
Is this at all possible, and are there and sources around?
Thank you
Take a long at this article http://msdn.microsoft.com/en-us/magazine/cc163435.aspx#S6
It's a bit long but it answers alot of your question and alore more in regards to glass.
but the relevant part for you directly is
One particular gotcha is that
rendering a GDI item in black uses the
bit pattern 0x00000000-which also
happens to be a completely transparent
black if you are using an alpha
channel. This means that if you draw
with a black GDI brush or pen you'll
get a transparent color, not a black
one. The biggest problem this presents
is when you try to use the default
text color in a control of a text
label that sits on the glass area.
Since the default text color is
usually black, the DWM will consider
this to be transparent and the text
will be written in the glass
incorrectly. An example can be seen in
Figure 10. The first line is written
with GDI+, the second is a text label
control using the default color. As
you can see, it's nearly illegible
because it's actually incorrectly
rendered text that shows up as gray,
not black.
Happily, there are a number of ways
around this problem. Using owner-draw
controls is one. Rendering to a bitmap
that has an alpha channel is another.
Fortunately, the easiest way to get
text on controls is to let the .NET
Framework 2.0 use GDI+ for you. This
is easily accomplished by setting the
UseCompatibleTextRendering property on
your controls. By default, this
property is set to false so that
controls written for previous versions
of the .NET Framework will render the
same. But if you set it to true, your
text will come out looking correct.
You can set the property globally with
the
Application.SetUseCompatibleTextRenderingDefault
method.
He also provides example code you can place in your Main()
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true);
Application.Run(new GlassForm());
}
But I recommend reading the article, It'll clear up alot of what's going on with Aero/Glass
Cheers,
Phyx

Categories

Resources