Click here to Skip to main content
Click here to Skip to main content

SQL Database Image Storage & Easy Thumbnails

By , 17 May 2007
Rate this:
Please Sign up or sign in to vote.

Introduction

A while ago I needed to store some images within a database as part of a project. For a second task I also wanted to create thumbnails of the stored image data at varying sizes for an ASP.NET application that was part of my overall project.

This article will demonstrate how to store and retrieve image data from an SQL database, and shall also demonstrate how to create thumbnail images of this SQL database stored image data.

The Database

Why should we use a database and not just have the images within a virtual folder under the main ASP.NET folder? Well there are several reasons why it might be good to store images in a database, such as

  • If the images binary data is stored in a database table, we have all the data required to make the image any size we want, and it will always look like the orginal image
  • If the images binary data is stored in a database table, when we back the database up, we have also backed up all the users images

I am not saying this is the only way to go, its simply one way. As I say its something I had to do for a project, so I thought I would share what I found with you lot.

So what does the database look like.

It simply contains one table called tbl_image which can be setup using the following script (contained within the object creation script at the top of this article)

CREATE TABLE [dbo].[tbl_image] (
    [img_pk] [int] IDENTITY (1, 1) NOT NULL ,
    [img_data] [image] NOT NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

As can be seen, its a very simply table. We simply store the images primary key (img_pk) as an int type column, and the image data (img_data) as an image type column. This is all fairly easy isn't it?

So how do we get data in / out of this table. I have actually written three stored procedures (contained within the object creation script at the top of this article), but most of this could actually be done with standard SQL command strings. That I'll leave up to you.

Let's have a look at the three stored procedures shall we, they are quite easy, in fact I think the comments at the top pretty much explain them in enough detail. So I won't bore you with any more explanatory words, as it's clear, isn't it?

sp_AddImage

/*
======================================================================
NAME : sp_AddImage

DESCRIPTION :

Creates a new image within the tbl_Image table, and returns the ID for
the newly inserted image.

Inserts a new image into the tbl_Image table, using the parameteres 
provided. The IMAGE item is expected to be a binary[] array of data
that respresents the image in its entirety.

If the insertion is successful the newly inserted image primary key is
returned, in the output parameter @img_pk


INPUT PARAMETERS :

NAME:                DATATYPE:
@img_data            IMAGE

OUTPUT PARAMETERS :

NAME:                DATATYPE:
@img_pk            INT

RETURNS : 
Nothing

======================================================================
*/
CREATE       PROCEDURE [sp_AddImage] 
        (    
                @img_pk        INT         OUTPUT    ,
                @img_data        IMAGE                
        )
AS 
    INSERT INTO tbl_Image ( img_data)
    VALUES ( @img_data )

    IF @@ROWCOUNT=1
    SET @img_pk=@@IDENTITY
GO

sp_GetImageByID

/*
======================================================================
NAME : sp_GetImageByID

DESCRIPTION :

Returns a binary[] array which represents the image, whos primary key is equal
to the @img_pk input parameter

INPUT PARAMETERS :

NAME:                DATATYPE:
@img_pk            INT    
RETURNS : 
A binary[] array which represents the image, whos primary key is equal
to the @img_pk input parameter
======================================================================
*/
CREATE       PROCEDURE [sp_GetImageByID] 
        (    
                @img_pk        INT     
        )
AS 

    SELECT img_data FROM tbl_Image 
    WHERE img_pk=@img_pk
GO

sp_GetImages

/*
======================================================================
NAME : sp_GetImages

DESCRIPTION :
Returns a  DataSet containing all the stored  images

RETURNS : 
A DataSet containing all the stored  images
======================================================================
*/
CREATE       PROCEDURE [sp_GetImages] 

AS 
    SELECT * FROM tbl_Image
GO

The Web Application

Design

To properly understand how this all works let's consider the following class diagram which should help.

Screenshot - ClassDiagram.png

Let's have a quick look at the design of the web application, before diving into how it all works, shall we?

Default is a standard ASP.NET wb form, and it looks like the following image in design time. This is the only page within the application.

It can be seen that this page simpy provides an upload field, and a button to submit the uploaded file.

Below that it has a literal element in which I use to show error messages (NOTE: This is not how to normally do error handling in ASP.NET, normally one would have a custom error page, but that is outside the scope of this article. This is simply to show the Exception message as quickly as possible).

Then there is a Placeholder element, which is used to add a thumbnail of the uploaded image (if sucessful).

Then there is a button to SELECT all (using stored procedure sp_GetImages) previously stored database images. These stored images are then bound to a DataList control. This is explained in more detail below.

That's the design of the page, but how does it all work?

So How Does It All Work

Well let's start at the beginning shall we? The following steps are carried out.

To upload and store an image

  1. The user selects a file from their local file system, using the upload field shown
  2. They then click the "Upload" button, which then checked the posted content, to see if is is actually an image. If it is valid image go to step 3, otherwise show an error message
  3. Create an image from the upload stream, and then convert this image to a byte[] array, and save this to the database using the dbAccess class' SaveImageToDb() method, which in turn calls the sp_AddImage stored procedure above
  4. If the save was successful, create a thumbnail of the image using the primary key of the current image.

To create a thumnail for an image

It is a little known fact that an image may be created as the result of writing another ASP.NET form (with no controls of its own) to the HTTP response stream. This is how we manage to do the thumbnails. Let's have a look shall we?

  1. If a primary key for an image is known, we can create thumbnail as shown in the following code snippet:
    ThumbFromID.THUMBNAIL_SIZE = this.THUMBNAIL_SIZE;
    ThumbFromID.USE_SIZE_FOR_HEIGHT = false;
    imgImage = new System.Web.UI.WebControls.Image();
    // set the source to the page that generates the thumbnail image
    imgImage.ImageUrl = ThumbFromID.PAGE_NAME + "?" +
       ThumbFromID.IMAGE_ID + "=" + img_pk;

What's actually going on here, is that we are setting two static field values within the ThumbFromID class, which will dictate what size the thumbnail will be. Next we assign the current images ImageUrl property the value of the string ThumbFromID.PAGE_NAME?ThumbFromID.IMAGE_ID=5; for example. What this is doing is requesting the page ThumbFromID to load. Remember that the page ThumbFromID does not have any controls of its own, its sole job is to provide the correct image from the database at the requested size, on the standard HTTP response stream. This will probably make a bit more sense if we have a look at the Page_Load event of the ThumbFromID class.

    private void Page_Load(object sender, System.EventArgs e)
    {
        byte[] imageData = null;
        MemoryStream ms = null;
        System.Drawing.Image fullsizeImage = null;
        String imageID = null;

        if (!Page.IsPostBack)
        {
            try
            {
                // get the ID of the image to retrieve from the database
                imageID = Request.QueryString[IMAGE_ID];
                imageData = dbAccess.GetImageByID(int.Parse(imageID));

                // create an image from the byte array
                ms = new MemoryStream(imageData);
                fullsizeImage = System.Drawing.Image.FromStream(ms);

                Response.ContentType = "image/Jpeg";
                ImageResize ir = new ImageResize();

                // Load your image and perform any resizing here
                ir.File = fullsizeImage;
                if (USE_SIZE_FOR_HEIGHT)
                    ir.Height = THUMBNAIL_SIZE;
                else
                    ir.Width = THUMBNAIL_SIZE;
                //get the thumbnail
                ir.GetThumbnail().Save(Response.OutputStream,
                    System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
            finally
            {
                ms.Close();
            }
        }
    }

Can you see what is happening here? A couple of fields are created to hold the finished image and a MemoryStream is created for temporary storage. Then the value of the images primary key is read from the request string (this would be 5 if we stick to the example above). So next the image data is fetched from the dbAccess class by using the GetImageByID(..) method (which in turn calls the stored procedure sp_GetImageByID). This binary image data from the database is then placed into the MemoryStream object. Then a new ImageRezize object is created, and is used to create a thumbnail at the requested size. The ImageRezize class is not my own, it is by a chap called Alex Hildyard, and is available at here

The ImageRezize object, simply resizes the image to the correct size, and writes the image to a stream. In this case, as we are dealing with ASP.NET, and are trying to create a image control ImageUrl property, this is set to Response.OutputStream

How about doing this with a databound control

You may want to use thumbnail images within a databound control, such as a DataList or GridView, etc. To demonstrate this let's consider the following method of the Default page, which contains a DataList control. As shown previously in the Design section of this article.

Well, let's look at that shall we, The Default page provides a single button called btnSeeAll, whos job it is to SELECT all the SQL stored images by using the dbAccess classes GetImages(..) method (which in turn calls the stored procedure sp_GetImages)

protected void dlImages_ItemDataBound(object sender, DataListItemEventArgs e)
{
    System.Web.UI.WebControls.Image img = null;

    // make sure this is an item in the data list (not header etc.)
    if ((e.Item.ItemType == ListItemType.Item) ||
        (e.Item.ItemType == ListItemType.AlternatingItem))
    {
        // get a reference to the image used for the bar in the row
        img = (System.Web.UI.WebControls.Image)
            (e.Item.FindControl("imgThumbnail"));
        //get the img_pk from DataRow being bound
        int img_pk = Convert.ToInt16(
            ((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString());
        ThumbFromID.THUMBNAIL_SIZE = this.THUMBNAIL_SIZE;
        ThumbFromID.USE_SIZE_FOR_HEIGHT = false;
        // set the source to the page that generates the thumbnail image
        img.ImageUrl = ThumbFromID.PAGE_NAME + "?" +
            ThumbFromID.IMAGE_ID + "=" + img_pk;            
    }
}

It can be seen that this to follows the same principles as just outlined. The only difference being that the dlImages_ItemDataBound event is raised during databinding, for each item within the databound control (A DataList in this case). As such the extraction of the primary key must be gained by examining the DataSet that is being bound to the databound control. However, once we have the current DataRowView Primary key value, which is obtained thusly:

Convert.ToInt16(((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString())
We simpy create the thumnail the same way. This is repeated for each DataRowView within the DataLists data source.

Full Code Listing

For those of you that want full code listings.

dbAccess

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.IO;

#region dbAccess CLASS
/// <summary>
/// Provides a wrapper around the underyling SQL database. This class
/// provides all methods that are required to INSERT / SELECT 
/// images within the underyling SQL database. 
/// </summary>
public sealed class dbAccess
{
    /// <summary>
    /// Returns a Byte[] array which represents the database stored image
    /// whos primary key is the same as the img_pk input parameter
    /// </summary>
    /// <param name="img_pk">The primary key of the image to retrieve</param>
    /// <returns>A Byte[] array which represents the database stored image
    /// whos primary key is the same as the img_pk input parameter</returns>
    public static byte[] GetImageByID(int img_pk)
    {
        //use the web.config to store the connection string, using statement 
        //ensure connection always closes                
        using (SqlConnection connection = new SqlConnection(
            ConfigurationManager.ConnectionStrings[
            "EasyThumbs_DB"].ConnectionString))
        {
            try
            {
                SqlCommand command = new SqlCommand("sp_GetImageByID", 
                    connection);
                command.CommandType = CommandType.StoredProcedure;
                //build params
                SqlParameter param0 = new SqlParameter(
                    "@img_pk", SqlDbType.Int);
                param0.Value = img_pk;
                command.Parameters.Add(param0);
                //open connection, and execute stored procedure
                connection.Open();
                byte[] imgdata = (byte[])(command.ExecuteScalar());
                connection.Close();
                return imgdata;
            }
            catch (SqlException ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }
    }

    /// <summary>
    /// Inserts a new image using the details provided, and will then update 
    /// the input parameter img_pk with the correct primary key value from 
    /// the database, and shall also return the number of rows affected by 
    /// the call to this method.
    /// </summary>
    /// <param name="img_pk">The image primary key, the will get assigned 
    /// value by this method call as the parameter is passed by 
    /// Reference</param>
    /// <param name="imgbin">A byte[] array representing the image to be 
    /// stored</param>
    /// <returns>The number of rows affected by the call to this 
    /// method</returns>
    public static int SaveImageToDB(ref int img_pk, byte[] imgbin)
    {
        try
        {
            //use the web.config to store the connection string, using 
            //statement ensure connection always closes                
            using (SqlConnection connection = new SqlConnection(
                ConfigurationManager.ConnectionStrings[
                "EasyThumbs_DB"].ConnectionString))
            {
                SqlCommand command = new SqlCommand("sp_AddImage", 
                    connection);
                command.CommandType = CommandType.StoredProcedure;
                //build params
                int IMG_PK = 0;
                SqlParameter param0 = new SqlParameter("@img_pk", 
                    SqlDbType.Int);
                param0.Value = IMG_PK;
                command.Parameters.Add(param0);
                param0.Direction = ParameterDirection.Output;
                SqlParameter param1 = new SqlParameter("@img_data", 
                    SqlDbType.Image);
                param1.Value = imgbin;
                command.Parameters.Add(param1);
                //open connection, and execute stored procedure
                connection.Open();
                int numRowsAffected = command.ExecuteNonQuery();
                connection.Close();
                //set the ref parameter and return value
                img_pk = int.Parse(param0.Value.ToString());
                //return the rows affected
                return numRowsAffected;
            }
        }
        catch (SqlException ex)
        {
            throw new Exception(ex.Message, ex);
        }
    }

    /// <summary>
    /// Returns a DataSet which contains all database stored images
    /// </summary>
    /// <returns>A DataSet which contains all database stored images
    /// images</returns>
    public static DataSet GetImages()
    {
        //use the web.config to store the connection string, 
        //using statement ensure connection always closes                
        using (SqlConnection connection = new SqlConnection(
            ConfigurationManager.ConnectionStrings[
            "EasyThumbs_DB"].ConnectionString))
        {
            try
            {
                SqlCommand command = new SqlCommand("sp_GetImages", 
                    connection);
                command.CommandType = CommandType.StoredProcedure;
                //execute stored procedure and return DataSet
                SqlDataAdapter da = new SqlDataAdapter();
                da.SelectCommand = command;
                DataSet ds = new DataSet();
                da.Fill(ds, "IMAGES");
                return ds;
            }
            catch (SqlException ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }
    }
}
#endregion

ImageResize

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.IO;

#region ImageResize CLASS
/// <summary>
/// ImageResize is a class that is based on an article that was obtained from
/// the URL http://www.devx.com/dotnet/Article/22079/0/page/3. I had to make
/// some minor changes to a couple of the properties, but otherwise it is very
/// much like the original article.
/// </summary>
public class ImageResize
{
    #region Instance Fields
    //instance fields
    private double m_width, m_height;
    private bool m_use_aspect = true;
    private bool m_use_percentage = false;
    private System.Drawing.Image m_src_image, m_dst_image;
    private System.Drawing.Image m_image;
    private ImageResize m_cache;
    private Graphics m_graphics;
    #endregion
    #region Public properties
    /// <summary>
    /// gets of sets the File
    /// </summary>
    public System.Drawing.Image File
    {
        get { return m_image; }
        set { m_image = value; }
    }
    /// <summary>
    /// gets of sets the Image
    /// </summary>
    public System.Drawing.Image Image
    {
        get { return m_src_image; }
        set { m_src_image = value; }
    }
    /// <summary>
    /// gets of sets the PreserveAspectRatio
    /// </summary>
    public bool PreserveAspectRatio
    {
        get { return m_use_aspect; }
        set { m_use_aspect = value; }
    }
    /// <summary>
    /// gets of sets the UsePercentages
    /// </summary>
    public bool UsePercentages
    {
        get { return m_use_percentage; }
        set { m_use_percentage = value; }
    }
    /// <summary>
    /// gets of sets the Width
    /// </summary>
    public double Width
    {
        get { return m_width; }
        set { m_width = value; }
    }
    /// <summary>
    /// gets of sets the Height
    /// </summary>
    public double Height
    {
        get { return m_height; }
        set { m_height = value; }
    }
    #endregion
    #region Public Methods
    /// <summary>
    /// Returns a Image which represents a rezised Image
    /// </summary>
    /// <returns>A Image which represents a rezised Image, using the 
    /// proprerty settings provided</returns>
    public virtual System.Drawing.Image GetThumbnail()
    {
        // Flag whether a new image is required
        bool recalculate = false;
        double new_width = Width;
        double new_height = Height;
        // Load via stream rather than Image.FromFile to release the file
        // handle immediately
        if (m_src_image != null)
            m_src_image.Dispose();
        m_src_image = m_image;
        recalculate = true;
        // If you opted to specify width and height as percentages of the 
        // original image's width and height, compute these now
        if (UsePercentages)
        {
            if (Width != 0)
            {
                new_width = (double)m_src_image.Width * Width / 100;

                if (PreserveAspectRatio)
                {
                    new_height = new_width * m_src_image.Height / 
                        (double)m_src_image.Width;
                }
            }
            if (Height != 0)
            {
                new_height = (double)m_src_image.Height * Height / 100;

                if (PreserveAspectRatio)
                {
                    new_width = new_height * m_src_image.Width / 
                        (double)m_src_image.Height;
                }
            }
        }
        else
        {
            // If you specified an aspect ratio and absolute width or height,
            // then calculate this now; if you accidentally specified both a 
            // width and height, ignore the PreserveAspectRatio flag

            if (PreserveAspectRatio)
            {
                if (Width != 0 && Height == 0)
                {
                    new_height = (Width / (
                        double)m_src_image.Width) * m_src_image.Height;
                }
                else if (Height != 0 && Width == 0)
                {
                    new_width = (Height / (
                        double)m_src_image.Height) * m_src_image.Width;
                }
            }
        }
        recalculate = true;
        if (recalculate)
        {
            // Calculate the new image
            if (m_dst_image != null)
            {
                m_dst_image.Dispose();
                m_graphics.Dispose();
            }
            Bitmap bitmap = new Bitmap((int)new_width, (int)new_height, 
                m_src_image.PixelFormat);
            m_graphics = Graphics.FromImage(bitmap);
            m_graphics.SmoothingMode = 
                System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            m_graphics.InterpolationMode = 
                System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            m_graphics.DrawImage(
                m_src_image, 0, 0, bitmap.Width, bitmap.Height);
            m_dst_image = bitmap;
            // Cache the image and its associated settings
            m_cache = this.MemberwiseClone() as ImageResize;
        }
        return m_dst_image;
    }
    #endregion
    #region Deconstructor
    /// <summary>
    /// Frees all held resources, such as Graphics and Image handles
    /// </summary>
    ~ImageResize()
    {
        // Free resources
        if (m_dst_image != null)
        {
            m_dst_image.Dispose();
            m_graphics.Dispose();
        }

        if (m_src_image != null)
            m_src_image.Dispose();
    }
    #endregion
}
#endregion

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" 
    Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="lblInstructions" runat="server" Font-Bold="True" 
            Font-Names="Arial" Text="Please select an image file"></asp:Label>
        <br/>
        <asp:FileUpload ID="UploadFile" runat="server" Width="631px" />
        <asp:Button ID="btnSubmit" runat="server" Height="20px" 
            OnClick="btnSubmit_Click" Text="Upload" Width="78px" />
        <br/>
        <br />
        <asp:Label ID="lblException" runat="server" Font-Bold="True" 
            Font-Names="Arial" Text="ERRORS : If any exist" 
            ForeColor="Red"></asp:Label>
        <br />        
        <asp:Literal ID="litException" runat="server"></asp:Literal>
        <br/>
        <br />
        <asp:PlaceHolder id="plImage" Runat="server"></asp:PlaceHolder>
        <br />
        <br />
        <asp:Label ID="lblSeeAll" runat="server" Font-Bold="True" 
            Font-Names="Arial" 
            Text="View all saved images from SQL database"></asp:Label>
        <br />
        <br />
        <asp:Button ID="btnSeeAll" runat="server" Height="20px"  
            Text="See All Images" Width="115px" OnClick="btnSeeAll_Click" />
        <br />
        <br />
        <asp:datalist id="dlImages" Runat="server" Width="90%" 
            ItemStyle-HorizontalAlign="Left" RepeatLayout="Table"
            RepeatDirection="Horizontal" RepeatColumns="4" 
            OnItemDataBound="dlImages_ItemDataBound">
        <ItemTemplate>
            <asp:Image id="imgThumbnail" runat="server" borderSize="5" />
        </ItemTemplate>
        </asp:datalist>            
        <br/>        
    </div>
    </form>
</body>
</html>

Default.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;

public partial class _Default : System.Web.UI.Page
{
    #region instance fields
    //instance fields
    protected System.Web.UI.WebControls.Image imgImage;
    private int THUMBNAIL_SIZE = 60;
    #endregion

    protected void Page_Load(object sender, EventArgs e)
    {
    }

    /// <summary>
    /// Creates an image, by querying the SQL database with the given img_pk
    /// parameter. The query will return a byte[] array, which represents the 
    /// image. This byte[] array is then converted into an image and added to 
    /// the placeholder control "plImage" which is on this page
    /// </summary>
    /// <param name="img_pk">The primary key to fetch the image data for</param>
    private void createImageFromDBBytes(int img_pk)
    {

        ThumbFromID.THUMBNAIL_SIZE = this.THUMBNAIL_SIZE;
        ThumbFromID.USE_SIZE_FOR_HEIGHT = false;
        imgImage = new System.Web.UI.WebControls.Image();
        // set the source to the page that generates the thumbnail image
        imgImage.ImageUrl = ThumbFromID.PAGE_NAME + "?" +
            ThumbFromID.IMAGE_ID + "=" + img_pk;
        litException.Visible = false;
        plImage.Controls.Clear();
        plImage.Controls.Add(imgImage);
    }

    /// <summary>
    /// returns a byte[] array which represents the input Image
    /// </summary>
    /// <param name="bmp">The source image to return as byte[] array</param>
    /// <returns>byte[] array which represents the input Image</returns>
    private byte[] BmpToBytes(System.Drawing.Image bmp)
    {
        MemoryStream ms = null;
        byte[] bmpBytes = null;
        try
        {
            ms = new MemoryStream();
            // Save to memory using the Jpeg format
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

            // read to end
            bmpBytes = ms.GetBuffer();
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
            bmp.Dispose();
            if (ms != null)
            {
                ms.Close();
            }
        }
        return bmpBytes;
    }

    /// <summary>
    /// Will attempt ot save the posted file contents to SQL server
    /// table. Will firstly check that the posted file is an image
    /// </summary>
    /// <param name="sender">the btnSubmit</param>
    /// <param name="e">the btnSubmit EventArgs</param>
    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        try
        {
            string imgContentType = UploadFile.PostedFile.ContentType;

            //check if an image
            if (imgContentType.ToLower().StartsWith("image"))
            {
                //get the image from upload stream
                System.Drawing.Bitmap b = (
                    System.Drawing.Bitmap)System.Drawing.Image.FromStream(
                    UploadFile.PostedFile.InputStream);
                //get pk, to allow image to be created on this page from the
                //SQL server stores byte[] array
                int img_pk = 0;
                //store the image in database, and also ccheck to see if it 
                //was successful, and if so create 
                //a thumnail here of the stored image
                int RowsAffected = dbAccess.SaveImageToDB(ref img_pk,
                    BmpToBytes(b));
                if (RowsAffected > 0)
                {
                    createImageFromDBBytes(img_pk);
                }
                else
                {
                    litException.Text = ("<br><p>ERROR saving image </p>");
                }
            }
            else
            {
                litException.Text = ("<br><p>The file is not an image</p>");
            }
        }
        catch (Exception ex)
        {
            litException.Text = ("<br><p>" + ex.Message + "</p>");
        }
    }
    /// <summary>
    /// Will attempt fetch all SQL server stored images, and will bind the 
    /// resultant DataSet to the "dlImages" datalist on this page. When the 
    /// databinding occurs the dlImages_ItemDataBound(..) event is fired. At
    /// that stage the image control is found, and a new thumbnail is 
    /// constructed for each DataSet row value
    /// </summary>
    /// <param name="sender">the btnSeeAll</param>
    /// <param name="e">the btnSeeAll EventArgs</param>
    protected void btnSeeAll_Click(object sender, EventArgs e)
    {
        try
        {
            // set the source of the data for the repeater control and bind it
            DataSet dsImgs = dbAccess.GetImages();
            dlImages.DataSource = dsImgs;
            dlImages.DataBind();
        }
        catch (Exception ex)
        {
            litException.Text = ("<br><p>" + ex.Message + "</p>");
        }
    }
    /// <summary>
    /// Occurs when the server side DataList starts databinding. This event
    /// is used to intercept the databinding to create a new Image that
    /// uses the binary array value of the data within the DataList datasource
    /// </summary>
    /// <param name="sender">the datalist</param>
    /// <param name="e">the datalist DataListItemEventArgs</param>
    protected void dlImages_ItemDataBound(object sender, 
        DataListItemEventArgs e)
    {
        System.Web.UI.WebControls.Image img = null;

        // make sure this is an item in the data list (not header etc.)
        if ((e.Item.ItemType == ListItemType.Item) ||
            (e.Item.ItemType == ListItemType.AlternatingItem))
        {
            // get a reference to the image used for the bar in the row
            img = (System.Web.UI.WebControls.Image)
                (e.Item.FindControl("imgThumbnail"));

            //get the img_pk from DataRow being bound
            int img_pk = Convert.ToInt16(
                ((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString());

            ThumbFromID.THUMBNAIL_SIZE = this.THUMBNAIL_SIZE;
            ThumbFromID.USE_SIZE_FOR_HEIGHT = false;
            // set the source to the page that generates the thumbnail image
            img.ImageUrl = ThumbFromID.PAGE_NAME + "?" +
                ThumbFromID.IMAGE_ID + "=" + img_pk;            
        }
    }
}

ThumbFromID.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ThumbFromID.aspx.cs" 
    Inherits="ThumbFromID" %>

ThumbFromID.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.OleDb;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
#region ThumbFromID CLASS
/// <summary>
/// ThumbFromID inherits from <see System.Web.UI.Page>System.Web.UI.Page</see>
/// Retrieves a binary array from the SQL Server database by the use of the
/// <see dbAccess>dbAccess</see>class. Once this binary
/// array is retrieved from the database, it is written to a memory stream
/// which is then written to the standard Html Response stream, this 
/// binary data represents an image from the database, which has been scaled 
/// using the fields within this class
/// </summary>
public partial class ThumbFromID : System.Web.UI.Page
{
    #region Instance Fields
    // constants used to create URLs to this page
    public const String PAGE_NAME = "ThumbFromID.aspx";
    //the image primary key for use when getting image data from database
    public const String IMAGE_ID = "img_pk";
    // height of the thumbnail created from the original image
    public static int THUMBNAIL_SIZE;
    // true if using thumbnail THUMBNAIL_SIZE for height, else it is used 
    // for width
    public static bool USE_SIZE_FOR_HEIGHT;
    #endregion
    #region Private Methods
    /// <summary>
    /// Retrieves a binary array from the SQL Server database by the use 
    /// of the <see dbAccess>dbAccess</see>class. Once this binary
    /// array is retrtieved from the database, it is written to a memory 
    /// stream which is then written to the standard Html Response stream, 
    /// this binary data represents an image from the database, which has 
    /// been scaled using the fields within this class
    /// </summary>
    private void Page_Load(object sender, System.EventArgs e)
    {
        byte[] imageData = null;
        MemoryStream ms = null;
        System.Drawing.Image fullsizeImage = null;
        String imageID = null;

        if (!Page.IsPostBack)
        {
            try
            {
                // get the ID of the image to retrieve from the database
                imageID = Request.QueryString[IMAGE_ID];
                imageData = dbAccess.GetImageByID(int.Parse(imageID));

                // create an image from the byte array
                ms = new MemoryStream(imageData);
                fullsizeImage = System.Drawing.Image.FromStream(ms);

                Response.ContentType = "image/Jpeg";
                ImageResize ir = new ImageResize();

                // Load your image and perform any resizing here
                ir.File = fullsizeImage;
                if (USE_SIZE_FOR_HEIGHT)
                    ir.Height = THUMBNAIL_SIZE;
                else
                    ir.Width = THUMBNAIL_SIZE;
                //get the thumbnail
                ir.GetThumbnail().Save(Response.OutputStream,
                    System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
            finally
            {
                ms.Close();
            }
        }
    }
    #endregion
    #region Web Form Designer generated code
    /// <summary>
    /// privided automaitically by Web Form Designer 
    /// </summary>
    /// <param name="e">the event args</param>
    override protected void OnInit(EventArgs e)
    {
        //
        // CODEGEN: This call is required by the ASP.NET Web Form Designer.
        //
        InitializeComponent();
        base.OnInit(e);
    }
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.Load += new System.EventHandler(this.Page_Load);
    }
    #endregion
}
#endregion

Web.Config

<?xml version="1.0"?>
<!-- 
    Note: As an alternative to hand editing this file you can use the 
    web admin tool to configure settings for your application. Use
    the Website->Asp.Net Configuration option in Visual Studio.
    A full list of settings and comments can be found in 
    machine.config.comments usually located in 
    \Windows\Microsoft.Net\Framework\v2.x\Config 
-->
<configuration>
  <appSettings/>
  <connectionStrings>
    <add name="EasyThumbs_DB" 
      connectionString="server=localhost;uid=sa;pwd=sa;Database=EasyThumbs"/>
  </connectionStrings>
  <system.web>
    <!-- 
            Set compilation debug="true" to insert debugging 
            symbols into the compiled page. Because this 
            affects performance, set this value to true only 
            during development.
        -->
    <compilation debug="true"/>
    <!--
            The <authentication> section enables configuration 
            of the security authentication mode used by 
            ASP.NET to identify an incoming user. 
        -->
    <authentication mode="Windows"/>
    <!--
            The <customErrors> section enables configuration 
            of what to do if/when an unhandled error occurs 
            during the execution of a request. Specifically, 
            it enables developers to configure html error pages 
            to be displayed in place of a error stack trace.

        <customErrors mode="RemoteOnly" 
            defaultRedirect="GenericErrorPage.htm">
            <error statusCode="403" redirect="NoAccess.htm" />
            <error statusCode="404" redirect="FileNotFound.htm" />
        </customErrors>
        -->
  </system.web>

</configuration>

What Do You Think ?

That's it, I would just like to ask, if you liked the article please vote for it.

Conclusion

I hope this has not been to hard for most folks to follow. I think its a fairly easy thumbnail solution.

History

v1.0 06/01/07

License

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

A list of licenses authors might use can be found here

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
 
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
 
Both of these at Sussex University UK.
 
Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
QuestionTrouble running Multiple times PinmemberMember 81568649-Sep-13 2:14 
AnswerRe: Trouble running Multiple times PinmemberMember 81568649-Sep-13 4:48 
QuestionThis was helpful and great but if you want a simple,easy and working database visit this link PinmemberSyed Wajahat Ali Shah4-Apr-13 11:34 
QuestionProject can not compile in .Net 4.0 PinmemberPoul-Erik Jensen11-Sep-12 3:07 
Questionneed help for show all ima btn Pinmemberamin.naghdbishi7-Sep-12 9:50 
QuestionAbout inserting images PinmemberWin32nipuh8-Apr-12 4:29 
QuestionAdding other data PinmemberVictoria Rowe3-Jul-11 23:37 
GeneralMy vote of 5 PinmemberVictoria Rowe3-Jul-11 23:26 
GeneralError object not an instance Pinmemberglstephens0814-Dec-10 6:02 
GeneralRe: Error object not an instance PinmemberVictoria Rowe4-Jul-11 21:00 
GeneralFullsize Image from Thumbnail Pinmemberdmcghee867-Dec-09 8:40 
GeneralRe: Fullsize Image from Thumbnail PinmvpSacha Barber7-Dec-09 9:26 
QuestionWhat about performance PinmemberAshu8711-Nov-08 18:02 
AnswerRe: What about performance PinmvpSacha Barber11-Nov-08 22:01 
GeneralAnother Example Pinmembermayurmv5-Sep-08 17:18 
QuestionHelp Using Example Code In A FormView Located In A UpdatePanel Pinmemberusacoder23-Aug-08 5:46 
AnswerRe: Help Using Example Code In A FormView Located In A UpdatePanel PinmvpSacha Barber24-Aug-08 22:53 
GeneralRe: Help Using Example Code In A FormView Located In A UpdatePanel Pinmemberusacoder25-Aug-08 5:01 
GeneralRe: Help Using Example Code In A FormView Located In A UpdatePanel PinmvpSacha Barber25-Aug-08 9:33 
QuestionGenerating an image (screenshot) dynamically from a URL Pinmemberrbunn8381510-Feb-08 20:05 
GeneralRe: Generating an image (screenshot) dynamically from a URL [modified] PinmvpSacha Barber10-Feb-08 20:57 
GeneralRe: Generating an image (screenshot) dynamically from a URL Pinmemberrbunn8381510-Feb-08 21:22 
GeneralThumbnailer Speed Pinmemberjustin.moses8-Jan-08 9:55 
GeneralRe: Thumbnailer Speed PinmvpSacha Barber8-Jan-08 10:03 
QuestionWhy is there a top and left edge border on the thumbnails? Pinmemberjustin.moses8-Jan-08 7:22 
AnswerRe: Why is there a top and left edge border on the thumbnails? Pinmemberjustin.moses11-Jan-08 12:03 
GeneralRe: Why is there a top and left edge border on the thumbnails? PinmvpSacha Barber11-Jan-08 21:52 
GeneralRe: Why is there a top and left edge border on the thumbnails? Pinmemberjustin.moses14-Jan-08 4:02 
AnswerRe: Why is there a top and left edge border on the thumbnails? [modified] PinmemberMember 1010419811-Jun-13 14:17 
GeneralThankyou for showing me the way Pinmembermallikarjunaprasad21-Dec-07 21:46 
GeneralThanks For you great Efforts (Botros) PinmemberMember 46692184-Dec-07 10:45 
GeneralVB.net version of this code Pinmemberscottt4025-Sep-07 3:44 
GeneralRe: VB.net version of this code PinmemberSacha Barber25-Sep-07 3:46 
GeneralFYI Pinmembersterlyng5823-Aug-07 9:16 
GeneralRe: FYI PinmemberSacha Barber23-Aug-07 22:48 
GeneralBLOB (image or text) data in SQL Server, and lack of caching PinmemberJon Rista26-May-07 16:59 
GeneralRe: BLOB (image or text) data in SQL Server, and lack of caching PinmemberSacha Barber26-May-07 22:17 
GeneralImage Storage in SQL Server Pinmembersamshah51219-May-07 6:13 
GeneralRe: Image Storage in SQL Server PinmemberSacha Barber19-May-07 7:29 
GeneralImage Control Pinmembersamshah51220-May-07 21:09 
GeneralRe: Image Control PinmemberSacha Barber21-May-07 2:10 
GeneralImage Storage in SQL Server Pinmembersamshah51219-May-07 6:10 
GeneralPerformance optimization PinmemberOmar Al Zabir18-May-07 19:04 
GeneralRe: Performance optimization PinmemberSacha Barber19-May-07 5:43 
GeneralVery useful PinmemberOmar Al Zabir18-May-07 18:57 
GeneralNice article ... but PinmemberJakub Florczyk18-May-07 2:29 
GeneralRe: Nice article ... but PinmemberSacha Barber18-May-07 3:03 
GeneralRe: Nice article ... but Pinmemberkingdomware22-May-07 3:48 
GeneralResizing greatly reduces quality of image thumbnail Pinmemberckwyand2-May-07 18:28 
GeneralRe: Resizing greatly reduces quality of image thumbnail PinmemberSacha Barber3-May-07 9:18 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 17 May 2007
Article Copyright 2007 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid