C# ASP.NET: Generating Image Buttons with Dynamic text

After writing several websites with custom buttons. I’ve had it with having to create images for each button that has a different text!

If you feel the same way then you’ll love this solution. With the code below you’ll be able to create a button.aspx page that takes a “t” url query parameter where you can specify the text and it will return the desired image. Here are some usage examples:

http://siteurl.com/button.aspx?t=Yes!” will give you:

http://siteurl.com/button.aspx?t=BACK&m=t” will give you:

http://siteurl.com/button.aspx?t=CONTINUE” will give you:

Even though the links to the image are not your usual *.png or *.jpg, the button.aspx page returns an image (content type image/x-png or image/jpeg) so it is OK to do the following in your aspx code:

<asp:ImageButton runat="server" ID="btnFormBack" ImageUrl="button.aspx?t=Continue" />

OR

<a href="targeturl.html"><img src="button.aspx?t=Continue" /></a>

Pretty cool ha!

Well, and now to the code. This is your button.aspx file:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="button.aspx.cs" Inherits="controls_button" %>
<%@ OutputCache VaryByParam="m;t" Duration="9123123" %>

And your button.aspx.cs file:

public partial class controls_button : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var text = this.Request.QueryString["t"];
        if (string.IsNullOrEmpty(text))
            throw new ApplicationException("The text url parameter must be specified");

        var sMirror = this.Request.QueryString["m"];
        bool mirror = (!string.IsNullOrEmpty(sMirror) && sMirror == "t");

        var rightImageWidth = 10; // in pixels
        var imageHeight = 42;
        var topPadding = 11; // top and bottom padding in pixels
        var sidePadding = 10; // side padding in pixels
        var textBrush = new SolidBrush(Color.White);
        var font = new Font("Arial Black", 11);


        //-------- Calculate the text's width
        // this graphics and bitmap object is just temporary. I could not 
        // find a way to calculate the text' width witout having one.
        var bitmap = new Bitmap(300, 300);
        var graphics = Graphics.FromImage(bitmap);
        var textSize = graphics.MeasureString(text, font);
        bitmap.Dispose();
        graphics.Dispose();

        //-------- Create the graphics object
        var bitmapWidth = sidePadding * 2 + (int)textSize.Width;
        bitmap = new Bitmap(bitmapWidth, imageHeight);
        //bitmap = new Bitmap(500, 40);
        graphics = Graphics.FromImage(bitmap);

        // Draw the background
        var leftImage = System.Drawing.Image.FromFile(this.Server.MapPath("~/resources/button-left.png"));
        var rightImage = System.Drawing.Image.FromFile(this.Server.MapPath("~/resources/button-right.png"));
        graphics.DrawImage(leftImage, 0, 0, bitmapWidth - rightImageWidth, imageHeight);
        graphics.DrawImage(rightImage, bitmapWidth - rightImageWidth, 0, rightImageWidth, imageHeight);
        // These disposes are necessary, otherwise the files get locked 
        leftImage.Dispose();
        rightImage.Dispose();

        if (mirror)
            bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX);

        // Draw the text
        graphics.DrawString(text, font, textBrush, sidePadding, topPadding);

        
        //-------- Serve the Image

        this.Response.ContentType = "image/x-png";
        
        // The line below breaks on the production and development servers
        // (it does not break on my computer). I was getting the following
        // vague exception "A generic error occurred in GDI+". I found this 
        // post that showed
        // me the work around http://aspalliance.com/319 . In short it says
        // that some image formats (like Png) require a seekable stream when 
        // saving. The Response.OutputStream is not seekable so we
        // have to use a MemoryStream as an intermediary.
        //bitmap.Save(this.Response.OutputStream, ImageFormat.Png);

        var memStream = new System.IO.MemoryStream();
        bitmap.Save(memStream, ImageFormat.Png);
        memStream.WriteTo(this.Response.OutputStream);

        // Some cleanup, not sure if it is all needed
        this.Response.End();
        memStream.Dispose();
        graphics.Dispose();
        bitmap.Dispose();
    }
}

And you also need to have these images in the ~/resources folder of your website. If you want to have them in another folder, update the .cs code.

~/resources/button-left.png :

~/resources/button-right.png :

Enjoy!

Advertisements

One thought on “C# ASP.NET: Generating Image Buttons with Dynamic text

  1. Thanks for this. Updated it so you can use 3 images (one for left, center and right):

    public partial class controls_button : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    var text = this.Request.QueryString[“t”];
    if (string.IsNullOrEmpty(text))
    throw new ApplicationException(“The text url parameter must be specified”);

    var sMirror = this.Request.QueryString[“m”];
    bool mirror = (!string.IsNullOrEmpty(sMirror) && sMirror == “t”);

    var rightImageWidth = 28;
    var leftImageWidth = 26;
    var imageHeight = 40;
    var topPadding = 11;
    var sidePadding = 28;
    var textBrush = new SolidBrush(Color.Black);
    var font = new Font(“Arial”, 8);

    var image = new Bitmap(300, 300);
    var graphics = Graphics.FromImage(image);
    var textSize = graphics.MeasureString(text, font);
    image.Dispose();
    graphics.Dispose();

    var imageWidth = sidePadding * 2 + (int)textSize.Width;
    image = new Bitmap(imageWidth, imageHeight);

    graphics = Graphics.FromImage(image);

    var leftImage = System.Drawing.Image.FromFile(this.Server.MapPath(“~/Images/TextImageButton/left.png”));
    var centerImage = System.Drawing.Image.FromFile(this.Server.MapPath(“~/Images/TextImageButton/center.png”));
    var rightImage = System.Drawing.Image.FromFile(this.Server.MapPath(“~/Images/TextImageButton/right.png”));

    graphics.DrawImage(leftImage, 0, 0, rightImageWidth, imageHeight);
    graphics.DrawImage(centerImage, leftImageWidth + 2, 0, imageWidth – (leftImageWidth + rightImageWidth + 1), imageHeight);
    graphics.DrawImage(rightImage, imageWidth – (rightImageWidth – 1), 0, rightImageWidth, imageHeight);

    leftImage.Dispose();
    centerImage.Dispose();
    rightImage.Dispose();

    //if (mirror)
    // image.RotateFlip(RotateFlipType.RotateNoneFlipX);

    graphics.DrawString(text, font, textBrush, sidePadding, topPadding);

    this.Response.ContentType = “image/x-png”;

    var memStream = new System.IO.MemoryStream();
    image.Save(memStream, ImageFormat.Png);
    memStream.WriteTo(this.Response.OutputStream);

    this.Response.End();
    memStream.Dispose();
    graphics.Dispose();
    image.Dispose();
    }
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s