Skip navigation.

Jeffrey Richter Coming to TownAll recent postsJeffrey Richter Did Come To Town

.IR: Image Replacement With ASP.NET (Beta)

I'm not sure who came up with image replacement (probably Todd Fahrner), but I first read about it on Doug Bowman's site, and then saw a post by Dave Shea with a collection of image replacement variations.

In a nutshell, with image replacement you can add more appeal to a heading by replacing its text with an image. Normally, the image shows the same text, but since you create it yourself you may use any font you like.

When using fonts on the web, you're confined to a handful of fonts. Outside of the "standard" set of Verdana, Arial and Courier you can hardly expect others to have the certain exotic fonts installed on their computers. One font might be available by default in Windows, but not in Linux, and vice versa.

Creating images by hand has several drawbacks. If you change the heading text you have to redraw your image. If headings are database-bound you have no way of keeping up drawing images by hand. The whole process has to be automated.

Shaun Inman came up with a technique now known as Scalable Inman Flash Replacement (sIFR). sIFR allows you to place a bit of Flash that draws text with your choice of fonts. You can see it in action on his site and that of Mike Davidson. Mike and a couple of other creative individuals have been working on open source (so to say) code that makes sIFR a reality. You can download the latest and greatest of this development from Mike's site. If y'all want to see some hardcode, "object oriented" JavaScript coding, take a look at the source code. Them folks did a fine job!

Ever since this initiative set sail, I've been wondering if there was a way to do the same by using .NET libraries and do it without reliance on Flash. GDI+ seemed to be the right alternative. What's GDI+?

GDI+ is the portion of the Microsoft® Windows® XP operating system that provides two-dimensional vector graphics, imaging, and typography. GDI+ improves on GDI (the graphics device interface included with earlier versions of Windows) by adding new features and by optimizing existing features.

The GDI+ managed class interface (a set of wrappers) is part of the Microsoft .NET Framework, an environment for building, deploying, and running XML Web services and other applications.

I thought I could get GDI+ to create image files on the fly and embed them in headings much like sIFR does.

I attempted to extend the JavaScript code Mike made available, but I realized a few bits and pieces would've been redundant, such as Flash detection, creation of object and embed elements, etc. Therefore I changed it to create images with the help of a light-weight HttpHandler.

Roll Your Own Headings

I don't want to go into the nitty-gritty implementation details, so I encourage you to check out source code on your own. Let me briefly discuss how you can use image replacement on your site.

First and foremost, you need a link to the external JavaScript file:

<script src="dotIR.js" type="text/javascript"></script>

This file is where all of the client-side processing happens. Next, you need to indicate which headings to replace. The original JavaScript code parses selectors (all h1s in the code below) and passes some additional parameters to the server-side code:

<script type="text/javascript">
if (dotIR != null)
 {
   dotIR.replaceElement ("h1", "#990000", "#ccc", 490, 
        "center", 42, "Book Antiqua");
 }
 </script>

A little bit of CSS helps hide the original content:

span.dotIR-alternate {
   position: absolute;
   left: -100em;
   width: 100em;
 }

.dotIR-replaced {
   visibility: visible !important;
 }

