|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionOur designer gave me some cool Photoshop screen drafts of what she thought our application ought to look like. The drafts had several examples of where she had made text with a halo outline around the words. Like all good designers, she had sliced the images up into discrete sections, allowing me to do the integration easily. The problem with this approach was that it was time consuming to integrate each image she gave me, and when we wanted to localize the product later, we would need to redo them all. I needed a way to generate these on the fly. The PlanWinForms' I expected this to take a little while to do, so I planned on having a function return the bitmap for the final text image so that I could squirrel it away and use that as a cached version of the text from that point onwards, thus only suffering the performance hit once. This seemed like a workable solution, so I set about implementing it... The ImplementationThis was going to take some brushes, some bitmaps, some graphics contexts etc., and we may call this function hundreds of times, so judicious resource management would be important. For those that don't know, when a managed object goes out of scope, it is marked as "unreferenced" to be garbage collected automatically, later in time. When? You may have no idea if you don't explicitly call garbage collection yourself (not necessarily recommended if you use things like weak references, etc., but that is beyond the scope of this article). These managed objects, like the using (SolidBrush brFore=new SolidBrush(clrFore))
{
... use the brush inside of here
}
In order to make the containing bitmap, we will need to know how big the text will be in pixels. We use the SizeF sz=g.MeasureString(strText, fnt);
GDI+ is built for both speed and beauty, and by default, it picks a happy medium. There are properties you can set on a gBmp.SmoothingMode=SmoothingMode.HighQuality;
gBmp.InterpolationMode=InterpolationMode.HighQualityBilinear;
gBmp.TextRenderingHint=TextRenderingHint.AntiAliasGridFit;
From the bitmap, we create a graphics context ( using (Bitmap bmp=new Bitmap((int)sz.Width,(int)sz.Height))
using (Graphics gBmp=Graphics.FromImage(bmp))
using (SolidBrush brBack=new
SolidBrush(Color.FromArgb(16,clrBack.R,
clrBack.G, clrBack.B)))
using (SolidBrush brFore=new SolidBrush(clrFore))
{
...
}
We now create another image, made bigger by bmpOut=new Bitmap(bmp.Width+blurAmount,bmp.Height+blurAmount);
...
// smear image of background of text about
// to make blurred background "halo"
for (int x=0;x<=blurAmount;x++)
for (int y=0;y<=blurAmount;y++)
gBmpOut.DrawImageUnscaled(bmp,x,y);
After rendering the blur, we finally render the actual text again, in the center ( // draw actual text
gBmpOut.DrawString(strText, fnt, brFore,
blurAmount/2, blurAmount/2);
Using the codeHere is how you would call the code to generate an image for some text, and how you would render the final fancy text image onto a Windows form: public class Form1 : System.Windows.Forms.Form
{
private Bitmap _bmpText;
public Form1()
{
this.BackColor = System.Drawing.Color.IndianRed;
this.ClientSize = new System.Drawing.Size(358, 126);
using (Font fnt=new Font("Arial", 20, FontStyle.Bold))
_bmpText = (Bitmap) FancyText.ImageFromText("Hello Code" +
" Project Fans!", fnt, Color.Green, Color.Yellow);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImageUnscaled(_bmpText, 10, 40);
}
}
History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||