Images on the Fly in ASP.NET

Introduction

Here's the scenario, you have a client that runs banner ads on their website. The client now wants to customize their banner ads when a user is logged in. That is, when Bob comes and logs in to the website they want the top of the banner ad to read "Hey Bob!". Now, you could obviously achieve the same results by simply having text over a background image in a table cell. However, the font that your client uses is very unusual and they want to be sure that the text on the image is the same font as they use throughout the rest of their website images.

The Project Code

The login form and code:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ImageOnTheFlyExample.aspx.vb" Inherits="QuinStreetSampleScripts.ImageOnTheFlyExample" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Images on the Fly Example</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <table border="1" cellpadding="5" cellspacing="0" style="width: 500px">

            <tr>

                <td colspan="2" style="font-size: 18pt; color: yellow; font-family: 'Baskerville Old Face';

                    background-color: maroon">

                    Images on the Fly Example</td>

            </tr>

            <tr>

                <td valign="top">

                    <strong>User Login<br />

                    </strong>

                    <br />

                    Name:

                    <asp:TextBox ID="TextBoxUserName" runat="server" Width="300px"></asp:TextBox><br />

                    <br />

                    <asp:Button ID="ButtonLogin" runat="server" Text="Login" /><br />

                </td>

                <td valign="top">

                    <asp:Image ID="ImageCustomAd" runat="server" AlternateText="Images on the Fly - Example Ad"

                        ToolTip="Images on the Fly - Example Ad" ImageUrl="~/images/BannerAdExample03242010.jpg" /></td>

            </tr>

        </table>

    </div>

    </form>

</body>

</html>

ImageOnTheFlyExample.aspx.vb

Partial Public Class ImageOnTheFlyExample

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

    End Sub

 

    Protected Sub ButtonLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonLogin.Click

        Me.ImageCustomAd.ImageUrl = "~/ImageOnTheFlyOutput.aspx?text=" & HttpUtility.UrlEncode(Me.TextBoxUserName.Text.Trim)

    End Sub

 

End Class

The page and code that renders the image:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ImageOnTheFlyOutput.aspx.vb" Inherits="QuinStreetSampleScripts.ImageOnTheFlyOutput" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    </form>

</body>

</html>

ImageOnTheFlyOutput.aspx.vb

Imports System.IO

Imports System.Drawing

Imports System.Drawing.Imaging

Imports System.Drawing.Text

Imports System.Drawing.Drawing2D

 

Partial Public Class ImageOnTheFlyOutput

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        ' Get text to be displayed from querystring

        Dim MyUsernameText As String = "Hey, " & Request.QueryString("text") & "!"

        ' Declare image and output variables

        Dim MyBitmap As Bitmap

        Dim MyMemoryStream As New MemoryStream

        Dim MyGraphics As Graphics

        Dim MyGraphicsPath As New GraphicsPath

        Dim MyBrush As SolidBrush = New SolidBrush(Color.White) ' You can also use custom RGB colors

        Dim ContentStartPoint As New System.Drawing.Point(5, 5)

        Dim ContentWorkArea As New System.Drawing.Size(90, 30) ' Space where drawing will occur - (width, height)

        Dim MyImageRectangle As Rectangle = New Rectangle(ContentStartPoint, ContentWorkArea)

        ' Font variable - defines font family, font size, font style and font size type

        Dim MyFont As Font = New Font("Baskerville Old Face", _

                                      14, _

                                      System.Drawing.FontStyle.Regular, _

                                      System.Drawing.GraphicsUnit.Point)

        ' Set formatting

        Dim MyFormat As StringFormat = New StringFormat

        MyFormat.Alignment = StringAlignment.Center

        MyFormat.LineAlignment = StringAlignment.Center

        ' Get base image

        Dim MyImage As Image = Image.FromFile(Server.MapPath("images/BannerAdExample03242010.jpg"))

        MyBitmap = New Bitmap(MyImage) ' For quality purposes use a bitmap as the base image

        ' Set resoltion

        MyBitmap.SetResolution(72, 72) ' 72x72 is an average resolution for web

        ' Build the image

        ' Set Graphics

        MyGraphics = Graphics.FromImage(MyBitmap)

        ' Set graphics quality

        With MyGraphics

            .InterpolationMode = InterpolationMode.HighQualityBicubic

            .CompositingMode = CompositingMode.SourceOver

            .CompositingQuality = CompositingQuality.HighQuality

            .TextRenderingHint = TextRenderingHint.AntiAlias

            .SmoothingMode = SmoothingMode.AntiAlias

        End With

        ' Add text and font/style definitions to GraphicsPath which is used in FillPath to actually create the text

        MyGraphicsPath.AddString(MyUsernameText, MyFont.FontFamily, MyFont.Style, MyFont.Size, MyImageRectangle, MyFormat)

        MyGraphics.FillPath(MyBrush, MyGraphicsPath)

        ' Clear and set response

        Response.Clear()

        Response.ContentType = "image/png" ' Note: this must match the ImageFormat type you choose below

        ' Use memory stream to output page as image

        ' Use PNG format for best quality output

        MyBitmap.Save(MyMemoryStream, ImageFormat.Png)

        MyMemoryStream.WriteTo(Response.OutputStream)

        ' Clean up

        MyBitmap = Nothing

        MyImage = Nothing

        MyGraphics.Dispose()

        MyGraphicsPath.Dispose()

        MyBrush.Dispose()

        MyFont.Dispose()

    End Sub

 

