Click here to Skip to main content
15,883,883 members
Articles / Web Development / ASP.NET
Article

Rotated Text Image Overlay Control

Rate me:
Please Sign up or sign in to vote.
4.00/5 (7 votes)
9 Aug 20037 min read 80.9K   2.6K   39   3
ASP.NET control to overlay rotated text on images.

Sample Image - RotatedTextImageControl.png

Introduction

Have you ever wanted to be able to display rotated text on a web page? Have you ever been handed a web site design from a graphic designer only to realize that every button, tab and other bit of text has suddenly turned into an image? Have you ever wanted to overlay the same text on all the images provided by part of your site - e.g. a copyright message?

Well I had and I was bored of creating, and more than that, maintaining collections of images just to do some basic text overlay. So I created this project.

Background

While not essential, it does make the project easier to use, if you make sure the user aspnet_wp runs as (normally ASPNET) has write access to your virtual directory location. For the RotateTextImage control to work, it needs a file called HaleyRotateText.aspx (or whatever you set as the AspxFile property of the control) in the web application. The AspxFile property of the control should be set to a relative web path from the path containing page, to the location of the HaleyRotateText.aspx file. (If the page is in the same directory as all your other pages, then you can leave this property blank) If the user that your aspnet_wp process runs under (normally ASPNET) has write access to this path, then the file will be created automatically the first time the control is executed. If for security reasons this isn't the case, you will need to create the file with the following contents.

ASP.NET
<%@ Page language="c#" AutoEventWireup="false" 
          Inherits="Haley.RotateText.Control.RotateText" %>

For ease of setup, the demo includes a built version of the source. So once you have downloaded the demo, unzip the file into a new directory and create a new virtual directory in IIS to point at it. Running the demo should then be as simple as running up Test.aspx or Test2.aspx from there. To build the source, just unzip the source code to a new directory on in VS2003 and hit build. If you are playing with it much, it will probably be helpful to add both projects to the same solution.

Using the code