The parameters are:

  1. Elements to locate on the page. You may use classes (e.g. h3.sidebox) and IDs (e.g. h5#pullquote).
  2. Font color.
  3. Background color.
  4. Maximum width of the heading in pixels.
  5. Alignment. Allowed values are: "left" (default), "center", "right".
  6. Font size in pixels.
  7. Font name. This font has to be installed on the server.

The lightweight HttpHandler uses GDI+ to measure the height of the image box given the maximum width (parameter #4) and font size (parameter #6). This guarantees your text won't be clipped.

What About Quality?

I've tried tweaking anti-aliasing and contrast properties to get the best quality possible. The image handler streams a JPEG which offers better quality than GIF (at least, in this case). The quality of text is far from being perfect. On a white background it looks pretty darn good. On colored backgrounds you will see some noise, especially with small fonts.

I'm sure some of you are much better versed in GDI+ than me. Please, look through the code and let me know how to improve image quality. So far I've used only native GDI+ algos.

There's an online demo for you to see what it all looks like.

What About Accessibility?

If someone disables images you will still see the header text in the image placeholder. The image's alt attribute is what reveals it. With JavaScript disabled no substitution takes place, so the user will see the original heading text. I'm not sure how screen readers will take this. Let me know if you have one.

I've run the demo page in Lynx, and it displayed the heading itself without an image.

Improvements

This is fresh beta code, so there's a lot of room for improvement. I'll look into text size units other than pixels. I'm also thinking about caching images for 6 hours at a time, for example. Please, pitch ideas and suggestions. Feel free to download source code.

Upadate: to read about further improvements and download beta 2 code see .IR: Image Replacement With ASP.NET (Beta 2).

Comments

Comment permalink 1 Mike Gale |
I've always had an uneasy feeling about raster for fonts.

Yesterday I had another look at WEFT (Windows Embedded Font Tool, free from Microsoft look for WEFT) which enables you to upload any suitably enabled True Type Font to an IE browser. I had a different font on a web page within minutes, all through CSS. I'm not entirely happy with my initial choice of font. (I haven't yet checked what happens in Mozilla.)

I used this in an earlier incarnation and was pleased with what it did. The latest version (3.2) was released in 2003, so it looks as though development is happening.

Anyone used this a lot? If so, what's your experience?

In the long run I'd really like to define my own fonts. The closest thing I've heard to my idea is a, now unavailable, product called Font Chameleon.
Comment permalink 2 Milan Negovan |
One of the main driving forces behind image replacement is its universal application across browsers. It might never look perfect, but for the lack of support of font downloading this is as good as it gets, be it Flash or plain images.

The quest is still on. There's no perfect solution that satisfies all permutations of CSS on/off, images on/off and JavaScript on/off.
Comment permalink 3 Morgan |
Milan,

One of the problems you'll find with this solution is the graininess of the image - this is due to a limitation of GDI+ which you can overcome if you pass the resultant image through a quantization step.

Check out the Quantization article I wrote last year on MSDN. Using this with generated images should provide just the thing you need.

Hope this helps!
Comment permalink 4 Mike Gale |
That quantization is very impressive.

I checked the embedded fonts (@font-face in the CSS and an eot file on the server) using two browsers with Gecko builds (20040803 and 20040113). Both rendered the page using the embedded fonts. Very pleasing.

So this seems to work with IE and Firefox.
Comment permalink 5 Mark Wubben |
Nice adaptations man! It's really cool to see technology reused in such a way. Just keep checking back for new sIFR versions ;-)
Comment permalink 6 Joseph Swenson |
View nice! I was struggling to find a way to make this output transparencies and found a good article by Eric W. Bachtal on GDI+ transparencies here :

http://ewbi.blogs.com/develops/2005/08/sparklines_22.html

After a few modifications I was able to make your code output transparencies which is what I needed.
Comment permalink 7 Mark Melville |
I made a small change to the code to allow it to be able to use any font (TTF file) residing on the server, and not just one installed on the server:

PrivateFontCollection fontColl = new PrivateFontCollection();
fontColl.AddFontFile(System.Configuration.ConfigurationSettings.AppSettings.Get(ctx.Request.QueryString ["fn"]));
Font font = new Font(fontColl.Families[0], (float)fontSize.Value, FontStyle.Regular, GraphicsUnit.Pixel);

Then I pointed the "Font Name" in the Web.Config to the path of the TTF.
Comment permalink 8 Mark "Jumping the Gun" Melville |
Whoops! I just discovered that you have a Beta 2, in which it's already been done! Sorry for the useless posts, including this one.
Comment permalink 9 Milan Negovan |
It's all right. I do need to organize my projects better.
Comment permalink 10 Dave |
GREAT stuff, thanks so much for the article. If you are not too concerned about accessibility issues (although I suppose everyone should be), you can skip the JS altogether and just reference an IMG tag with the .ashx file as the SRC attribute, and append all of the querystring variables. Makes the loading very clean. Not too much of a stretch to just make a custom control that turns all of those attributes into parameters for the custom control; wraps everything up into a neat bundle.

Again, thanks!!
Comment permalink 11 Maximilian |
Although this thread is very old I really liked the technique and technology which was introduced here. Great Job!
What I did was that I created a new class project and wrapped all stuff together in a Control.
What you need to do is: 1) Drag the control on your page 2) Sepcify in the control's properties which elements should be rplaced 3) Register your http handler in your web.config

You will be able to get IR working in less than 10 minutes.

I also added new features like caching, transparency of gifs and the new sIFR code so you can have more specific css class/id mappings.

You can download the code and the control at http://www.mbeller.de/
Comment permalink 12 Milan Negovan |
Good stuff, Maximilian. Many thanks!
Comment permalink 13 Eamon Brennan |
Hello everyone

Thanks very much to all those involved in dotIR. Its been a wonderful solution.

We do have one little issue though. When I put a question mark at the end of a headline. It generates an error emessage in asp.net. Can this be avoided?
Comment permalink 14 Milan Negovan |
Eamon, good to hear you've found .IR helpful!

What is the error you get there? I've had lots of post titles ending with a question mark, but never had any problems. I'm curious though why it would happen.

Can you elaborate on your obseration a little more?
Comment permalink 15 Maximilian |
Well I finally released a quite stable version of the .NET library I have announced some month ago... :) sorry for the laziness.
You can download it at my site http://www.mbeller.de/

I am looking forward to feedback!
Comment permalink 16 Maximilian |
You can view a Live-Demo of my control here:
http://beller-arabi-hashemi.de/IRSample/

Emails and Notifications

Would you like to be notified when somebody responds to this post?  Would you like to have these comments emailed to you?

TrackBacks

Sorry, TrackBacks are not allowed.

Submit your comment

Please enter only text since all HTML tags except hyperlinks will be stripped. Hyperlinks will become live links. Any comments with flaming or offensive language will be deleted. Be courteous to other posters. Thank you.

Your name (required):
Your email (optional):
Your site's URL (optional):
Enter this number
Type in the number above:
Comment (required):