here is a code sample that loads a jpeg

Upload: pankhoo

Post on 06-Apr-2018

221 views

Category:

Documents


0 download

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.