The code can logically be broken down into 4 sections:

  • The objects that provide the definition of an image we wish to create.
  • Image generation.
  • The APS.NET control and page used to deliver the images
  • Caching

    Defintion objects

    • RotatedTextDefn - the main definition of the image requirements.
    • Border - provides a basic encapsulation of 4 borders, used to describe padding, margins, borders etc.
    • Corner - provides basic encapsulation of height and width to describe the size of a corner rectangle as distances from the actual corner.
    • ScalingDefn - provides encapsulation of how to cut and scale the different parts of the image.
    • BorderTypeConverter - type converter for the Border object.
    • CornerTypeConverter - type converter for the Corner object.
    • ScalingDefnTypeConverter - type converter for the ScalingDefn object.

    The basic classes are little more than encapsulations of a bunch of value properties. The TypeConverters are required to enable the Expandable features of the property grid. Getting the expandable property grid to work was not as easy as you might have thought. There are 2, what now seem like simple steps:

    Each of the properties need to be tagged with the following attributes:

    C#
    [NotifyParentProperty(true), 
     RefreshProperties(RefreshProperties.All),
     DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

    Each of the expandable objects need to have a type converter that inherits from ExpandableObjectConverter. The type converter overrides 2 methods as follows:

    C#
    public override PropertyDescriptorCollection 
           GetProperties(ITypeDescriptorContext context, 
           object value, Attribute[] attributes)
    {
        // return the list of properties ordering as we want
        string [] names = {"TopBorder", "BottomBorder", 
                           "LeftBorder", "RightBorder", 
                           "TopLeft", "TopRight", 
                           "BottomRight", "BottomLeft"};
            PropertyDescriptorCollection pdc =  
                           TypeDescriptor.GetProperties
                           (value,attributes).Sort(names);
            return pdc;
    }
                                    
    public override object ConvertTo(ITypeDescriptorContext context, 
          CultureInfo culture, object value, Type destType) 
    {
        if (destType == typeof(string) && value is ScalingDefn) 
        {
            ScalingDefn sd = (ScalingDefn)value;
            return "Expand for values";
        }
        if(destType == typeof(InstanceDescriptor))
        {
            // Create an instance descriptor for the type so that it
            // can be recreated from a list of properties
            System.Reflection.ConstructorInfo constructor;
            constructor = typeof(ScalingDefn).GetConstructor
                 (new Type[] {typeof(Corner),typeof(Corner),
                 typeof(Corner),typeof(Corner), typeof(int),
                 typeof(int),typeof(int),typeof(int)});
            ScalingDefn sd = (ScalingDefn)value;
            return new InstanceDescriptor(constructor,
                new Object[] {sd.TopLeft, sd.TopRight, 
                sd.BottomRight, sd.BottomLeft, 
                sd.TopBorder, sd.BottomBorder, 
                sd.LeftBorder, sd.RightBorder});
        }
        return base.ConvertTo(context, culture, value, destType);
    }

    Image generation

    Image generation is done by the ImageGenerator class. It takes a RotatedTextDefn and returns an image as either a Bitmap object or a byte[] of PNG image data. Image generation can be broken down into 2 basic parts:

    • Creation of the background image
    • Overlaying of the text

    Creation of background image

    The background image can be created in a variety of ways:

    • The most basic is just a straight background color.
    • Next is providing a background image that can be scaled to fit.
    • Most complex is providing a background image and a ScalingDefn that describes how to extract and scale different parts of the image.

    The scaling definition defines 3 sets of areas as follows:

    • 4 corners which are not scaled at all.
    • 4 borders which are stretched along the edge between the corners.
    • The centre which is the largest rectangle not overlapped by any of the other parts of the image and is stretched across the entire background before the other parts are copied on.

    The size of the background is worked out either by the Height and Width properties or if these are null, then we calculate what size it needs to be to fit the rotated text and specified padding on.

    Overlaying the text

    In order to overlay the text in the right place, we need to create 4 transformations:

    • One to rotate the text.
    • One to move the rotated text to the right place in the image.
    • One to cope with offsets due to padding and alignment specifications.
    • One to cope with repositioning text that was center or right paragraph aligned.

    The Control & Image page

    The control is just a simple wrapper round the definition objects and the generator that allows it to be dropped easily onto web forms. The image page is a thin aspx page that streams the byte[] of image data back to the client, when it receives a request. The details of how the control works are covered more in the caching section.

    Caching

    There are 2 types of caching in use in the project.

    • Caching of images as byte[] data - this is permanent until aspnet_wp restarts.
    • Caching of RotatedTextDefn objects - these timeout after 2 minutes.

    The ImageCache object handles both. The custom control caches images as byte[] the first time a control executes that has its CacheName property set. From then on, any request for an image with that CacheName will be served directly out of the memory cache with no generation overhead. Images generated in code can be written into the cache, say at application startup, and then accessed by instances of the control that have their CacheName property set. The control caches RotatedTextDefn objects. It does this because, to provide the functionality, it writes an IMG tag to the page that looks like this:

    btml
    <img id="Rotatetextimage3" 
       src= "./HaleyRotateText.aspx?Defn=7525ea7f-440c-4672-86fa-65353672c30b
       &CacheName=Image1" />

    When this request is processed by the server, it first checks to see if an image exists in the cache for the CacheName=Image1. If not, it retrieves the definition from the cache using the guid provided in the querystring, generates the image and then adds it to the image cache, so future calls do not have to generate it. If the CacheName was not specified, the generated image would not be stored and so would need to be regenerated next time.

    Caching as images can serve 2 purposes, it can enhance the speed of your site which is always important, but it can also allow the site to work behind load balancing servers where the return request is not guaranteed to be directed to the same machine and so any temporarily cached definition may not be there. Creating and caching images as required in the global.asax at startup will get round this. While not practical for large quantities of images, it would be fine for things like tabs, buttons, bits of styling etc.

    Advanced image creation

    In order to be able to create more advanced images, it is possible via code to create an image either as a Bitmap or byte[] and set this to be the input for another definition. When creating the image, the generator looks at the 3 properties in this order to determine what to use for the background: BackgroundImageBitmap, BackgroundImageBytes, BackgroundImageFile. The test.aspx included in the demo gives an example of this.

    Future enhancements

    • Caching of images to disk to reduce memory overhead.
    • Option to change the output format of the images - currently they are all PNG.
    • Transparency - IE currently doesn't support PNG transparency and they are licensing, and palette size issues with using GIFs.

    History

    • 08 August 2003 - Initial version

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    Web Developer
    United Kingdom United Kingdom
    Paul has a background in VB / C++ COM development and has now converted to dotNET, coding in C# for the financial markets industry for the last 3 years.

    Comments and Discussions

     
    GeneralThanks - you rock! Pin
    sculptnz11-Jun-06 14:32
    sculptnz11-Jun-06 14:32 
    Generaltext rotate component Pin
    davidbeseke28-Jul-05 9:31
    davidbeseke28-Jul-05 9:31 
    GeneralRe: text rotate component Pin
    Paul Haley30-Jul-05 2:39
    Paul Haley30-Jul-05 2:39 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.