End Class

How it Works

There are two pieces to this project. First, there is the simple pseudo login form. This does nothing except provide a textbox, login button and our ad image. It's only function is to take whatever username is entered into the textbox and use that to generate our custom ad image. This is accomplished by setting the ImageUrl property to the page that renders our image with a query string containing the text entered in the textbox.

The interesting part of the project is the second piece which renders the custom image. In short, the page receives text to insert into our image from the querystring and builds the image from the base ad image, and then renders it via a Response.OutputStream.

Of course, it's not as simple as 1, 2, 3, so we'll break down the code for ImageOnTheFlyOutput.aspx. The first thing you should notice is that the project uses System.IO and several System.Drawing classes. You will also see everything happens within the Page Load event. The page has no controls, it simply renders an image, so there are no other events to consider here.

When the page loads the first order of business it to get the username from the quesrystring and create the nice little "welcome" phrase that will be inserted over the ad image. After that there are several variables that we will use to do all of the image rendering work. Now, I purposely used more variables than was really necessary so that everyone could see most of the different options available. In some cases for this example I am setting properties equal to their default values for illustrative purposes. Here is a quick breakdown of each variable's purpose:

  • MyBitmap - In order to build an image you must convert your base image to a bitmap, add your text, and then output the bitmap to whatever format you like. That makes this variable our blank canvas where we will create our image.
  • MyMemoryStream - Instead of our page rendering ASP.NET controls we are creating it to become an image generator using MemoryStream.
  • MyGraphics - This is the palette for the image. This variable determines how the graphics will be rendered onto our bitmap canvas. It's the paint type, brush type, etc. for our canvas.
  • MyGraphicsPath - This variable handles setting up rendering of text onto the image. It brings together the brush, font, text and format together. It's the sketch before the paint is applied.
  • MyBrush - This is exactly as it sounds. It determines the type of brush used when rendering along with the color.
  • ContentStartPoint - Here is the upper left corner position for the work area (defined below).
  • ContentWorkArea - This defines the size of the work area where you will be working.
  • MyImageRectangle - This puts the content work area and starting point together (defined above). It then becomes the boundaries within your image where your text will be rendered.
  • MyFont - This defines everything about the font you will be using for rendering which includes font name, size, size type and style.
  • Tip: If your image is not rendering the font as you expected it could be any one of three issues. The first is that the font is not installed on the server. The second is that the font is not a TrueType font (TrueType is the only type that will render correctly). Third, the font name is wrong or misspelled.

  • MyFormat -This defines the vertical and horizontal alignment of the text within your rectangle.

Now that you know what the variables are we'll do a simple walk-through of the code:

  1. Build the text from the querystring that will be inserted into the image.
  2. Define our work area rectangle using our starting point and work area variables. You can redefine this as many times as you like to put text in different areas of the image, however, we are only inserting text into one location.
  3. Define the font and format for our text.
  4. Get the base image and convert it into our working bitmap.
  5. Set the bitmap resolution and graphics settings. The graphics settings in the example will render a high quality image.
  6. Define the graphics path with our "welcome" string we created above. This includes definitions for font family, font style, font size, our work area rectangle, and text format.
  7. Use the MyGraphics variable to render our text onto the image.
  8. Clear and set our response.
  9. Save our bitmap as png to our memory stream which we then send to the output stream.
  10. Clean up our mess.

Common Questions

Can I output in other formats?

All of your standard formats like bitmap, gif, jpeg and png are available. However, for the best combination of quality and small footprint you should use png.

Can I use custom colors instead of the named colors?

You can use any RGB color that you like. You create custom colors using Color.FromArgb. What happens when the text exceeds the space allotted (MyImageRectangle)?

The class will attempt to wrap within your defined rectangle until it runs out of space. Anything beyond the bounds it simply not rendered. It does not "squish" the text into the allotted space.

Conclusion

I know the scenario is a bit absurd but it served its purpose for the example. In reality creating images can be very useful for specific circumstances. For example, you could easily watermark sample images using this technique for websites that sell stock photography. This would save much time and effort over manually creating images with a watermark. It would also allow you to automatically keep the copyright year in the watermark up to date. Another use (this one I have implemented before) might be for a printing company that wants to allow its users to preview custom print products before they order. Even though the practical applications are limited, the ability to create images on the fly can be a very powerful tool.

Note: The example here was built in ASP.NET 2.0. However, the classes used are included in ASP.NET 1.1 through 4.0 and have remained virtually unchanged since ASP.NET 1.1.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today make data protection a must-have, as we live in a data driven society. The digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join eVault Chief Technology …

  • "Security" is the number one issue holding business leaders back from the cloud. But does the reality match the perception? Keeping data close to home, on premises, makes business and IT leaders feel inherently more secure. But the truth is, cloud solutions can offer companies real, tangible security advantages. Before you assume that on-site is the only way to keep data safe, it's worth taking a comprehensive approach to evaluating risks. Doing so can lead to big benefits.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds