harriyott.com

Dynamic numbered map pins with ASP.NET MVC

A mapping project I've recently been working on needed to have coloured, numbered pins to correspond to the numbered items shown in the list below the map, e.g.
Green 23 marker

I wanted the images to be created dynamically, as the numbers could reach into the hundreds, and I didn't fancy spending several days with Photoshop. I started with empty pin images (red, green, blue and black).
Empty marker

To improve performance, I decided to write the image to disk once I'd generated it, which I could just return in future calls. I also wanted to cache the image path, so I wouldn't have to access the disk to see if the image had been created already.

I added an ImageController class, and an Index action that took the colour as a string and the number as an integer:

public ActionResult Index(string colour, int number)

This would correspond to the url http://domain.com/image/green/23.png. I put the png extension so everything would know it was a png file. So after checking that an existing image for the colour and number didn't exist, one needed to be generated. I've not used the graphics classes in .NET before, so I was super excited about it. The first step was to load the correctly coloured image:

using (var stream = new FileStream(imageRoot + colour + ".png") {
  image = Image.FromStream(stream);
}

Now to draw the number on top of the image:

var g = Graphics.FromImage(image);
g.TextRenderingHint = TextRenderingHint.AntiAlias;
var stringFormat = new StringFormat
  {
    Alignment = StringAlignment.Center,
    LineAlignment = StringAlignment.Center
  };
g.DrawString(
  number.ToString(),
  SystemFonts.DefaultFont,
  Brushes.Black,
  new RectangleF(0f, 0f, image.Width, 33f),
  stringFormat);

This is just setting up the text style, defining a rectangle in the right place, then drawing the string into the rectangle. (I still can't help thinking of Speedos.) Then it was a simple case of saving the image for next time and returning it as a FilePathResult:

image.Save(imagePath, ImageFormat.Png);
return File(imageUrl, "image/png");

2 June 2010