Implement the first of the two ASP.NET pages described in
Recipe 12.3, changing the
Page_Load
method in the code-behind class to scale
the full-sized image retrieved from the database to the appropriate
size for a thumbnail presentation.
In the Page_Load
method of the code-behind class
for the page, use the .NET language of your choice to:
Create a System.Drawing.Image
object from the byte
array retrieved from the database.
Use a constant to define the height of the thumbnail and then calculate the width to maintain the aspect ratio of the image.
Use the GetThumbnailImage
method of the
Image
object to scale the image to the desired
size.
Load the thumbnail image into a MemoryStream
and
then write it to the Response
object.
Example 12-16 and Example 12-17 show the VB and C# code-behind class for our
example that illustrates this solution. (See the
CH12ImageFromDatabaseVB
.aspx
file and VB and C# code-behind files in Recipe 12.3 for our starting point.)
To display the thumbnails, create another ASP.NET page, add a
DataList
control with image tags in the
ItemTemplate
, and then use data binding to set the
src
attributes of the image tags.
In the .aspx
file for the page:
Use a DataList
control to provide the ability to
generate a list using data binding.
Use a HeaderTemplate
to label the table of images.
Use an ItemTemplate
to define an image that is
displayed in the DataList
.
In the code-behind class for the page, use the .NET language of your choice to:
Open a connection to the database.
Build a query string, and read the list of images from the database.
Assign the data source to the DataList
control and
bind it.
Set the src
attribute of the image tags used to
display the thumbnail images in the ItemDataBound
event of the DataList
.
Example 12-18 through Example 12-20 show the .aspx
file and
VB and C# code-behind files for the application that uses the
dynamically generated images. The output produced by the page is
shown in Figure 12-4.
The rationale for this recipe is similar to that of Recipe 12.3. That is, you need a convenient way to display images from a database, in this case a page of thumbnail images, and it must efficiently move the image data to the browser while maintaining the maximum flexibility in selecting images from the data store.
This recipe uses the same approach as in Recipe 12.3 where, with one page, an image is retrieved from the database and streamed to the browser, and a second page is used to generate the image requests and display the results, which in this case is a set of thumbnails. Additionally, the image retrieval page must scale the images to thumbnail size.
In our example that demonstrates the solution, the
Page_Load
method of the code-behind for the image
building page (the CH12ThumbnailFromDatabase
page)
is modified to scale the full-sized image retrieved from the database
to the appropriate size for a thumbnail presentation.
The first step to scale the image is to create a
System.Drawing.Image
object from the byte array
retrieved from the database. This requires loading the byte array
into a MemoryStream
and then using the
FromStream
method of the Image
class to create the image.
Next, we need to calculate how much to reduce the image. A constant is used to define the height of the thumbnail, and the width is calculated by determining how much the height is being reduced and multiplying the value times the width of the full-size image.
It is important to reduce the height and width by the same scale factor to keep the aspect ratio correct. If the height or width is reduced by a different amount, the image will be distorted.
Handling mixed calculations of integers and doubles can result in unexpected results. Visual Basic is more tolerant and will allow the division of two integers with the quotient set to a variable of type double and result in the correct value. C# will return an integer result from the division of two integers, effectively truncating the result. It is best to cast at least the numerator to the type of the resultant variable.
Now that the width and height of the thumbnail are determined, the
GetThumbnailImage
method of the
full-size
image can be used to return a scaled-down image to use as the
thumbnail.
Once the thumbnail image is created it can be loaded into a
MemoryStream
and then written to the
Response
object in the same manner described in
Recipe 12.1.
The web form used to display the thumbnails uses a
DataList
control to provide the ability to
generate the list using data binding. The DataList
is configured to display four columns horizontally by setting the
RepeatColumns
attribute to "4
"
and the RepeatDirection
attribute to
"Horizontal
“. This will start a new row in the
table used to display the images after every fourth image.
A HeaderTemplate
is used to label the table of
images. The template can contain any HTML that can be properly
displayed in a table. In this example, the template consists of a
single table row containing a single cell with the heading for the
table. The colspan
attribute is set to
"4
" to cause the cell to span across all columns
in the table, and the align
attribute is set to
"center
" to center the heading.
An ItemTemplate
is used to define an item that is
displayed in the DataList
. In this example, the
template consists of an img
tag that simply has
the ID
and Runat
attributes set
to provide access to the item from the code-behind.
The Page_Load
method in the code-behind reads the
list of images from the database and binds them to the
DataList
control. This is accomplished by opening
a connection to the database, querying for a list of the image IDs,
then setting the DataSource
and calling the
dataBind
method of the
DataList
. The only data we need from the database
is the list of IDs for the images. These will be used to set the
image sources, and the actual reading of the image data will be done
by the code described earlier.
The src
attribute of the image tags used to
display the thumbnail images is set in the
ItemDataBound
event of the
DataList
. The ItemDataBound
event is called for every item in the DataList
,
including the header. Therefore, it is important to check the item
type, since image tags only appear in the data items. Data items can
be an Item
or an
AlternatingItem
.
If the item is actually a data item, we need to get a reference to
the image control in the item. This is accomplished by using the
FindControl
method of the item to locate the image
control using the ID assigned in the .aspx
file.
This reference must be cast to an HtmlImage
type
since the return type of FindControl
is an
Object
.
Once a reference to the image is obtained, the src
attribute can be set to the name of the ASP.NET page that is used to
generate the thumbnail image passing the ID of the image in the URL.
As with Recipe 12.3, constants are
used for the name of the page and the name of the item passed in the
URL.
The ID of the image is obtained from the DataItem
method of the item. This must be cast to a
DbDataRecord
type to allow
“looking up” the ID of the image
using the name of the column included in the SQL query used in the
bindData
method described earlier.
This example presents a useful method of displaying thumbnails of images stored in a database. When used with reasonably small images, the performance is acceptable for most applications. If the images are very large, however, you may want to create the thumbnail images offline and store them in the database to avoid the performance hit for real-time conversion.
Example 12-16. Page_Load method for generating thumbnail image (.vb)
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load'height of the thumbnail created from the original image
Const THUMBNAIL_HEIGHT As Integer = 75
Dim dbConn As OleDbConnection Dim dc As OleDbCommand Dim imageData( ) As Byte Dim strConnection As String Dim strSQL As String Dim ms As MemoryStream Dim fullsizeImage As image Dim thumbnailImage As image Dim thumbnailWidth As Integer Dim imageID As String If (Not Page.IsPostBack) Then Try 'get the ID of the image to retrieve from the database imageID = Request.QueryString(QS_IMAGE_ID) 'get the connection string from web.config and open a connection 'to the database strConnection = _ ConfigurationSettings.AppSettings("dbConnectionString") dbConn = New OleDb.OleDbConnection(strConnection) dbConn.Open( ) 'build the query string and get the data from the database strSQL = "SELECT ImageData " & _ "FROM BookImage " & _ "WHERE BookImageID=" & imageID dc = New OleDbCommand(strSQL, dbConn) imageData = CType(dc.ExecuteScalar( ), Byte( ))'create an image from the byte array
ms = New MemoryStream(imageData)
fullsizeImage = System.Drawing.Image.FromStream(ms)
'calculate the amount to shink the height and width
thumbnailWidth = _
CInt(Math.Round((CDbl(THUMBNAIL_HEIGHT) / _
fullsizeImage.Height) * fullsizeImage.Width))
'create the thumbnail image
thumbnailImage = fullsizeImage.GetThumbnailImage(thumbnailWidth, _
THUMBNAIL_HEIGHT, _
Nothing, _
IntPtr.Zero)
'write thumbnail to the response object
ms = New MemoryStream
thumbnailImage.Save(ms, ImageFormat.Jpeg)
Response.ContentType = "image/jpg"
Response.BinaryWrite(ms.ToArray( ))
Finally 'clean up If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End If End Sub 'Page_Load
Example 12-17. getImage method for generating thumbnail image (.cs)
private void Page_Load(object sender, System.EventArgs e) {// height of the thumbnail created from the original image
const int THUMBNAIL_HEIGHT = 75;
OleDbConnection dbConn = null; OleDbCommand dc = null; byte[] imageData = null; String strConnection = null; String strSQL = null; MemoryStream ms = null; System.Drawing.Image fullsizeImage = null; System.Drawing.Image thumbnailImage = null; int thumbnailWidth; String imageID = null; if (!Page.IsPostBack) { try { // get the ID of the image to retrieve from the database imageID = Request.QueryString[QS_IMAGE_ID]; // get the connection string from web.config and open a connection // to the database strConnection = ConfigurationSettings.AppSettings["dbConnectionString"]; dbConn = new OleDbConnection(strConnection); dbConn.Open( ); // build the query string and get the data from the database strSQL = "SELECT ImageData " + "FROM BookImage " + "WHERE BookImageID=" + imageID; dc = new OleDbCommand(strSQL, dbConn); imageData = (byte[])(dc.ExecuteScalar( ));// create an image from the byte array
ms = new MemoryStream(imageData);
fullsizeImage = System.Drawing.Image.FromStream(ms);
// calculate the amount to shink the height and width
thumbnailWidth =
Convert.ToInt32(Math.Round((Convert.ToDouble(THUMBNAIL_HEIGHT) /
fullsizeImage.Height) * fullsizeImage.Width));
// create the thumbnail image
thumbnailImage = fullsizeImage.GetThumbnailImage(thumbnailWidth,
THUMBNAIL_HEIGHT,
null,
IntPtr.Zero);
// write thumbnail to the response object
ms = new MemoryStream( );
thumbnailImage.Save(ms, ImageFormat.Jpeg);
Response.ContentType = "image/jpg";
Response.BinaryWrite(ms.ToArray( ));
} finally { if (dbConn != null) { dbConn.Close( ); } } } } // Page_Load
Example 12-18. Display thumbnail images (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH12TestThumbnailsFromDatabaseVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH12TestThumbnailsFromDatabaseVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Display Thumbnails</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmDisplayThumbnails" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td align="center"> </td> </tr> <tr> <td align="center" class="PageHeading"> Display Thumbnail Images (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"><asp:DataList ID="dlImages" Runat="server"
RepeatColumns="4" RepeatDirection="Horizontal"
RepeatLayout="Table" Width="50%">
<HeaderTemplate>
<tr>
<td colspan="4" class="SubHeading" align="center">
Thumbnails of Images In Database<br /><br />
</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<img id="imgThumbnail" runat="server" border="0" >
</ItemTemplate>
</asp:DataList>
</td> </tr> </table> </form> </body> </html>
Example 12-19. Display thumbnail images code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH12TestThumbnailsFromDatabaseVB.aspx.vb ' ' Description: This module provides the code behind for the ' CH12TestThumbnailsFromDatabaseVB.aspx page. ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.Common Imports System.Data.OleDb Imports System.Web.UI.WebControls Namespace ASPNetCookbook.VBExamples Public Class CH12TestThumbnailsFromDatabaseVB Inherits System.Web.UI.Page 'controls on the form Protected WithEvents dlImages As System.Web.UI.WebControls.DataList '*************************************************************************** ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. ' '--------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim dbConn As OleDbConnection Dim dc As OleDbCommand Dim dr As OleDbDataReader Dim strConnection As String Dim strSQL As String If (Not Page.IsPostBack) Then Try'get the connection string from web.config and open a connection
'to the database
strConnection = _
ConfigurationSettings.AppSettings("dbConnectionString")
dbConn = New OleDb.OleDbConnection(strConnection)
dbConn.Open( )
'build the query string and get the data from the database
strSQL = "SELECT BookImageID " & _
"FROM BookImage"
dc = New OleDbCommand(strSQL, dbConn)
dr = dc.ExecuteReader( )
'set the source of the data for the repeater control and bind it
dlImages.DataSource = dr
dlImages.DataBind( )
Finally 'clean up If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End If End Sub 'Page_Load '*************************************************************************** ' ' ROUTINE: dlImages_ItemDataBound ' ' DESCRIPTION: This routine is the event handler that is called for each ' item in the datalist after a data bind occurs. It is ' responsible for setting the source of the image tag to ' the URL of the page that will generate the thumbnail ' images with the ID of the appropriate image for the item. '---------------------------------------------------------------------------Private Sub dlImages_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) _
Handles dlImages.ItemDataBound
Dim img As System.Web.UI.HtmlControls.HtmlImage
'make sure this is an item in the data list (not header etc.)
If ((e.Item.ItemType = ListItemType.Item) Or _
(e.Item.ItemType = ListItemType.AlternatingItem)) Then
'get a reference to the image used for the bar in the row
img = CType(e.Item.FindControl("imgThumbnail"), _
System.Web.UI.HtmlControls.HtmlImage)
'set the source to the page that generates the thumbnail image
img.Src = CH12ThumbnailFromDatabaseVB.PAGE_NAME & "?" & _
CH12ThumbnailFromDatabaseVB.QS_IMAGE_ID & "=" & _
CStr(CType(e.Item.DataItem, DbDataRecord)("BookImageID"))
End If
End Sub 'dlImages_ItemDataBound
End Class 'CH12TestThumbnailsFromDatabaseVB End Namespace
Example 12-20. Display thumbnail images code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH12TestThumbnailsFromDatabaseCS.aspx.cs // // Description: This module provides the code behind for the // CH12TestThumbnailsFromDatabaseCS.aspx page // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.Common; using System.Data.OleDb; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH12TestThumbnailsFromDatabaseCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.WebControls.DataList dlImages; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { OleDbConnection dbConn = null; OleDbCommand dc = null; OleDbDataReader dr = null; String strConnection = null; String strSQL = null; // wire the item data bound event this.dlImages.ItemDataBound += new DataListItemEventHandler(this.dlImages_ItemDataBound); if (!Page.IsPostBack) { try {// get the connection string from web.config and open a connection
// to the database
strConnection =
ConfigurationSettings.AppSettings["dbConnectionString"];
dbConn = new OleDbConnection(strConnection);
dbConn.Open( );
// build the query string and get the data from the database
strSQL = "SELECT BookImageID " +
"FROM BookImage";
dc = new OleDbCommand(strSQL, dbConn);
dr = dc.ExecuteReader( );
// set the source of the data for the repeater control and bind it
dlImages.DataSource = dr;
dlImages.DataBind( );
} finally { // clean up if (dbConn != null) { dbConn.Close( ); } } } } // Page_Load //************************************************************************ // // ROUTINE: dlImages_ItemDataBound // // DESCRIPTION: This routine is the event handler that is called for // each item in the datalist after a data bind occurs. // It is responsible for setting the source of the image // tag to the URL of the page that will generate the // thumbnail images with the ID of the appropriate image // for the item. //------------------------------------------------------------------------private void dlImages_ItemDataBound(Object sender,
System.Web.UI.WebControls.DataListItemEventArgs e)
{
System.Web.UI.HtmlControls.HtmlImage 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.HtmlControls.HtmlImage)
(e.Item.FindControl("imgThumbnail"));
// set the source to the page that generates the thumbnail image
img.Src = CH12ThumbnailFromDatabaseCS.PAGE_NAME + "?" +
CH12ThumbnailFromDatabaseCS.QS_IMAGE_ID + "=" +
(((DbDataRecord)(e.Item.DataItem))["BookImageID"]).ToString( );
}
} // dlImages_ItemDataBound
} // CH12TestThumbnailsFromDatabaseCS }