Hi,
I need to draw text into the bitmap. Resulting text should be "smooth" (antialiased) and international scripts should be handled properly. In addition, it should be fast. You might think, "That is simple, isn't it " Well, it is not!
There are at least two ways to do it:
1. Graphics.DrawString and
2. TextRenderer.DrawText.
Problem is that I cannot reach my targets with these two guys (who would say, huh ).
Graphics.DrawString is too SLOW, and it is not handling complex scripts properly they say. On the other hand, rendering quality is ok, and it is not depending on system-wide text smoothing setting.
TextRenderer.DrawText is the recommended text rendering engine in .NET2 and it is doing its job when rendering the text on the controls and system-wide text smoothing is active. Problem is, that it is rendering text into bitmaps always without text smoothing (independently of the system-wide text smoothing state) - at least I never managed to get smooth text out of it.
I need help desperately - I have spent already many days trying to figure out the solution without any success. I just cannot believe that in 2006 with all new technologies around it is such an issue to get smooth text into the bitmap. :(
Thanks for all your ideas beforehand.
Best regards,
Roman

Problem: How to draw text into bitmap?
sanmarcos
You are probably right about hardware acceleration in case of on-screen GDI rendering - at least it makes sense. And yes, text rendering could be accelerated by video hardware.
Yes, they look different. As I said - GDI+ renders Arabic properly (RTL), and GDI - reversed (LTR). That's very strange.
15 lines is not a problem per se. The problem begins when I try to scroll that list as fast as possible - I am getting 100% CPU utilization (while using GDI+). That is not a very good thing, as my application has to react to certain things (like digital TV processing) in real time. With DirectX I do not hit this performance bottleneck, but I am not happy about DirectX way of handling text rendering - if you think GDI vs GDI+ is tough, you would be surprised to see how ugly is DirectX.
I was thinking about some kind of compromise between those two - using DirectX for main graphics tasks while using GDI or GDI+ for text rendering part: render text into black and white bitmap, convert it to texture and then use pixel shader to render actual text in DirectX using that texture as alpha source (I hope this explanation is clear).
Could be... On the other hand it would be quite stupid not to use some kind of buffering (in-memory bitmap) for this purpose... I think, that the difference comes mostly from the fact that GDI text rendering is hardware accelerated, while GDI+ is not - they had to implement completely new text rendering engine to handle all those cool features like GenericTypographic and alpha blending.
Anyway, now we have "best" of both worlds - slowness of GDI+ with its ability to render typographically correct text with alpha blending and inability to handle Uniscribe on one side, and speed of GDI (speed which speed ) with its ability to handle complex scripts (well, if you can figure out how to do itl; so far - no success), but nasty bugs in alpha handling on the other. If you ask my opinion, these two technologies are kind of orthogonal, i.e. one cannot get simple job (render complex scripts properly) done with either of them.
Oh, well, nevermind... It seems Microsoft is sooooooooo busy marketing and developing future versions of the "new and improved" products (they could try to release "old and fixed" version for a change at least once), that such annoying things like FAST and CORRECT text rendering (done by bloody Macs for ages) are simply not fitting into their strategy. It sounds so funny when MS guys on DirectX-related forums propose people with text rendering problems to write their own text rendering engines :) - IMHO it would make sense if MS would fix errors in GDI, GDI+ and DirectX just once, and for all... Dreams.... dreams.....
zeeshan hirani
Hello again!
So, it seems that text rendering IS indeed quite tough subject...
I just wonder, if anyone had any success in rendering for example Arabic with TextRenderer.DrawText I just downloaded little demo program from MSDN Magazine (don't have the link to it anymore, but article was about DrawString vs DrawText) and it has same behavior: DrawString - properly handles "mixed" content (string like "abc <then some Arabic> def"), DrawText - "reverses" Arabic sub-parts (so it renders "abc <cibarA emos neht> def"). Weird...
(NOTE: I am not an "expert" in Arabic - I make my judgment based on what I see when I render it and assuming that Internet Explorer renders Arabic properly).
Roman
fastdev
jmckown
I've tried with some text copied from BBC Arabic page. It looks the same, including some numbers in it. I'm using IE 7 Beta 2. Could be that other version/browser has problems copying the text
GDI is 4-5 times faster than GDI+ with both Latin and Arabic text. And there's a good chance that il will be even faster if you PInvoke TextOut/DrawText instead of using TextRenderer. TextRenderer needs to configure the HDC every time you call it that is something like SetTextColor, SetBkColor, SelectObject(font). If you use PInvoke to GDI functions you can set these things just once and draw multiple strings.
Indeed, with a large font size normal font antialiasing is good enough or even better than ClearType. ClearType was probably designed for small sizes like 8-12 pt where taking advantage of 3 RGB subpixels that compose a pixel means a lot. It's like you are renderint text on a device that has 288 dpi instead of 96 (of course, only horizontally).
Bob M
I tried various combinations but I could not get Arabic text to render reversed. I wrote random text in Word using Arabic keyboard and copy/pasted in Visual Studio, I wrote directly in Visual Studio using Arabic keyboard (and in both cases I added some other text using English keyboard and some numbers). One time I got something strange: a number that in Word was displayed after some arabic text was displayed in front of it using TextRenderer AND DrawString, but the order of characters/digits was normal.
DrawText has a flag: TextFormatFlags.RightToLeft, try it and see what happens... but for it reversed some words (words, not the characters in the words).
And about GDI performance when rendering on a bitmap. Try this modified code:
Public Class Form1
Declare Auto Function CreateBitmap Lib "gdi32.dll" Alias "CreateBitmap" (ByVal width As Int32, ByVal Height As Int32, ByVal planes As UInt32, ByVal bpp As UInt32, ByVal bits As IntPtr) As IntPtr
Declare Auto Function CreateCompatibleDC Lib "gdi32.dll" (ByVal hdc As IntPtr) As IntPtr
Declare Auto Function SelectObject Lib "gdi32.dll" (ByVal hdc As IntPtr, ByVal hbmp As IntPtr) As IntPtr
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim F As New Font("Arial", 48, FontStyle.Regular, GraphicsUnit.Pixel, 0)
Dim hdc As IntPtr = CreateCompatibleDC(IntPtr.Zero)
Dim hbmp As IntPtr = CreateBitmap(500, 500, 1, 32, IntPtr.Zero)
SelectObject(hdc, hbmp)
Dim GG As Graphics = Graphics.FromHdc(hdc)
GG.Clear(Color.White)
Dim DC As IDeviceContext = GG
Dim ST As System.DateTime
Dim ET As System.DateTime
ST = System.DateTime.Now
For i As Integer = 0 To 10000
GG.DrawString("This is only a test", F, Brushes.Black, 10, 10, System.Drawing.StringFormat.GenericTypographic)
'TextRenderer.DrawText(DC, "This is only a test", F, New Point(10, 100), Color.Black, Color.Transparent)
Next
ET = System.DateTime.Now
Debug.Print("Time " & (ET - ST).ToString())
GG.Dispose()
Dim b As Bitmap = Bitmap.FromHbitmap(hbmp)
Dim G As Graphics = CreateGraphics()
G.DrawImageUnscaled(b, 0, 0, 500, 500)
End Sub
End Class
You'll have a surprise... GDI isn't slower anymore... The reason Obviously GDI cannot draw onto a "native" GDI+ Graphics object nor onto a "native" GDI+ Bitmap so someone somewhere must do some heavy lifting to make them work together, probably something like CreateDC, CreateBitmap and maybe even some bitmap copying and pixel format conversion (for instance your example uses PARGB format, I wonder if GDI can handle this ) . Once you create the Graphics/Bitmap objects from GDI objects this problems go away.
"render text into black and white bitmap, convert it to texture and then use pixel shader to render actual text in DirectX using that texture as alpha source (I hope this explanation is clear)."
Now it depends what you mean by black and white bitmap. If it's 1 bpp bitmap then it will blow up any form of antialiasing done by DrawString/TextRenderer. If it's something like 8bpp grayscale this will probably blow up ClearType antialiasing because it needs the color components of the pixel. Take a screenshot of some ClearType black text on white background and you'll see that pixels at the border between text and background have various colors, they're not gray. In fact ClearType will be blown up by other things like rendering text horizontally and then displaying it vertically.
Travis Baldree
Tried the example and got the same result, that is GDI is slower than GDI+. Surprise... Well, not completly surprised. Try drawing to the screen (create the Graphics context using Form.CreateGraphics method) and you'll have another suprise... GDI is faster than GDI+
. Why I'm not sure. One big difference between GDI and GDI+ is that GDI sits in kernel mode and talks directly to the video driver taking advantage of hardware acceleration (if there is such a thing for text, I don't know how text rendering can be hardware accelerated) and GDI+ works in user mode and ... umm... how does actually GDI+ writes to the screen I don't know but all it can do is talk to either GDI or DirectX and as far as I know it does not use hardware acceleration.
I'm don't know what you mean by different results in the case of Arabic. It's a bit slower with both and the look similar to me Did they look different to you Anyway it's known that GDI++ doesn't do quite well. See this blog for a comment about this: http://blogs.msdn.com/michkap/archive/2005/10/11/479438.aspx.
And look here at another blog post about GDI vs. GDI+ performance:
http://blogs.msdn.com/cjacks/archive/2006/05/19/602021.aspx
Unfortunately text rendering is not an easy task and when it comes to supporting different languages is even harder.
Look here for another interesting post about differences between GDI and GDI+, it made my head spin a bit:
http://windowsforms.net/articles/gdiptext.aspx
For your case maybe you should somehow cache the rendered text (bitmaps). Speaking of this, are you sure the way you render the text in Direct X is OK I mean 15 lines of text is not much for neither GDI or GDI++ but I suppose you render to a bitmap and create a texture from the bitmap (or update an existing one)... thing like this. If done wrong this operations can be quite expensive.
And one last note... it needs the background color so it can do antialiasing correctly. You cannot do antialias if you don't know what's behind the text... that could be a good reason why GDI+ is slower on display... it may need to read pixels from the screen to do antialiasing and that's usually slow... reading from a memory bitmap is much faster.
Sajitha Jose
Great! Now the text IS smooth! (and yes - black background helps too). Very strange behaviour I would say, but nevermind...
The only problem is that now I am even more confused.
1. GDI+ is supposed to be SLOWER than GDI, yeah Well, the fact is, that in my test run Graphics.DrawString is about 5 times FASTER than TextRenderer.DrawText! 8-O
2. I am getting totally different result from those guys if I am putting some Arabic text there. I am not an expert in Arabic to say which one is correct, but that is funny behaviour.
Here is the snippet (don't kick me - it is in VB.NET, but it is not my fault :) - can be put in button_click or wherever...
-------------------------------------
Dim F As New Font("Arial", 48, FontStyle.Regular, GraphicsUnit.Pixel, 0)
Dim B As New Bitmap(500, 500, Imaging.PixelFormat.Format32bppPArgb)
Dim GG As Graphics = Graphics.FromImage(B)
GG.Clear(Color.White)
Dim DC As IDeviceContext = GG
Dim ST As System.DateTime
Dim ET As System.DateTime
ST = System.DateTime.Now
For i As Integer = 0 To 10000
'GG.DrawString("This is only a test", F, Brushes.Black, 10, 10, System.Drawing.StringFormat.GenericTypographic)
TextRenderer.DrawText(DC, "This is only a test", F, New Point(10, 100), Color.Black, Color.White)
Next
ET = System.DateTime.Now
Debug.Print("Start " & ST & " " & ST.Millisecond)
Debug.Print("End " & ET & " " & ET.Millisecond)
GG.Dispose()
Dim G As Graphics = Me.CreateGraphics()
G.DrawImageUnscaled(B, 0, 0, 500, 500)
-------------------------------------
Tell me, that I am just plain stupid and have some obvious error in the code above... I cannot believe that text rendering is really SO BIG DEAL in Windows environment with video accelerators capable of rendering real-time movie effects.
Best regards,
Roman
Vince2006
Carl Perkins
There are two cases, to display Arabic text using DrawText:
Unmirrored HDC (I mean normal , without mirroring styles). You need to set the flag + adjust the y-coordinates. As seen below:
'We have to adjust the left of the drawing rectangle to draw the text in the correct location
'NewLeft = FormWidth – (Left + Width)
TextRenderer.DrawText(e.Graphics, " .", Me.Font, New Rectangle(Me.Width - (10 + 100), 10, 100, 100),
SystemColors.ControlText, TextFormatFlags.RightToLeft)
If your DC is mirrored (for example use RightToLeftLayout=true) then you don't need to add a flag or adjust the y-coordinates:
TextRenderer.DrawText(e.Graphics, " .", Me.Font, New Rectangle(10, 10, 100, 100), SystemColors.ControlText)
However, I'm not sure that you can displays indic numerals.
zooto68
User interface of my application is made with DirectX. Unfortunately, I do not like the way DirectX is handling the text (far various reasons) - that's why I started to look at alternatives.
Now back to the amount of the text... Sometimes it could be quite much - for example, on some forms there could be few multicolumn lists with 15 quite long lines each. List scrolling takes 100% of CPU (it is really a problem - there are other important things happening on the machine at the same time) and is not too fast. To have some UI animations like focus change, or list scrolling, I will end up inventing complex frameworks to cache rendered text, update only parts of the form, etc. and even those are not bringing acceptable performace (already tried it).
Just for reference: In DirectX implementation same scrolling takes only few percents of the CPU (but as I said I am not satisfied with the way DirectX handles the text).
On top of that, speed is not the only concern - as I said I need complex scripts, and GDI+ is not good for those.
OldSam
I've tried using TextRenderer to draw onto a Bitmap and it worked just fine.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Bitmap bmp = new Bitmap(100, 100))
{
using (Graphics g = Graphics.FromImage(bmp))
TextRenderer.DrawText(g, "hello world", Font, Point.Empty, Color.Black, SystemColors.Control);
e.Graphics.DrawImage(bmp, Point.Empty);
}
}
Note that I have specified the background color of the text. Without it clear type won't work as expected (unless you are drawing on a black bakground).
I'm curious about the speed. GDI+ is known to much slower at text rendering than GDI but still... 15 lines of text does not sound like much. You said that using Direct X text rendering CPU usage is very low and when using GDI++ the usage is 100%. But how does it look with GDI, even without clear type
CyrilDex
How much text are you drawing that DrawString is too slow