Dynamic Text Replacement with JavaScript and C# ASP.NET

What it Does

You write some basic markup and include a JavaScript file and some code which replaces normal text with a .NET generated image:

<style type="text/css">
h2 { color: #9E100F; size: 22px; }
</style>
<!-- This says "Frequently asked questions in zh-TW -->
<!-- If you just see boxes, you need to install Asian fonts on your machine --> <h2>關於網上教育常見的問題</h2> <script type="text/javascript" src="fontreplacer.js"></script> <script type="text/javascript"> FontReplacer.replace('h2','*', 'MyGreatFont'); </script>

This will take all h2 tags with any class (*) and replace them with and image rendered using ‘MyGreatFont’. This font needs to be installed the c:\windows\fonts\ folder of your server or in the same folder as the .NET script which generates it. Initially the page will look like this (using the standard font for Chinese script on a PC which is ‘MS Mincho’):

image

But after the replacement happens, it looks like this:

image

With another less formal font, it could look like this:

image

Of course, you can use any font installed on the server and it is not limited to Chinese text. Here is an example replacing the default Times New Roman text with Century Gothic:

image

image

This may be useful in other scenarios for viewing Unicode text on a machine without Unicode fonts installed (Greek, Hebrew, Arabic, etc.).

It can also produce anti-aliased PNGs for use on top of an image:

image image

Why I did it

Recently, I needed to have the titles for a series of webpages be rendered in a specific Chinese font (see http://www.dts.edu/chinese and click on "zh-TW" in the upper right) because the default doesn’t look very official (according to my Chinese friends). I wanted to use sIFR which replaces the HTML text node with a Flash file that has the font embedded. The problem is that Chinese fonts are 3-8MB which means the user has to download a gigantic SWF. Also, there can be copyright problems with using sIFR.

So I turned to .NET to generate images using the font. The basic technique was first published back in a 2004 A List Apart article titled Dynamic Text Replacement. ALA used JavaScript and PHP and, since then, there have been many permutations of the basic idea, some using pure CSS instead of JavaScript. I haven’t seen a good one for .NET, so I had to write my own. I don’t like using CSS for some of the reasons mentioned here, so I went with JavaScript for the replacement. This way users without images or JavaScript can still see the text. Users with images and JavaScript get a slightly nicer view.

How it Works

The JavaScript method looks at the HTML element(s) you send it and pulls out the text and font color. It then sends a request to ASP.NET to return an image which renders the text using your assigned font and colors. There are three ways to call it:

// elements by tag and class
FontReplacer.replace(tag, class, fontName);
// elements by tag and class inside a given elmenent
FontReplacer.replaceIn(element, tag, class, fontName);
// replace array of elements
FontReplacer.replaceElements(elementArray, fontName);

This calls up a .NET script which writes the text to an image using the specified font. The C# code can generate a JPG or transparent PNG which happily sits on top of any background and looks very nice. (There is a flag in the JavaScript to to allow the PNG transparency). There are some tricks in .NET for generating a PNG with alpha channels and for saving a JPEG with a specified quality, so here’s the full code for that part.

if (backColor == "transparent")
{
	MemoryStream io = new MemoryStream();
	bitmap.Save(io, ImageFormat.Png);
	context.Response.ContentType = "image/png";
	context.Response.BinaryWrite(io.GetBuffer());
}
else
{
	context.Response.ContentType = "image/jpg";
	SaveAsJpeg(bitmap, context.Response.OutputStream, (long)100);
}
void SaveAsJpeg(Image inputImage, Stream stream, long quality)
{
	 // generate JPEG stuff
	 ImageCodecInfo codecEncoder = GetEncoder("image/jpeg");
	 EncoderParameters encoderParams = new EncoderParameters(1);
	 EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
	 encoderParams.Param[0] = qualityParam;
	 inputImage.Save(stream, codecEncoder, encoderParams);
}
ImageCodecInfo GetEncoder(string mimeType)
{
	ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
	foreach (ImageCodecInfo codec in codecs)
	{
		if (codec.MimeType == mimeType)
		{
			return codec;
		}
	}
	return null;
}

There are also flags in the JavaScript to force the returned image to be the same height and width as the element you are replacing. By default, the height is forced so that the page doesn’t jerk at all, but you should be aware that browsers often report the font size inaccurately. Also, .NET’s measurement of the size a given string will take up can include some padding depending on the font, so you may have to play with it for your scenario.

Lastly, there are some important things to know about using fonts on the server.

  1. When you install a font on c:\windows\fonts\, IIS doesn’t immediately know it’s there. You’ll need to run the "resetiis" command for IIS to pick up the new fonts.
  2. If you’re in a hosted environment and can’t install fonts, you’re still in luck. There is some code to load a *.TTF file in the fontwriter.ashx script. In this case, you’ll need to specify the font file name (‘gothic.ttf’) rather than the installed font name (‘Century Gothic’).
  3. You might want to adjust the TextRenderingHint hint property at the top if you don’t want anti-aliased rendering.

Download & Example

6 thoughts on “Dynamic Text Replacement with JavaScript and C# ASP.NET

  1. Its cool! I have a question: How can I send a text image to participle mailbox?

  2. This does not work for IE6 users, well PNG transparency certainly doesn’t. I have seen techniques for working round the transparency issue but generally they work onload, after the image has been generated and it seems that the image generated in IE6 is actually a bitmap ?!

  3. Are the images created, able to have a fixed width but a fluid height using your code? I want to ensure that the text can run over multiple lines but yet keep the same font size.
    Thanks

Comments are closed.