Introduction
Welcome to the Part 2 of Outline Text article series! You can read Outline Text Part 1 if you haven’t had the chance to do so. In today’s article, I will teach you how to implement translucent shadow in theory. Every C++ code sample is accompanied by an equivalent C# code sample; I have wrapped the native implementation, using C++/CLI for use in .Net WinForms applications; WPF has its own text outline implementation. I will also introduce a PngOutlineText class which renders text to a PixelFormat32bppARGB format Bitmap object which is a Bitmap object with an alpha channel, so that you need not regenerate the text, everytime you render it; you just blit that PNG bitmap.
Shadows?
Text shadow is drawn using the single outline text code. There is one problem: shadow is translucent. If we use the first code example to render shadows, it will turn out to be like the image below. It is because some area of the font body and font outline overlaps, so they are rendered twice, therefore it is darker.
My solution is to render the shadow text body and shadow text outline separately like below and combine them, with the pixels with shadow text body takes precedence; Only where the shadow text body is not rendered, the shadow text outline is rendered. Shadow rendering is more involved and complicated, the 0.1.0 version of OutlineText.cpp without shadow implementation is only 3KB in file size and has 164 lines of code while the 0.2.0 version of OutlineText.cpp with shadow implementation is 23KB in file size and has 865 lines of code! Therefore, I will not show its code here, you can download and read source code if you are interested.
Single Outline
This is the C++ code to use the OutlineText class to display the single outline text with a shadow. First, we need to enable the shadow, set its background image and set its attributes, like shadow color, width of the shadow outline and its offset point from the actual text.
#include "TextDesigner/OutlineText.h" void CScratchPadDlg::OnPaint() { //CDialog::OnPaint(); CPaintDC dc(this); using namespace Gdiplus; Graphics graphics(dc.GetSafeHdc()); graphics.SetSmoothingMode(SmoothingModeAntiAlias); graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); FontFamily fontFamily(L"Arial Black"); StringFormat strformat; wchar_t pszbuf[] = L"Text Designer"; OutlineText text; text.TextOutline(Color(255,128,64),Color(200,0,0),8); text.EnableShadow(true); CRect rect; GetClientRect(&rect); text.SetShadowBkgd(Color(255,255,0),rect.Width(),rect.Height()); text.Shadow(Color(128,0,0,0), 4, Point(4,8)); text.DrawString(&graphics,&fontFamily,FontStyleItalic, 48, pszbuf, Gdiplus::Point(10,10), &strformat); }
This is the equivalent C# code to use the dotOutlineText class to display the single outline text with shadow.
private void OnPaint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; FontFamily fontFamily = new FontFamily("Arial Black"); StringFormat strformat = new StringFormat(); string szbuf = "Text Designer"; dotNetOutlineText text = new dotNetOutlineText(); text.TextOutline(Color.FromArgb(255,128,64),Color.FromArgb(200,0,0),8); text.EnableShadow(true); text.SetShadowBkgd(Color.FromArgb(255,255,0),this.Size.Width, this.Size.Height); text.Shadow(Color.FromArgb(128,0,0,0), 4, new Point(4,8)); text.DrawString(e.Graphics, fontFamily, FontStyle.Italic, 48, szbuf, new Point(10, 10), strformat); }
This is the settings in TestOutlineText application to display the above. I list out the settings here because sometimes even I was a bit lost on how to use TestOutlineText to display certain outline text effects. By listing the settings here, I hope the readers will get familiar with this application, so that they can try out the outline effects they want.
Double Outline
To achieve double outline text, you have to specify the outer outline and the inner outline . This is the C++ code to display the double outline text.
#include "TextDesigner/OutlineText.h" void CScratchPadDlg::OnPaint() { //CDialog::OnPaint(); CPaintDC dc(this); using namespace Gdiplus; Graphics graphics(dc.GetSafeHdc()); graphics.SetSmoothingMode(SmoothingModeAntiAlias); graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic); FontFamily fontFamily(L"Arial Black"); StringFormat strformat; wchar_t pszbuf[] = L"Text Designer"; OutlineText text; text.TextDblOutline(Color(255,255,255),Color(0,128,128),Color(0,255,0),4,4); text.EnableShadow(true); CRect rect; GetClientRect(&rect); text.SetShadowBkgd(Color(255,128,192),rect.Width(),rect.Height()); text.Shadow(Color(128,0,0,0), 4, Point(4,8)); text.DrawString(&graphics,&fontFamily,FontStyleRegular, 48, pszbuf, Gdiplus::Point(10,10), &strformat); }
This is the C# code to display the double outline text.
private void OnPaint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; FontFamily fontFamily = new FontFamily("Arial Black"); StringFormat strformat = new StringFormat(); string szbuf = "Text Designer"; dotNetOutlineText text = new dotNetOutlineText(); text.TextDblOutline(Color.FromArgb(255,255,255),Color.FromArgb(0,128,128),Color.FromArgb(0,255,0),4,4); text.EnableShadow(true); text.SetShadowBkgd(Color.FromArgb(255,128,192),this.Size.Width, this.Size.Height); text.Shadow(Color.FromArgb(128,0,0,0), 4, new Point(4,8)); text.DrawString(e.Graphics, fontFamily, FontStyle.Bold, 48, szbuf, new Point(10, 10), strformat); }
This is the settings to display the double outline text.