Getting Started with Dynamic Images in ASP.NET

   

Before you can create any images, or use any graphics commands, you must decide what you will be drawing to. In a standalone application, you will draw to one of the application's windows . Those of you who have been doing Windows programming for a while now, either in VB or C++, are familiar with the notion of a device context . A device context is a Windows object that describes a device to which you will draw. The device might be a window, a printer, a disk file, or any other item that is suitable for receiving a drawing.

Because your ASP.NET application does not have a window in the classic sense to which it can draw, you must create some other object to which youwill draw. In this chapter I use bitmaps, and these bitmaps are encapsulated in a Bitmap class. So, all the code samples in this chapter begin by creating a bitmap destination object for the drawing. Actually, it would be more correct to refer to this object as a surface . This is a similar concept to the DirectX notion, in which all operations in DirectX are done to a surface. So for the rest of this chapter I won't refer to a device context; instead, I will refer to either a bitmap or a surface as the destination for all drawing operations.

Several bitmap constructors are available to you. But in this chapter I will exclusively use the constructor that accepts a width and a height each as integers, and pixel format argument. A pixel format argument is an enumeration that can be seen in Table 16.1.

Table 16.1. The Pixel Format Enumeration

Name

Description

Alpha

The pixel data contains alpha values that are not premultiplied .

DontCare

No pixel format is specified.

Format16bppArgb1555

The pixel format is 16 bits per pixel. The color information specifies 32,768 shades of color , of which 5 bits are red, 5 bits are green, 5 bits are blue, and 1 bit is alpha.

Format16bppGrayScale

The pixel format is 16 bits per pixel. The color information specifies 65,536 shades of gray.

Format16bppRgb555

The pixel format is 16 bits per pixel. The color information specifies 32,768 shades of color, of which 5 bits are red, 5 bits are green, and 5 bits are blue.

Format16bppRgb565

The pixel format is 16 bits per pixel. The color information specifies 32,768 shades of color, of which 5 bits are red, 6 bits are green, and 5 bits are blue.

Format24bppRgb

The pixel format is 24 bits per pixel. The color information specifies 16,777,216 shades of color, of which 8 bits are red, 8 bits are green, and 8 bits are blue.

Format32bppArgb

The pixel format is 32 bits per pixel. The color information specifies 16,777,216 shades of color, of which 8 bits are red, 8 bits are green, and 8 bits are blue. The 8 additional bits are alpha bits.

Format32bppPArgb

The pixel format is 32 bits per pixel. The color information specifies 16,777,216 shades of color, of which 8 bits are red, 8 bits are green, and 8 bits are blue. The 8 additional bits are premultiplied alpha bits.

Format32bppRgb

The pixel format is 32 bits per pixel. The color information specifies 16,777,216 shades of color, of which 8 bits are red, 8 bits are green, and 8 bits are blue.

Format48bppRgb

The pixel format is 48 bits per pixel. The color information specifies 16,777,216 shades of color, of which 8 bits are red, 8 bits are green, and 8 bits are blue. The 8 additional bits are alpha bits.

Format64bppArgb

The pixel format is 64 bits per pixel. The color information specifies 16,777,216 shades of color, of which 16 bits are red, 16 bits are green, and 16 bits are blue. The 16 additional bits are alpha bits.

Format64bppPArgb

The pixel format is 64 bits per pixel. The color information specifies 16,777,216 shades of color, of which 16 bits are red, 16 bits are green, and 16 bits are blue. The 16 additional bits are premultiplied alpha bits.

Max

The maximum value for this enumeration.

Palpha

The pixel format contains premultiplied alpha values.

Undefined

The pixel format is undefined.

The following code fragment creates a bitmap that is 300 pixels wide and 200 pixels high. It specifies a format of 24 bits per pixel in an RGB color space. I tend to use 24-bit images because most JPG images are 24 bits per pixel. When I generate dynamic images, I usually get a more accurate rendering when I use 24 bits per pixel than I do if I use saved JPG images. You must use the System.Drawing namespace in your code.

C#

 Bitmap newBitmap = new Bitmap( 300, 200, PixelFormat.Format24bppRgb ); 

VB

 Dim newBitmap As New Bitmap(300, 200, PixelFormat.Format24bppRgb) 

After you have created a bitmap you then need to obtain a graphics object that references that bitmap. It is similar to getting a device context in Visual Basic or Visual C++ programming. It is almost identical, though, to what you do in Java. In Java, you have an object named exactly the same thing: Graphics . In Java, you make a method call to getGraphics() , and then you use the Graphics object for all draw operations. In ASP.NET (for a bitmap as we have created) you use the static FromImage() method. The FromImage() method takes as an argument the bitmap to which you want to draw and returns a Graphics object that references the bitmap. You use this Graphics object, then, for all subsequent drawing operations. You can see in the next line how to obtain a Graphics object from the newly created bitmap.

C#

 Graphics g = Graphics.FromImage( newBitmap ); 

VB

 Dim g As Graphics = Graphics.FromImage(newBitmap) 

I need to spend a short time now talking about pens and brushes. You cannot simply select a color, make some sort of call to the graphics API, and have your draw operation be preformed in that color. To draw a line or a line- related object in a certain color, you must create a Pen object. Pen objects are created with attributes such as a specified color, a width, and a style (such as dotted , dashed, or solid). Then, when you draw a line, you use a Pen object that you have created to let GEI.NET know how to draw the line. For example, if you want to draw a solid red line, you first create a pen and specify that it is red and the style is solid. You then call the Graphics object's DrawLine() method and specify your newly created line. The following code shows how to create a red pen and then draw a line using this newly created red pen:

C#

 Pen pen = new Pen( Color.Red );  g.DrawLine( pen, 10, 14, 100, 225 ); 

VB

 Dim pen as new Pen( Color.Red )  g.DrawLine( pen, 10, 14, 100, 225 ) 

The same idea holds true if you want to draw shapes that are solid in nature, such as a filled rectangle or a filled ellipse. Instead of a pen, though, you must create a SolidBrush , and the SolidBrush indicates the color with which you want to draw. The following example shows how to create a SolidBrush and draw a rectangle with it.

C#

 SolidBrush blueBrush = new SolidBrush( Color.Blue );  g.FillRectangle( blueBrush, 0, 0, 150, 100 ); 

VB

 Dim blueBrush as new SolidBrush( Color.Blue )  g.FillRectangle( blueBrush, 0, 0, 150, 100 ) 

And now it is time to complete this discussion of simple creation of bitmaps, obtaining a graphics, and then drawing to the Graphics object. Take a look at the code in Figure 16.1. This code draws four rectangles to a created bitmap, and then sends it out to the browser for display. The source code for the creation of the bitmap can be seen in Listing 16.1.

Figure 16.1. This simple code creates a bitmap, and then draws four rectangles.

graphics/16fig01.gif

I need to make several comments about the following code fragment, and more specifically about the call to the Save() method in the last line seen in Listing 16.1. The first thing you need to notice is that I saved the image to the Response.OutputStream object. As a result, the image bits are sent directly to the browser without being saved or loaded to disk. The only thing that the browser gets is the image; it gets no HTML. It is just as if you loaded an image in your browser outside the context of HTML. I also point out that I used this code rather than the Web form class's Page_Load() method. If I would have created a method such as a draw bitmap method, and then called it somewhere within the HTML creation process, it would have output what would have looked like garbage into the HTML stream, as shown in Figure 16.2.

Figure 16.2. Here the image was output to Response.OutputStream midway into the HTML rendering process.

graphics/16fig02.gif

Listing 16.1 Simple Code That Creates and Draws to a Bitmap Object
 Bitmap newBitmap = new Bitmap( 300, 200, PixelFormat.Format24bppRgb );  Graphics g = Graphics.FromImage( newBitmap );  SolidBrush blueBrush = new SolidBrush( Color.Blue );  SolidBrush redBrush = new SolidBrush( Color.Red );  SolidBrush greenBrush = new SolidBrush( Color.Green );  SolidBrush blackBrush = new SolidBrush( Color.Black );  g.FillRectangle( blueBrush, 0, 0, 150, 100 );  g.FillRectangle( redBrush, 150, 0, 150, 100 );  g.FillRectangle( greenBrush, 0, 100, 150, 100 );  g.FillRectangle( blackBrush, 150, 100, 150, 100 );  Response.ContentType="Image/Jpeg";  newBitmap.Save( Response.OutputStream, ImageFormat.Jpeg ); 

Another thing I want to point out is the image format enumerator that was used in the Save() method. The image format enumerator enables you to save your image in a variety of formats. They include BMP, GIF, JPG, PNG, and TIFF, among others. Table 16.2 lists the formats that are available to you in the image format enumerator.

Table 16.2. The Image Format Enumerations

Identifier

Description

Bmp

Specifies the bitmap image format (BMP).

Emf

Specifies the enhanced Windows metafile image format (EMF).

Exif

Specifies the Exchangeable Image Format (EXIF).

Gif

Specifies the Graphics Interchange Format (GIF).

Icon

Specifies the Windows icon image format.

Jpeg

Specifies the Joint Photographic Experts Group (JPEG) image format.

MemoryBmp

Specifies a memory bitmap image format.

Png

Specifies the W3C Portable Network Graphics (PNG) image format.

Tiff

Specifies the Tag Image File Format (TIFF) image format.

Wmf

Specifies the Windows metafile (WMF) image format.

