Chapter 2: Creating Thumbnails

Contents

2.1 Thumbnail-Creating Steps

To create a basic image thumbnail with AspJpeg.NET, the following steps must be taken:

  1. Create an instance of the JpegManager object.
  2. Open the source image from disk or memory using the JpegManager.OpenImage method.
  3. Set the desired width and height of the thumbnail via the JpegImage.Width and JpegImage.Height properties. To preserve aspect ratio, the original dimensions can be retrieved via the JpegImage.OriginalWidth and JpegImage.OriginalHeight properties.
  4. Save the resultant thumbnail to disk, memory, or an HTTP stream by calling JpegImage.Save, JpegImage.Binary, or JpegImage.SendBinary, respectively.

The following code sample opens a disk image and creates a thumbnail with the width hard-coded to a particular value (100 pixels in this sample) while preserving the original aspect ratio:

JpegManager objJpeg = new JpegManager();
JpegImage objImage = objJpeg.OpenImage(@"c:\path\image.jpg");

int L = 100;

objImage.Width = L;
objImage.Height = objImage.OriginalHeight * L / objImage.OriginalWidth;

objImage.Save(@"c:\path\thumbnail.jpg");

In the sample above, we calculate the new height as a product of the original height and a scaling factor which, in turn, is computed as a ratio of the new width to the original width.

If we were to inscribe the thumbnail into a given rectangle, i.e. set the longest dimension to a particular value, the following code could be used:

...
if(objImage.OriginalWidth > objImage.OriginalHeight)
{
   objImage.Width = L;
   objImage.Height = objImage.OriginalHeight * L / objImage.OriginalWidth;
}
else
{
   objImage.Height = L;
   objImage.Width = objImage.OriginalWidth * L / objImage.OriginalHeight;
}
...

The task of preserving aspect ratio is simplified via the property PreserveAspectRatio. If set to true, it creates a link between the Width and Height properties, so that a change in one dimension automatically causes a proportional change in the other. Using the PreserveAspectRatio property, the code sample above can be simplified as follows:

..
objImage.PreserveAspectRatio = true;

if (objImage.OriginalWidth > objImage.OriginalHeight)
   objImage.Width = L;
else
   objImage.Height = L;
...

The Save method used in the code sample above overwrites the output image file if it already exists. In addition to Save, the JpegImage object also offers the method SaveUnique. which forces unique file name generation. For example, if the file thumbnail.jpg already exists in the specified directory and another document is being saved under the same name, the SaveUnique method tries the filenames thumbnail(1).jpg, thumbnail(2).jpg, etc., until a non-existent name is found. The method returns the filename (without the path) under which the file ends up being saved.

2.2 Sending Thumbnails Directly to the Browser

When used in an IIS/ASP.NET environment, AspJpeg.NET is capable of sending a resultant thumbnail directly to the browser without creating a temporary file on the server. This is achieved via the method SendBinary. This method is similar to Save but instead of saving a thumbnail to disk, it internally makes calls to ASP.NET's Response.BinaryWrite method, thereby sending the image to the client browser.

The SendBinary method must be called from a separate script file which should contain no HTML tags whatsoever. This script should be invoked via the SRC attribute of an <IMG> tag.

The code sample 02_manythumbs.cs.aspx (02_manythumbs.vb.aspx) contains several <IMG> tags invoking the script 02_sendbinary.cs.aspx (02_sendbinary.vb.aspx) and passing file path and size parameters to it, as follows:

<IMG SRC="02_sendbinary.cs.aspx?path=<% = Path %>&width=300">

Below are the C# and VB.NET versions of the 02_sendbinary script. Notice that the width of the thumbnail is passed via the query string variable Width, and the height is set to be proportional to the specified width.

Once again, a script calling objImage.SendBinary must not contain any HTML tags, or the data stream it generates will be corrupted.

<%@ Page Language="C#" debug="true" %>

<%@ Import Namespace="System.IO"%>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="C#">

void Page_Load( Object Source, EventArgs E)
{
  // Create instance of JpegManager
  JpegManager objJpeg = new JpegManager();

  // Open Source image
  JpegImage objImage = objJpeg.OpenImage(Request["path"]);

  // Preserve aspect ratio
  objImage.PreserveAspectRatio = true;

  // Set new width
  objImage.Width = int.Parse(Request["width"]);

  // Send thumbnail directly to browser
  objImage.SendBinary("filename=\"" +
  Path.GetFileName( Request["path"] ) + "\"");
}

</script>
<%@ Page Language="VB" debug="true" %>

<%@ Import Namespace="System.IO"%>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="VB">

Sub Page_Load( Source As Object, E As EventArgs )
  ' Create instance of JpegManager
  Dim objJpeg As JpegManager = new JpegManager()

  ' Open Source image
  Dim objImage As JpegImage = objJpeg.OpenImage(Request("path"))

  ' Preserve aspect ratio
  objImage.PreserveAspectRatio = True

  ' Set new width
  objImage.Width = Integer.Parse(Request("width"))

  ' Send thumbnail directly to browser
  objImage.SendBinary("filename=""" +
  Path.GetFileName(Request("path")) + """")
End Sub

</script>

Click the links below to run this code sample:

2.3 Opening Images from Memory

The version of the OpenImage method described so far opens images from disk. Another overloaded version of this method opens images from memory. It expects a byte array as an argument and can be used to open images stored in the database as blobs. It can also be used to open images uploaded from a browser to memory (this topic is covered in the next chapter).

The OpenImage( byte []) overload is demonstrated by the code samples 02_display.cs.aspx and 02_fromdatabase.cs.aspx (and also 02_display.vb.aspx and 02_fromdatabase.vb.aspx). The file 02_display.cs.aspx (02_display.vb.aspx) simply invokes another .aspx script, 02_fromdatabase.cs.aspx (02_fromdatabase.vb.aspx), multiple times with various parameters. The OpenImage method is passed an OLEDB recordset value containing the source image as an argument.

The script 02_fromdatabase.cs.asp/vb.aspx is shown below:

<%@ Page Language="C#" debug="true" %>

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="C#">

void Page_Load( Object Source, EventArgs E)
{
  // Create instance of JpegManager
  JpegManager objJpeg = new JpegManager();

  string strDBPath = Server.MapPath("../db/aspjpeg.mdb");

  // Use one or the other.
  //string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
  //+ strDBPath
  string strConn = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source="
  + strDBPath;

  OleDbConnection myConnection = new OleDbConnection(strConn);
  myConnection.Open();

  OleDbCommand myCommand = new OleDbCommand(
  "select image_blob from images2 where id = "
  + Request["id"], myConnection);
  OleDbDataReader myReader = myCommand.ExecuteReader();
  myReader.Read();

  // Open source image
  JpegImage objImage = objJpeg.OpenImage((byte[])myReader["image_blob"]);

  // Preserve aspect ratio
  objImage.PreserveAspectRatio = true;

  // Resize
  objImage.Width = int.Parse(Request["Width"]);

  // Create thumbnail and send it directly to client browser
  objImage.SendBinary();

  myReader.Close();
  myConnection.Close();
}
</script>
<%@ Page Language="VB" debug="true" %>

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="VB">

Sub Page_Load( Source As Object, E As EventArgs )
  ' Create instance of JpegManager
  Dim objJpeg As JpegManager = New JpegManager()

  Dim strDBPath As string = Server.MapPath("../db/aspjpeg.mdb")

  ' Use one or the other.
  'Dim strConn As String="Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+
  ' strDBPath
  Dim strConn As String="Provider=Microsoft.ACE.OLEDB.12.0; Data Source="+
  strDBPath

  Dim myConnection As OleDbConnection= new OleDbConnection(strConn)
  myConnection.Open()

  Dim myCommand As OleDbCommand =
  New OleDbCommand("select image_blob from images2 where id = " +
  Request("id"), myConnection)
  Dim myReader As OleDbDataReader = myCommand.ExecuteReader()
  myReader.Read()

  ' Open source image
  Dim objImage As JpegImage = objJpeg.OpenImage(
  CType(myReader("image_blob"), Byte()))

  ' Preserve aspect ratio
  objImage.PreserveAspectRatio = True

  ' Resize
  objImage.Width = Integer.Parse(Request("Width"))

  ' Create thumbnail and send it directly to client browser
  objImage.SendBinary()

  myReader.Close()
  myConnection.Close()
End Sub
</script>

The scripts above require that a Microsoft Access OLEDB provider be installed on your machine, which is largely a relic of the past. Therefore, the links to run these code samples are not provided.

2.4 Output to Memory

In addition to the Save and SendBinary methods, AspJpeg.NET also offers the Binary property which returns the resultant thumbnail as an array of bytes. This property allows you to save the thumbnail directly in the database without creating a temporary file on disk:

...
param = cmd.Parameters.Add("@file", System.Data.OleDb.OleDbType.Binary);
param.Value = objImg.Binary;
cmd.ExecuteNonQuery();

2.5 Opening Remote Images From URLs

For AspJpeg.NET to open a remote image located at a particular URL, this image must first be downloaded to the server where AspJpeg.NET is running. The following code sample uses the .NET objects WebRequest and WebResponse to download the image from a URL to memory and then opens it with OpenImage.

<%@ Page Language="C#" debug="true" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="C#">

void Page_Load( Object Source, EventArgs E)
{
  string Url = "http://www.persits.com/images/top_logo_persits.png";
  WebRequest request = WebRequest.Create(Url);
  WebResponse response = request.GetResponse();

  Stream responseStream = response.GetResponseStream();

  int nLen = (int)response.ContentLength;
  byte[] ImageBytes = new byte[nLen];

  int n = 0;
  int nBuffer = 4096;
  while( n < nLen )
  {
    int nBytesRead = responseStream.Read(ImageBytes, n,
    (nLen - n < nBuffer) ? nLen - n : nBuffer);
    n += nBytesRead;
  }

  // Create instance of JpegManager
  JpegManager objJpeg = new JpegManager();
  JpegImage objImage = objJpeg.OpenImage(ImageBytes);

  // reduce size by 50%
  objImage.PreserveAspectRatio = true;
  objImage.Width /= 2;

  // Create thumbnail and send it directly to client browser
  objImage.SendBinary();
}

</script>
<%@ Page Language="VB" debug="true" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="Persits.Jpeg"%>

<script runat="server" languge="VB">

Sub Page_Load( Source As Object, E As EventArgs )
  Dim Url As String =
    "http://www.persits.com/images/top_logo_persits.png"
  Dim request As WebRequest = WebRequest.Create(Url)
  Dim response As WebResponse = request.GetResponse()

  Dim responseStream As Stream = response.GetResponseStream()

  Dim nLen As Integer = response.ContentLength

  Dim ImageBytes(nLen) As Byte

  Dim n As Integer = 0
  Dim nBuffer As Integer = 4096
  While n < nLen
    Dim nBytesRead As Integer = responseStream.Read(
    ImageBytes, n, If((nLen - n < nBuffer), nLen - n, nBuffer))
    n += nBytesRead
  End While

  ' Create instance of JpegManager
  Dim objJpeg As JpegManager = New JpegManager()
  Dim objImage As JpegImage = objJpeg.OpenImage(ImageBytes)

  ' reduce size by 50%
  objImage.PreserveAspectRatio = True
  objImage.Width = objImage.Width / 2

  ' Create thumbnail and send it directly to client browser
  objImage.SendBinary()
End Sub
</script>

Click the links below to run this code sample: