here is a code sample that loads a jpeg
TRANSCRIPT
-
8/3/2019 Here is a Code Sample That Loads a JPEG
1/19
Here is a code sample that loads a JPEG, changes any red pixels in the image to blue, and then
displays the bitmap in a picture box:
Bitmap bmp = (Bitmap)Bitmap.FromFile("image.jpg");
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
if (bmp.GetPixel(x, y) == Color.Red)
{
bmp.SetPixel(x, y, Color.Blue);
}
}
}
pictureBox1.Image = bmp;
Change Color Image to Balck and White
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Web;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;
usingSystem.Drawing; //Bitmap needed this
usingSystem.Drawing.Imaging;//ImageFormat needed this
usingSystem.IO;// .delete needed this
publicpartialclassColor2BW:System.Web.UI.Page
{
publicstaticBitmapGrayscale(Bitmap bitmap)
{
//Declare myBitmap as a new Bitmap with the same Width & Height
Bitmap myBitmap =newBitmap(bitmap.Width, bitmap.Height);
for(int i =0; i < bitmap.Width; i++)
{
for(int x =0; x < bitmap.Height; x++)
{
//Get the Pixel
ColorBitmapColor= bitmap.GetPixel(i, x);
-
8/3/2019 Here is a Code Sample That Loads a JPEG
2/19
//I want to come back here at some point and understand, then change,
the constants
//Declare grayScale as the Grayscale Pixel
int grayScale =(int)((BitmapColor.R *0.3)+(BitmapColor.G *0.59)
+(BitmapColor.B *0.11));
//Declare myColor as a Grayscale Color
Color myColor =Color.FromArgb(grayScale, grayScale, grayScale);
//Set the Grayscale Pixel
myBitmap.SetPixel(i, x, myColor);
}
}
return myBitmap;
}
protectedvoidAddPictureButton_Click(object sender,EventArgs e)
{
if(PictureUploadControl.HasFile)
{
PictureUploadControl.SaveAs(Server.MapPath("~/images/ORIGINAL")+
PictureUploadControl.FileName);
Bitmap oldBitmap =newBitmap(Server.MapPath("~/images/ORIGINAL")+
PictureUploadControl.FileName,false);
Bitmap newBitmap =Grayscale(newBitmap(oldBitmap));
string name ="grayscale";newBitmap.Save(Server.MapPath("~/images/")+ name +".jpg",
ImageFormat.Jpeg);
oldBitmap.Dispose();
//we will delete the old
File.Delete(Server.MapPath("~/images/ORIGINAL")+
PictureUploadControl.FileName);
GrayscaledPhoto.ImageUrl="images/"+ name +".jpg";
}
}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
3/19
Image Generation Service for ASP.NET
1.1Dino Esposito
Code download available at: CuttingEdge0404.exe(134 KB)
Browse the Code OnlineContents
What's IGS Anyway?
Comparing Image and DynamicImage
Comparing Pages and HTTP HandlersDesigning a ASP.NET 1.x Image Service
The CachedImageService.axd Handler
The DynamicImage Control In Action
Adding Support for Image TypesConclusion
Sometimes you need more than just static images on yourWeb siteyou may want to create images dynamically.
Thanks to GDI+, ASP.NET 1.x makes it easy to generate images programmatically. The ASP.NET infrastructure
can output images read from a source file, and can also retouch them in memory before outputting them.While this
gives programmers enough power to build effective one-off solutions, it requires them to reinvent the wheel every
time a new system is needed.
Aware of this limitation, the ASP.NET team designed more powerful image support into ASP.NET 2.0 and called it
the Image Generation Service (IGS).With IGS, working with images requires much less code than was required in
ASP.NET 1.x and lets you reference dynamically generated images in your pages more easily. You can read image
data stored in a local or remote file, in database fields, or in memory.Whatever the source of the image, a new
server control in IGS lets you link the image to the page.
In this column, I'll build a version of IGS targeted at ASP.NET 1.x and keep it as close as possible to the ASP.NET
2.0 implementation. This way you get tools to improve the manipulation of images in your current applications andcan get ready for the new ASP.NET 2.0 features. Note that ASP.NET 2.0 is still in development and some of these
APIs might change before release.
What's IGS Anyway?No matter what kind of abstraction layer you build, to display images over theWeb you still need an tag
pointing to a public URL. IGS is composed of two main elementsa server control and an HTTP handler. The
server control is an enhanced version of the Image control currently available in ASP.NET 1.x. It's a server-side
wrapper around the HTML element. The HTTP handler is a helper component that provides the data behind
the URL of the tag that is sent out to the browser. The HTTP handler represents a common piece of server
code used to generate and manipulate the bytes of the image to display.
Before I write my own version of the IGS for ASP.NET 1.x, let's briefly review the ASP.NET 2.0 DynamicImage
control. In ASP.NET 2.0, the server control is named DynamicImage and, at least at first glance, looks like a close
relative of the version 1.x control. But the DynamicImage control has more features. Run a page that
contains the following code:
The result of running the code is that the following markup is generated for displaying an image in a browser:
-
8/3/2019 Here is a Code Sample That Loads a JPEG
4/19
src="CachedImageService.axd?data={auto-generated guid}"
alt=""
style="border-width:0px;" />
Notice that the Src attribute is not set to the specified image file but points to an auto-generated URL.When
instantiated, the control loads the image from the specified resource and stores it in the ASP.NET cache. The keyused to store and retrieve the image is a GUID managed by ASP.NET.
The CachedImageService.axd URL corresponds to the public name of a built-in HTTP handler. The handler
retrieves the image from the ASP.NET cache and serializes its bytes to the browser using the proper content type.
The data parameter in the handler's query string indicates the key used to select the image from the ASP.NET cache.
The DynamicImage control also features a read-only ImageUrl property that returns the exact URL of the image
being generated.
In ASP.NET 2.0, the CachedImageService.axd service provides an additional capability. It can adjust the size and
format of the image based on the detected capabilities of the browser. If the browser cannot render that type of
image, the service will convert the image to a type supported on that browser, thanks to the ASP.NET 2.0 adaptive
rendering engine.
The DynamicImage class inherits from the DynamicImageBase class. Figure 1 lists the properties of the
DynamicImage control. As mentioned, ImageUrl is a read-only property and as such can't be used to set the URL of
an image to be displayed. This may be a source of confusion because ImageUrl is just the name of the main property
of the Image control in ASP.NET 1.x. (Note that dynamic images don't support width and height expressed as
percentages; they can only be expressed in pixels.)
Figure 1 ASP.NET 2.0 DynamicImage Control Properties
Property Description
AutoSize True by default. Indicates whether to modify the size of the image for
browsers with limited graphics capabilities.
Height Inherited from DynamicImageBase. Gets and sets the height of theimage in pixels.
Image Object of type System.Drawing.Image. Gets and sets the source of thedynamic image.
ImageBytes Gets and sets a reference to a byte array that contains the dynamicimage.
ImageFile Gets and sets the name of the file that contains the image.
ImageGeneratorUrl Gets and sets the URL of the HTTP handler image-generation service touse.
ImageType Inherited from DynamicImageBase. Gets and sets the preferred imagetype for the dynamic image.
ImageUrl Inherited from DynamicImageBase. Gets the URL used to generate thedynamic image. This property is read-only.
Parameters Gets a collection of parameters to pass to the image-generation service.
This property is important when an HTTP handler is used to generatethe image.
PercentScreenCover Gets and sets the percentage of the browser screen that the image willoccupy. This property only applies to mobile devices and has no effect
-
8/3/2019 Here is a Code Sample That Loads a JPEG
5/19
on desktop browsers.
ScaleBasedOnWidth Gets and sets a value indicating how to scale dynamic images to makethem fit into the specified width and height with respect to the image
aspect ratio. If true, the image is scaled based on its width, otherwise byits height.
Width Inherited from DynamicImageBase. Gets and sets the width of theimage in pixels.
The DynamicImage control can acquire the image bytes from a variety of sources and render them. Four of the
properties listed in Figure 1 are used to define usable image sources. They are: Image, ImageBytes, ImageFile, and
ImageGeneratorUrl. Image gets and sets the image as an instance of a GDI+ image class. The property is of type
System.Drawing.Image. This property is ideal for images dynamically created in memory using GDI+ capabilities.
ImageBytes represents the image as an array of bytes and is suitable for images stored in databases. ImageFile gets
and sets the URL to the image, whereas ImageGeneratorUrl returns the URL of a new image-specific HTTP handler
having the .asix extension.
Figure 2 The Control's Architecture
Whatever the format of the image, it is internally normalized to an instance of the System.Drawing.Image object,
assigned a random generated key, and cached in the ASP.NET Cache object. The diagram inFigure 2 shows an
approximation of the internal architecture of the control.
Comparing Image and DynamicImageOverall, in ASP.NET 2.0 you have two image server controlsImage and DynamicImage. Image is ideal for
referencing a static image as a server-side file or URL. If you can reference an image using a file path, then use the
Image control, which would produce the following familiar markup:
Referencing static images via a URL remains the fastest way to have an image downloaded to a client. No extracode is required and the browser and theWeb server would handle it automatically without involving the ASP.NET
runtime. IIS, for example, is optimized to serve static images such as JPG and GIF files on parallel threads without
involving any ISAPI code.
In DynamicImage, the image is cached in memory rather than being read from disk or downloaded from a remote
Web site on every access. However, consider that the vast majority of browsers are configured to cache images
locally, which is better for performance than server-side caching anyway. The real added value of ImageFile
becomes clear when you write applications designed to work with both desktop and mobile browsers. In this case
the IGS can automatically adapt the image to the device, at least in the most common scenarios.
Comparing Pages and HTTP HandlersMany developers still reference dynamic images using a URL that points to an .aspx page. Here's an example:
If it weren't for the .aspx extension, you might think this code came from an old ASP application. In ASP.NET,
however, this is a bad approach. The reason is simple: pages typically incur the most overhead of any HTTP handler
you can use to serve a request. In ASP.NET, each HTTP request is served by a special component known simply as
the HTTP handler. An HTTP handler is a class that implements the IHttpHandler interfacein particular, it
implements the ProcessRequest method.
The Page class is an HTTP handler with a really complex and sophisticated ProcessRequest method. The method
loops through the collection of child controls and instantiates them all. Next, it manages the viewstate and performs
-
8/3/2019 Here is a Code Sample That Loads a JPEG
6/19
postback events. None of this is really needed to manage images. Therefore, the most efficient way to handle
dynamic images in ASP.NET is to write a custom HTTP handler and optimize it to merely retrieve, serve, and
possibly cache images.
In ASP.NET 1.x, you have to write such a handler yourself, and sometimes you'll find you're doing it repeatedly, one
project after the next. In ASP.NET 2.0, on the other hand, you not only have the CachedImageService.axd handler
available to you for immediate use, but you can afford to know practically nothing about how it works under the
covers because the DynamicImage control shields you from all of the nitty-gritty details.
Designinga ASP.NET 1.x Image ServiceThis month's source code contains two projectsa DynamicImage custom server control and a sample application.
The control assembly also includes an ImageService HTTP handler. The control mimics the functionality of the
ASP.NET 2.0 DynamicImage class, while the handler presents some of the functionality of the
CachedImageService.axd handler. The code in Figure 3 shows the structure of the DynamicImage control.
Figure 3 DynamicImage Control
namespace MsdnMag
{
public class DynamicImage : System.Web.UI.WebControls.Image
{
private const string IgsBaseUrl = "cachedimageservice.axd?data={0}";
public DynamicImage()
{
m_imageBytes = null;
m_image = null;
this.PreRender += new EventHandler(DynamicImage_PreRender);
}
// PRIVATE members
private System.Drawing.Image m_image;
private byte[] m_imageBytes;
// PROPERTY: StorageKey
protected string StorageKey
{
get {return Convert.ToString(ViewState["StorageKey"]);}
set {ViewState["StorageKey"] = value;}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
7/19
// PROPERTY: ImageUrl (override)
public override string ImageUrl
{
get {return GetImageUrl();}
set {throw new NotSupportedException();}
}
// PROPERTY: ImageFile
public string ImageFile
{
get {return Convert.ToString(ViewState["ImageFile"]);}
set {ViewState["ImageFile"] = value;}
}
[Browsable(false)]
public byte[] ImageBytes
{
get {return m_imageBytes;}
set {m_imageBytes = value;}
}
[Browsable(false)]
public System.Drawing.Image Image
{
get {return m_image;}
set {m_image = value;}
}
// More code here...
}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
8/19
The DynamicImage control inherits Image and adds three new propertiesImageFile, Image, and ImageBytes.
Deriving from the Image control, it also inherits the ImageUrl property that the base class exposes to let developers
define the source of the resulting tag. Just like its ASP.NET 2.0 counterpart, the ASP.NET
1.x DynamicImage control overrides the ImageUrl property to make it read-only. This is done by simply throwing
an exception in the set accessor of the property. Not very elegant, but effective nonetheless:
public override string ImageUrl
{
get {return GetImageUrl();}
set {throw new NotSupportedException();}
}
In DynamicImage, ImageUrl plays a radically different role from the one it plays in Image. The actual URL of the
image as returned by ImageUrl is determined by looking at the contents of the properties listed inFigure 4. Of
course, only one of the source properties is used at a time. The control doesn't raise an error if more than one
property is set, but only one is taken into account (the current ASP.NET 2.0 implementation of this control only
allows one of these to be set and throws an exception otherwise). In my implementation, if set, ImageFile takes
precedence over the other two. Otherwise, the control first checks ImageBytes and then Image.Figure 4
Property Type Design-
time
Support
Description
Image System.Drawing.Image No References an image held in memory. Theimage is represented with a managed object.
The content of the image is loaded from adisk file, a stream, or created using GDI+
interfaces.
ImageBytes Byte[] No References the image as an array of bytes.Typically, you use this member when you
want to reference an image stored in adatabase field.
ImageFile String Yes References the image through its file name.This is equivalent to using a static file with
the tag.
ImageFile fully replaces ImageUrl as implemented in the Image control, though if you want to reference an image
through its physical or virtual file name, this is the property to use. ImageFile is also the only property you can set at
design time. The Browsable attribute, in fact, prevents Image and ImageBytes from displaying in the Properties box,
as shown here:
[Browsable(false)]
public byte[] ImageBytes {...}
[Browsable(false)]
public System.Drawing.Image Image {...}
When you set the ImageFile property declaratively or programmatically, the markup sent to the browser looks like
this:
-
8/3/2019 Here is a Code Sample That Loads a JPEG
9/19
The DynamicImage control outputs an tag even when you set the image through the ImageBytes or Image
property. HTML provides just one way to call an image: through the tag. That tag can only accept input
expressed as a publicly accessible URL. This means that the bytes of the image read from a database table, or the in-
memory image, must be referenced using a URL. This is where the image service HTTP handler comes in:
The constructor of the DynamicImage control registers a handler for the PreRender event. If the event fires, that
means at least one source property has been set. The control figures out the highest priority source for the image
content and determines the URL to use. The source code that demonstrates this feature is the GetImageUrl method
in Figure 5. GetImageUrl is invoked from within the get accessor of the ImageUrl property (see Figure 3).
Figure 5 GetImageURL Method
void DynamicImage_PreRender(object sender, EventArgs e)
{
if (ImageUrl.Length == 0)
return;
// Cache bytes or image
if (ImageBytes != null)
StoreImageBytes();
else
if (Image != null)
StoreImage();
return;
}
string GetImageUrl()
{
string url = "";
// Check ImageFile
if (ImageFile.Length >0)
{
url = ImageFile;
}
else // Check ImageBytes and Image
-
8/3/2019 Here is a Code Sample That Loads a JPEG
10/19
{
if (ImageBytes != null || Image != null)
{
if (StorageKey.Length == 0)
{
Guid g = Guid.NewGuid();
StorageKey = g.ToString();
}
return GetCachedImageUrl();
}
}
return url;
}
string GetCachedImageUrl()
{
return String.Format(IgsBaseUrl, StorageKey);
}
The PreRender event fires just before any ASP.NET 1.x control enters rendering mode. If the image is notreferenced through a plain URLthe content is set through either ImageBytes or Imagethe control ensures that
any image data is available to the built-in HTTP handler. Each image referenced as an object or an array of bytes is
given a unique key. This key is merely a GUID:
Guid g = Guid.NewGuid();
string storageKey = g.ToString();
The GUID is stored in the viewstate and preserved across page requests. This ensures that the same key always
identifies the image displayed by a given control:
protected string StorageKey
{
get {return Convert.ToString(ViewState["StorageKey"]);}
set {ViewState["StorageKey"] = value;}
}
The GUID is also used as the key to cache the image object or bytes in the ASP.NET cache.
Except when the ImageFile property is set, the output of the DynamicImage control is retrieved from the cache and
served to the browser by an HTTP handler. Figure 6 shows the code that stores the image content to the ASP.NET
cache.
-
8/3/2019 Here is a Code Sample That Loads a JPEG
11/19
Figure 6 Store Image in Cache
private void StoreImage()
{
StoreData(m_image);
}
private void StoreImageBytes()
{
StoreData(m_imageBytes);
}
private void StoreData(object data)
{
if (Page.Cache[StorageKey] == null)
{
Page.Cache.Add(StorageKey,
data,
null,
Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(60),
CacheItemPriority.High,
null);
}
}
The cache entry is created only if it doesn't exist. The Add method, in fact, fails if the specified entry is found to
already exist. The current storage key is used to uniquely identify the cache entry. The image is given a sliding
expiration policy along with a high priority. These settings match the settings of the DynamicImage control in
ASP.NET 2.0.
Sliding expiration indicates that the cached item will expire after a certain period of inactivity. If the cached item is
not read or written for the specified duration, it will be removed. If the item is accessed before its natural expiration
time, then the sliding period is automatically renewed.In this example, I've defined a one-minute intervalit is a
longer interval in ASP.NET 2.0, but configurable through the web.config file. You indicate a sliding expiration
through a TimeSpan objecta class that expresses a time interval. The FromSeconds static method creates an
interval in seconds.
Each item stored in the ASP.NET cache is given a priority that is used when the system runs low on memory. Items
with a lower priority are removed first to keep the system healthy.
The CachedImageService.axd Handler
-
8/3/2019 Here is a Code Sample That Loads a JPEG
12/19
As I mentioned, an HTTP handler is a piece of code used to service requests of a certain type. Typically, an HTTP
handler processes requests that have a certain extension or that match a certain URL. Figure 7shows the code of the
HTTP handler used to retrieve image data from the cache.
Figure 7 Retrieve Image from Cache
using System;
using System.Web;
using System.Drawing.Imaging;
namespace MsdnMag
{
public class CachedImageService : IHttpHandler
{
// Override the IsReusable property
public bool IsReusable
{
get { return true; }
}
// Override the ProcessRequest method
public void ProcessRequest(HttpContext context)
{
string storageKey = "";
// Retrieve the DATA query string parameter
if (context.Request["data"] == null)
{
WriteError();
return;
}
else
storageKey = context.Request["data"].ToString();
// Grab data from the cache
object o = HttpContext.Current.Cache[storageKey];
-
8/3/2019 Here is a Code Sample That Loads a JPEG
13/19
if (o == null)
{
WriteError();
return;
}
if ((o as byte[]) != null)
WriteImageBytes((byte[]) o);
else
if ((o as System.Drawing.Image) != null)
WriteImage((System.Drawing.Image) o);
}
private void WriteImageBytes(byte[] img)
{
HttpContext.Current.Response.ContentType = "image/jpeg";
HttpContext.Current.Response.OutputStream.Write(img, 0,
img.Length);
}
private void WriteImage(System.Drawing.Image img)
{
HttpContext.Current.Response.ContentType = "image/jpeg";
img.Save(HttpContext.Current.Response.OutputStream,
ImageFormat.Jpeg);
}
private void WriteError()
{
HttpContext.Current.Response.Write("No image specified");
}
}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
14/19
The IHttpHandler interface has only two methods of its own, one of which (IsReusable) just returns false in most
common implementations. The method value indicates whether another request can reuse the instance of the
handler.
The core of the handler is in the ProcessRequest method. This method contains the logic of the handler and governs
the processing of the request. The image service handler expects to find a data parameter in the query string. If the
parameter is missing, the method outputs an error message:
if (context.Request["data"] == null)
{
WriteError();
return;
}
void WriteError()
{
HttpContext.Current.Response.Write("No image specified");
}
The data parameter represents the key of the item in the ASP.NET cache that contains the image to display. The
handler grabs the image from the cache and outputs it to the browser. The image is rendered according to the storage
format. If the image is stored as an array of bytes, the array is flushed to the OutputStream property of the Response
object. Otherwise, if the image is a GDI+ object, the Save method of the Bitmap class targets the same stream.
The code in Figure 7 defaults to JPEG as the image format. This is arbitrary and using another image type is
certainly possible. Later, I'll return to this point to design a more general solution that includes the image type as a
variable argument.
The HTTP handler is a class and gets compiled in the same assembly as the DynamicImage control. How would you
invoke it? ASP.NET 2.0 uses the CachedImageService.axd URL to link to it. Can the same be done in ASP.NET
1.x? Yes, of course. The mapping between an HTTP handler and a URL name (or extension) can be set declaratively
in the application's web.config file. If that is going to be a system setting, then you can move the following script to
the machine.config file. (This happens to be exactly what ASP.NET 2.0 does.)
The section instructs the ASP.NET runtime to use the MsdnMag.CachedImageService handler class
to service any incoming GET request targeted to the cachedimageservice.axd URL. The .axd URL doesn't
-
8/3/2019 Here is a Code Sample That Loads a JPEG
15/19
correspond to a real server file or resource. It is just a fake name used to bind a given functionality (coded into the
HTTP handler class) to a URL.
The DynamicImage Control In ActionNow that the ASP.NET 1.x image generation service is up and running, let's see how to use it in a sample
application. Create your own ASP.NET project, tweak the web.config file as described previously, and reference the
DynamicImage control in your toolbox. The sample page has three instances of the DynamicImage control, each set
with a different source propertyImageFile, Image, and ImageBytes:
Both the Image and ImageBytes properties are bindable and can be set declaratively with the return value of anyfunction that generates the proper data type. Figure 8 shows the source code of the two helper functions that provide
the contents of the images to display. GetRandomNumber creates and returns an in-memory image that represents a
randomly generated number. GetEmployeePhoto retrieves the picture of an employee from the Northwind database
and attaches those bytes to the ImageBytes property of a DynamicImage control. Figure 9 shows the page in action.
The grid at the bottom of the page shows the current content of the Cache object. The output is generated by a
custom user control that iterates through the cache and populates a grid (see the source code in this month's
download).
Figure 8 GetRandomNumberand GetEmployeePhoto
public System.Drawing.Image GetRandomNumber()
{
// Store the number
Random gen = new Random();
int number = gen.Next();
// Generate the image
Bitmap bmp = new Bitmap(200, 100);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.LightCyan);
using (Font f = new Font("Impact", 20))
{
g.DrawString(number.ToString(), f, Brushes.Blue, 10, 10);
}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
16/19
return bmp;
}
public byte[] GetEmployeePhoto (int empID)
{
using (SqlConnection conn = new SqlConnection(
"SERVER=localhost;DATABASE=northwind;Integrated Security=SSPI"))
{
using (SqlCommand cmd = new SqlCommand(
"SELECT photo FROM employees WHERE employeeid=@id", conn))
{
cmd.Parameters.Add("@id", empID);
conn.Open();
byte[] img = (byte[]) cmd.ExecuteScalar();
conn.Close();
MemoryStream ms = new MemoryStream (img, 78, img.Length - 78);
return ms.ToArray();
}
}
}
-
8/3/2019 Here is a Code Sample That Loads a JPEG
17/19
Figure 9 The Page in Action
The image in the top-left corner comes from a server-side image file. The URL of the corresponding tag
served to the browser matches the URL assigned to the ImageFile property of the server control. The other two
images are generated dynamically. Their URLs look like this:
cachedimageservice.axd?data=2a1612b8-0d4a-4757-ab91-7a29f25c1aea
If you make a separate request for this URL you'll get the image, as long as the cached item has not been removed.
The cache lifetime depends on the sliding expiration set in the DynamicImage control (seeFigure 6). As mentioned,
this parameter is configurable in ASP.NET 2.0 and set to five minutes by default. If the image is removed from the
cache, a direct call would return an error. A call made through the control, on the other hand, would trap the error,
generate a new GUID, then reload and cache the image.
Adding Support for Image TypesIn the example developed thus far, the image type was assumed to be a JPEG. There's no reason you can't change it
to any other type that the Microsoft .NET Framework supports (GIF, PNG, BMP, and the like). The image type
can sometimes be inferred from the image bytes and the in-memory representation of the image. More precisely, if
you hold the image bytes you can apply some patterns to the array and recognize the formatall image formats
begin with a well-known signature and header; however, if the image is created as a GDI+ object, then no
information about the image type is stored. A GDI+ image is rendered as a format-independent objectthe Bitmap
class. In spite of the name, though, the .NET Framework Bitmap class simply represents an image as a matrix of
RGB pixels (plus the alpha channel, for a total of 32 bits per pixel) with no relationship to a common image fileformat. Only when the Bitmap object is serialized does the image format become an essential parameter:
img.Save(stream, imageType)
The internal serializer looks at the desired type and converts the generic RGB format to a layout typical of JPG or
GIF files.
In ASP.NET 2.0, the image type is expressed as an attribute to the DynamicImage control and stored with the
cached image object. This parameter is then retrieved and used when it is time to output the image stream. To add
-
8/3/2019 Here is a Code Sample That Loads a JPEG
18/19
this capability to the ASP.NET 1.x image generation service, you start by adding a new public property, called
ImageType, to the DynamicImage control:
public ImageType ImageType
{
get {return (ImageType) ViewState["ImageType"];}
set {return ViewState["ImageType"] = value;}
}
The type of the property is an enumeration named ImageType. The ImageType enumeration indicates the preferred
image type for dynamically generated images. It is worth noting that in ASP.NET 2.0, if the requesting browser does
not support the image type you specify, the DynamicImage control automatically provides a different type of image
based on the display capabilities of the particular browser in question:
public enum ImageType
{
Jpeg,
Gif,
Bmp,
Png
}
The ImageType property indicates the desired type of the output image. You can also build into the DynamicImage
control the ability to convert the image from the original format to the desired one. If the ImageType property is not
specified, you can make it default to a fixed type (JPEG) or infer it from the file name extension if the ImageFile
property is set.
In any case, once the desired image type has been determined, you pack the image to cache into a new data
structure, like so:class ImageInfo
{
object imageObject;
ImageType imageType;
}
The imageObject field contains the bytes of the image if the ImageBytes property has been set, or it contains the
GDI+ object if the Image property is used instead. The imageType property sets the desired output type.
It is important to note that setting the ImageType property doesn't automatically ensure that the image sent to the
browser is of the right type. This is easy to code for GDI+ objects, but not if the image is read out of a database field
or a file:
void WriteImage(System.Drawing.Image img)
{
string mimeType = ImageTypeToMimeType();
HttpContext.Current.Response.ContentType = mimeType;
img.Save(HttpContext.Current.Response.OutputStream,
-
8/3/2019 Here is a Code Sample That Loads a JPEG
19/19
m_imageType);
}
If the image is stored as a format-independent object, then you simply need to express its type as a MIME type (for
example, image/jpeg). The conversion from the RGB format to the desired one is necessary and cannot be avoided.
Things are a bit different if the image is an array of bytes or a file. If it's a file, the image type is well-defined and
implicit in the bytes but may not match the value of the ImageType property. The simplest way to code a control
that always outputs the image as specified by ImageType, irrespective of the original format, is to convert the source
format to a GDI+ object. This code shows how to load an image from a file:
FileStream fs = new FileStream(url, ...);
Bitmap img = Image.FromStream(fs);
Similarly, you can load a GDI+ image from an array of bytes.
MemoryStream ms = new MemoryStream(m_imageBytes);
Bitmap img = Image.FromStream(ms);
At this point, regardless of the original format, you cache the image as a generic Bitmap object and can output it in
the desired format with no problemthe approach taken in ASP.NET 2.0.
ConclusionThe DynamicImage control in ASP.NET 2.0, and in the implementation provided here for ASP.NET 1.x, achieves
two main goals. First, it gives you an easy way to display images that are dynamically generated and not simply read
from a static file. As I demonstrated, you can also bind the properties of the new control to data-bound expressions
for maximum flexibility. Just remember to place a call to Page.DataBind somewhere in the code to trigger the
evaluation of any data-bound expressions throughout the page.
Second, the DynamicImage control provides a smart way to cache generated images.When static files are used, they
are downloaded the first time (unless cache-specific settings prevent that) and loaded from the local browser cache
when needed. One of the issues with dynamic images accessed through .aspx pages or .ashx handlers in ASP.NET
1.x, is that the image is regenerated each time it is accessed. The DynamicImage control reduces this overhead
significantly by storing the generated image in the ASP.NET cache and retrieving it from there. A configurableparameter lets you decide how long the images can be stored. Each image is given a unique GUID and when the
image is no longer available from the cache, it is regenerated.
Send your questions and comments for Dino to [email protected].
Dino Esposito is an instructor and consultant based in Rome, Italy. Author ofProgramming
ASP.NET(Microsoft Press, 2003), he spends most of his time teaching classes on ADO.NET and ASP.NETand speaking at conferences. Get in touch with Dino at [email protected] or join the blog
athttp://weblogs.asp.net/despos.