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

Run-time Image in ASP.NET using GDI+

Rate me:
Please Sign up or sign in to vote.
4.80/5 (5 votes)
12 Jun 2012CPOL 36.2K   442   14   11
How to make a dynamic/embedded image at run-time for an ASP.NET application using GDI+.

Sample Image

Introduction

This tip explains how to make a dynamic/embedded image at run-time for an ASP.NET application using GDI+.

Background

I searched around in Google and the only answer I could find was to make an ASPX page, hijack the Response.OutputStream, and change the Response.ContentType. This approach I think is far easier to work with, although older browser compatibility issues may come into play. Read about embedded image data and dataURI here: Wiki - Data_URI_scheme. There is also a Microsoft disclaimer for using GDI+ within ASP.NET. Anyway...

Using the code

Here is the code for the ASP.NET 'UserControl'. There is no mark-up code, and below is the code-behind.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.IO;

public partial class UserControls_ImageRender : System.Web.UI.UserControl
{   

    protected override void Render(HtmlTextWriter writer)
    {    
        writer.Write(@"<img src=""data:image/jpeg;base64,{0}"">", Data64);
    }

    public Bitmap bitmap
    {
        set
        {
            MemoryStream ms = new MemoryStream();
            value.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            Data64 = Convert.ToBase64String(ms.ToArray());
        }
    }

    private string Data64
    {
        get
        {
            string s = ViewState["Data64"] as string;
            return (s == null) ? string.Empty : s;
        }
        set
        { ViewState["Data64"] = value; }
    }
}

Register your control in web.config:

XML
<add tagPrefix="ctl" src="~/UserControls/ImageRender.ascx" tagName="ImageRender"/>

Add an example to use on your form:

XML
<ctl:ImageRender id="Image1" runat="server"/>

Use this Control, by setting the bitmap property.

C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        Image1.bitmap = MakeImage();
    }
}
	
// make your own GDI+ image here. Here is my example...
public Bitmap MakeImage()
{
    DateTime dt = DateTime.Now;
    string sHeading1 = "asd";
    string sMachineSerial = "asdasd";
    string sText1 = "rtu";
    string sText2 = "uiouiouio";
    string sText3 = "dfgbftyfy";

    Bitmap bitmap = new System.Drawing.Bitmap(400, 200);
    Graphics g = System.Drawing.Graphics.FromImage(bitmap);
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    System.Drawing.Font drawFontAGBoldSmall = new System.Drawing.Font("Arial", 8);
    System.Drawing.Font drawFontAGBold = new System.Drawing.Font("Arial", 12);
    System.Drawing.Font drawFontAGBook = new System.Drawing.Font("Arial", 12, FontStyle.Bold);
    System.Drawing.Font drawFontAGBookDate = new System.Drawing.Font("Arial", 24);
    System.Drawing.Font drawFontAGBookHeading = new System.Drawing.Font("Arial", 16, FontStyle.Bold);
    System.Drawing.Font drawFontArial = new System.Drawing.Font("Arial", 12, FontStyle.Bold);

    Color myColor = ColorTranslator.FromHtml(@"#F0F0F0");
    System.Drawing.SolidBrush drawBrush = new System.Drawing.SolidBrush(myColor);

    System.Drawing.StringFormat drawFormat = new System.Drawing.StringFormat();
    System.Drawing.StringFormat drawCentreFormat = 
           new System.Drawing.StringFormat(StringFormatFlags.NoWrap);
    drawCentreFormat.Alignment = StringAlignment.Center;

    Pen drawPen = new Pen(drawBrush);

    g.DrawRectangle(drawPen, new Rectangle(0, 0, bitmap.Width - 1, bitmap.Height - 1));

    g.DrawString(dt.ToShortDateString(), drawFontAGBookDate, drawBrush, 
                 new Rectangle(0, 36, 400, 40), drawCentreFormat);
    g.DrawString(sHeading1, drawFontAGBookHeading, drawBrush, new Rectangle(4, 0, 392, 26), drawFormat);
    g.DrawString(sMachineSerial, drawFontAGBoldSmall, drawBrush, new Rectangle(8, 22, 392, 14), drawFormat);
    g.DrawString(sText1, drawFontAGBold, drawBrush, new Rectangle(8, 80, 192, 20), drawFormat);
    g.DrawString(sText2, drawFontAGBold, drawBrush, new Rectangle(8, 101, 192, 20), drawFormat);
    g.DrawString(sText3, drawFontAGBold, drawBrush, new Rectangle(8, 122, 192, 20), drawFormat);

    drawFontAGBook.Dispose();
    drawFontAGBold.Dispose();
    drawFontArial.Dispose();
    drawBrush.Dispose();
    drawPen.Dispose();
    g.Dispose();

    return bitmap;
}

End

All done! As my son would write, thanks for listening!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralBase64 vs. Content-type Pin
David A. Gray21-Jun-12 9:17
David A. Gray21-Jun-12 9:17 
QuestionI wont vote but: Pin
HaBiX14-Jun-12 20:12
HaBiX14-Jun-12 20:12 
AnswerRe: I wont vote but: Pin
Richard Leiser14-Jun-12 22:49
Richard Leiser14-Jun-12 22:49 
GeneralRe: I wont vote but: Pin
HaBiX14-Jun-12 23:01
HaBiX14-Jun-12 23:01 
GeneralRe: I wont vote but: Pin
Richard Leiser15-Jun-12 3:17
Richard Leiser15-Jun-12 3:17 
Your overall approach would suit most people, most of the time but that's not the nut I'm trying to crack.
Your method requires the drawing to be done within the DynamicPictureGenerator page, mine doesn't - you set the "bitmap" field of the control. So your way I would have to pass arguments over in the QueryString to say what kind of image I would like drawn.

Normally not a whole lot of difference - you have to put the code somewhere right. But as I say my control stands alone, with a nice coding interface.

Image1.bimap = CreateBitmap(TextBoxProductWidth.Text, TextBoxProductHeight.Text, TextBoxProductLength.Text);

Rather than...

Image2.Src = String.Format("DynamicPictureGenerator.aspx?Args={0},{1},{2}",TextBoxProductWidth.Text, TextBoxProductHeight.Text, TextBoxProductLength.Text);
isn't that intuitive.

I tried your approach, but it's not x4 as big.

For a test image:
my base64 string was 9kB, and the same rendered jpeg image was 7k.

In terms of bandwidth though, the short coming of my method is that the ViewState also carries a copy of the image too. BUT you could alter that and instead re-render \ draw the Bimap on each post back, which is also what has to happen anyway with your method.

As for the cache, the image can change after each and every postback. So caching the image is exactly what you don't want. I don't want to see a previously stored, now 'wrong to go with the rest of the page' image.
GeneralRe: I wont vote but: Pin
HaBiX15-Jun-12 6:15
HaBiX15-Jun-12 6:15 
Generalsome great feedback Pin
Richard Leiser15-Jun-12 13:14
Richard Leiser15-Jun-12 13:14 
GeneralRe: some great feedback Pin
HaBiX17-Jun-12 20:31
HaBiX17-Jun-12 20:31 
GeneralMy vote of 5 Pin
Carsten V2.05-Jun-12 4:26
Carsten V2.05-Jun-12 4:26 
Questionhello Pin
beleshi3-Jun-12 23:44
beleshi3-Jun-12 23:44 

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.