You must be careful when you choose an image format for your save operations. Different formats give you different results. For example, JPG images are great for photographic images, but they are not very good when your images are sharp and crisp. If your images are sharp and crisp and you save in the JPG format, you notice unexplainable artifacts that make the image look less than perfect. GIF images are very good when the desired rendering must be sharp and crisp, but GIF is limited to colors with an eight-bit pixel depth. This limits you to a total of 256 colors in a given image. That means, if you have drawn to a bitmap in a color that is not available in a saved GIF image, those colors are mapped in a way that might be somewhat undesirable. For example, if you draw a color in a shade of green that cannot be found in the standard GIF file format palette, your green color will be dithered in a way that most closely approximates the color with which you drew. But it won't match the original.

So, if your image is counting on some specific colors that are not a part of the standard GIF palette, you need to consider using JPG. On the other hand, if your image needs to be crisp and sharp, you must select GIF. It is not always an easy decision, because you might want some of the things that each format has to offer.

There might be situations in your Web development when you need to create image banners at the tops of Web pages. The banners might need to be dynamically created based on the current situation. It is an easy manner to create a bitmap, draw to the bitmap, and then save it to disk. This image then can be loaded into a Web page as a banner at the top of the page.

I have created a fairly simple application that asks the user to type his name into a TextBox editable field. After the user has entered his name, he clicks the Submit button; a banner image is created; and then the banner image appears in the Web page. You can see this application as it is being executed in Figure 16.3.

Figure 16.3. This application creates a simple banner based on the user's name.

graphics/16fig03.gif

You should now take a look at the code in Listing 16.2. This is the ASPX code that was created for the banner creation application. The first thing to notice is that the code makes a call to the DisplayBanner() method. This method decides whether a banner has been created for this user, and if so it displays it by outputting the appropriate HTML code at this point. If no banner has been created, then nothing is output into the HTML stream here and the user does not see a banner.

Farther down in the code you can see the TextBox in which users type in their names. And directly after that is the button with which users submit their names to the C# code that creates and saves the banner to disk.

Listing 16.2 The .ASPX Code for the Banner Creation Application
 <form id="WebForm2" method="post" runat="server">    <% DisplayBanner(); %>    <P>      <asp:Label id="Label1" runat="server" Font-Size="XX-Large" ForeColor="White">Banner graphics/ccc.gif Creator</asp:Label>     </P>    <P>      <asp:Label id="Label2" runat="server" Font-Size="Medium" ForeColor="Yellow">Your Name: graphics/ccc.gif </asp:Label>      <asp:TextBox id="TextBox1" runat="server" Width="208px" Height="24px"></asp:TextBox>    </P>    <P>      <asp:Button id="Button1" runat="server" Text="Submit"></asp:Button>      <asp:Label id="Label3" runat="server" Visible="False"></asp:Label>    </P>  </form> 

Now take a look at the code in Listing 16.3, which is the code behind the ASP code you just looked at. This code performs the necessary operations to make the application function correctly.

Start by looking at the Page_Load() method. This method sets the Boolean variable m_bCreate to true if indeed this is a PostBack . It does this because if it is a PostBack , you can assume that the user has already typed in a name and clicked on the Submit button.

Next, you can see the DisplayBanner() method. If the m_bCreated variable is true (which happens only if this is a PostBack ), then the HTML code necessary to display the banner is output. Notice that the actual filename is created by concatenating the word image with the text contained in Label3.TEXT followed by the .JPG extension. The Label3.TEXT property contains the randomly generated file number from when the BannerImage file was initially created. It is stored in a label so that it will persist between PostBack s.

Listing 16.3 The C# Code for the Banner Creation Application
 bool m_bCreated = false;  private void Page_Load(object sender, System.EventArgs e)  {    if( IsPostBack )    {      m_bCreated = true;    }  }  public void DisplayBanner()  {    if( m_bCreated )    {     Response.Write( "<IMG SRC=BannerImages/Image" + Label3.Text + ".jpg>\n\r" );    }  }  private void Button1_Click(object sender, System.EventArgs e)  {    DateTime dt = DateTime.Now;     Label3.Text = "" + dt.Second + "" + dt.Millisecond;    String strFilename = "BannerImages\Image" + Label3.Text + ".jpg";    String strName = TextBox1.Text;    if( strName.Length == 0 )    {      strName = "No Name";    }    Bitmap newBitmap = new Bitmap( 400, 100, PixelFormat.Format24bppRgb );    Graphics g = Graphics.FromImage( newBitmap );    SolidBrush redBrush = new SolidBrush( Color.Red );    g.FillRectangle( redBrush, 0, 0, 400, 100 );    Font newFont = new Font( "Times New Roman", 25 );    SizeF TextSize = g.MeasureString( strName, newFont );    g.DrawString( strName, newFont, new SolidBrush( Color.Blue ),      ( 400 - TextSize.Width ) / 2, ( 100 - TextSize.Height ) / 2 );    newBitmap.Save( Request.MapPath( strFilename ), ImageFormat.Gif );  } 

The lion's share of the code for this application can be found in the Button1_Click() method. This method can also be seen in Listing 16.3. The first thing that happens in this method is that the date and time are retrieved into a DateTime object. The seconds and milliseconds that are contained in the DateTime object are used to create a unique portion of the filename. This filename is different for each user so that there is no mix-up. It would not be very good if three users created their banner images and then a fourth user came along and created her banner image, and the first three users saw the fourth user's banner image rather than their own. For this reason, each user gets a unique filename, which is used to create the image file on disk. The only possible way that the filename would not be unique is if two users tried to have their banners created at exactly the same point in time down to the millisecond.

If the preceding code were put on a production server, the chances are that you would fill your available disk space fairly quickly. The amount of time it will take depends on the amount of use, because there is no code to remove the files when finished. Instead of generating the image in the Button1's Click event, a separate aspx file should be linked to from the <image> tag. Then, the image could be generated and sent similarly to the first example. This would have the necessary information to generate the image passed to the image creation aspx file, and would generate the proper image. This way, the image is generated dynamically and never needs to be saved to the disk. Listings 16.4 and 16.5 show an example that does this.

Listing 16.4 The C# Code for the Banner Creation Application
 bool m_bCreated = false;  str m_sImageSrc;   private void Page_Load(object sender, System.EventArgs e)  {    if( IsPostBack )    {      m_bCreated = true;    }  }  public void DisplayBanner()  {    if( m_bCreated )    {      Response.Write( "<IMG SRC='"+m_sImageSrc+ "'>\n\r" );    }  }  private void Button1_Click(object sender, System.EventArgs e)  {    m_sImageSrc="GenerateImage.aspx?TEXT="+System.URLEncode(TextBox1.Text);  } 
Listing 16.5 Source for GenerateImage.aspx
 String strName = Request.QueryString("TEXT");  if( strName.Length == 0 )  {    strName = "No Name";  }  Bitmap newBitmap = new Bitmap( 400, 100, PixelFormat.Format24bppRgb );  Graphics g = Graphics.FromImage( newBitmap );  SolidBrush redBrush = new SolidBrush( Color.Red );  g.FillRectangle( redBrush, 0, 0, 400, 100 );  Font newFont = new Font( "Times New Roman", 25 );  SizeF TextSize = g.MeasureString( strName, newFont );  g.DrawString( strName, newFont, new SolidBrush( Color.Blue ),    ( 400 - TextSize.Width ) / 2, ( 100 - TextSize.Height ) / 2 );  Response.ContentType="Image/Gif";  newBitmap.Save( Response.OutputStream, ImageFormat.Gif ); 

The name is retrieved from TextBox1 and, if there is nothing in TextBox1 , the text string no name is arbitrarily assigned to it. This way, some text is always displayed in the banner, even if the user fails to type anything in.

A Bitmap object is created. The width of this bitmap is 400, the height is 100, and the pixel format is 24 bits per pixel in an RGB color space. The next line of code retrieves a Graphics object from the newly created bitmap. Then, a solid red brush is created and the banner is made red with the FillRectangle() method.

Now you need to draw the user's name into the banner bitmap. First, you need to create a new font. The easiest way to create a font is with the constructor that takes the name of a font and the size. As you can see, I have created a font that specifies Times New Roman with a point size of 25. Now, because I want to center the text string both vertically and horizontally, I need to find out how many pixels high and wide the text string is to be in this context, so I use the MeasureString() method. The MeasureString() method takes the text string and the font, and returns a SizeF object. The SizeF object enables me to get the width and height in pixels of the text string in this context.

Then, I call the DrawString() method. The first argument I give it is the user's name, the second is the font, the third is a solid brush, and the fourth and fifth are the X and Y coordinates to which I will draw. The X and Y coordinates refer to the upper-left corner of the rectangle in which the text string is to be drawn. To calculate the X coordinate I take the banner width, which is 400, subtract out the pixel size of the string, and then divide that by 2. To calculate the Y coordinate I take the height of the banner, which is 100, subtract out the pencil height of the text string, and then divide that by 2. This perfectly centers the text string in the banner bitmap. Finally, I save the banner image to disk using the filename that I created, which is based on the current time.

This application could easily be extended with many more options and features. You could enable users to create anything from banners to buttons to certificates using this approach.

   


Special Edition Using ASP. NET
Special Edition Using ASP.Net
ISBN: 0789725606
EAN: 2147483647
Year: 2002
Pages: 233

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net