Chapter 2: Creating Thumbnails

Contents

2.1 Thumbnail-Creating Steps

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

  1. Create an instance of the AspJpeg object.
  2. Open the source image from disk or memory using the Open or OpenBinary methods, respectively.
  3. Set the desired width and height of the thumbnail via the Width and Height properties. To preserve aspect ratio, the original dimensions can be retrieved via the OriginalWidth and OriginalHeight properties.
  4. Save the resultant thumbnail to disk, memory, or an HTTP stream by calling Save, Binary, or 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:

<%
' Create instance of AspJpeg
Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Open source image
Jpeg.Open "c:\path\myimage.jpg"

' New width
L = 100

' Resize, preserve aspect ratio
Jpeg.Width = L
Jpeg.Height = Jpeg.OriginalHeight * L / Jpeg.OriginalWidth

' create thumbnail and save it to disk
Jpeg.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 jpeg.OriginalWidth > jpeg.OriginalHeight Then
   jpeg.Width = L
   jpeg.Height = jpeg.OriginalHeight * L / jpeg.OriginalWidth
Else
   jpeg.Height = L
   jpeg.Width = jpeg.OriginalWidth * L / jpeg.OriginalHeight
End If
...

Starting with AspJpeg 1.4, 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:

..
jpeg.PreserveAspectRatio = True

If jpeg.OriginalWidth > jpeg.OriginalHeight Then
   jpeg.Width = L
Else
   jpeg.Height = L
End If
...

By default, AspJpeg generates images in JPEG format. Other supported output image formats are PNG, BMP, and WEBP. The output format can be specified via the OutputFormat property of the main ASPJpeg object. Valid values are 0 (JPEG, default), 1 (PNG), 2 (BMP) and 3 (WEBP). WEBP is supported as of Version 2.9.0.2.

  • PNG output can also be specified by setting the PNGOutput property to True instead of using the OutputFormat property.
  • WEBP output uses lossy compression by default. To specify lossless compression, the Baseline property needs to be set to False.
  • PNG and WEBP output is described in detail in Chapter 10.
..
Jpeg.OutputFormat = 1 ' PNG output
Jpeg.PNGOutput = True ' Alternative way to specify PNG output
Jpeg.Save "c:\path\thumbnail.png"
...

Jpeg.OutputFormat = 3 ' WEBP output, lossy compression
Jpeg.Save "c:\path\thumbnail.webp"
...

Jpeg.OutputFormat = 3 ' WEBP output
Jpeg.Baseline = False ' Lossless compression
Jpeg.Save "c:\path\thumbnail.webp"

2.2 Sending Thumbnails Directly to the Browser

When used in an IIS/ASP environment, AspJpeg 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'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.asp contains several <IMG> tags invoking the script 02_sendbinary.asp and passing file path and size parameters to it, as follows:

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

Below are the ASP/VB Script and ASP.NET/C# versions of the 02_sendbinary.asp 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 Jpeg.SendBinary must not contain any HTML tags, or the data stream it generates will be corrupted.

Under .NET, you must use the directive <%@ Page aspCompat="True" %> for the SendBinary method to work properly.

<%
Response.Expires = 0

' create instance of AspJpeg
Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Open source file
Jpeg.Open( Request("path") )

' Set new height and width
Jpeg.Width = Request("Width")
Jpeg.Height = Jpeg.OriginalHeight * Jpeg.Width / Jpeg.OriginalWidth

' Perform resizing and
' send resultant image to client browser
Jpeg.SendBinary

%>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="ASPJPEGLib" %>
<%@ Page aspCompat="True" %>

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

void Page_Load(Object Source, EventArgs E)
{
// this script may not contain any HTML tags, not even comments

ASPJPEGLib.IASPJpeg objJpeg;
objJpeg = new ASPJPEGLib.ASPJpeg();

// Open source image
objJpeg.Open( Request["path"] );

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

// Preserve aspect ratio
objJpeg.Height = objJpeg.OriginalHeight * objJpeg.Width / objJpeg.OriginalWidth;

// Send thumbnail data to client browser
objJpeg.SendBinary(Missing.Value);
}

</script>

Click the links below to run this code sample:

2.3 Opening Images from Memory

Starting with version 1.2, AspJpeg offers the method OpenBinary which opens an image from a binary memory source (such as an ADO recordset) rather than a disk file. You can use this method to create thumbnails from images residing in a database as blobs. You can also use it to open images uploaded to memory with AspUpload (this topic is covered in the next chapter).

The OpenBinary method is demonstrated by the code samples 02_display.asp and 02_fromdatabase.asp. The file 02_display.asp simply invokes another ASP script, 02_fromdatabase.asp, multiple times with various parameters. The file 02_fromdatabase.asp uses the method OpenBinary rather than Open and passes an ADO recordset value containing a source image as an argument.

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

<% ' Using ADO, open database with an image blob
strConnect = "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & Server.MapPath("../db/aspjpeg.mdb")

Set rs = Server.CreateObject("adodb.recordset")
SQL = "select image_blob from images2 where id = " & Request("id")
rs.Open SQL, strConnect, 1, 3

Set Jpeg = Server.CreateObject("Persits.Jpeg")

' Open image directly from recordset

Jpeg.OpenBinary rs("image_blob").Value

' Resize
jpeg.Width = Request("Width")
' Set new height, preserve original aspect ratio
jpeg.Height = jpeg.OriginalHeight * jpeg.Width / jpeg.OriginalWidth

Jpeg.SendBinary

rs.Close
%>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="ASPJPEGLib" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Page aspCompat="True" %>

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

void Page_Load(Object Source, EventArgs E)
{
ASPJPEGLib.IASPJpeg objJpeg;
objJpeg = new ASPJPEGLib.ASPJpeg();

// Connect to database
String strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("../db/aspjpeg.mdb");
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
objJpeg.OpenBinary( myReader["image_blob"] );

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

// Set new height, preserve aspect ratio
objJpeg.Height = objJpeg.OriginalHeight * objJpeg.Width / objJpeg.OriginalWidth;

// Create thumbnail and send it directly to client browser // aspCompat=True is required.

objJpeg.SendBinary( Missing.Value );

myReader.Close();
myConnection.Close();
}
</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 also offers the Binary property which returns the resultant thumbnail as a binary array of bytes. This property allows you to save the thumbnail directly in the database without creating a temporary file on disk:

<%
...
Set rs = Server.CreateObject("adodb.recordset")
rs.Open "images", strConnect, 1, 3
rs.AddNew

rs("image_blob").Value = Jpeg.Binary

rs.Update
...
%>

This property will be covered in detail in the next chapter.

2.5 Opening Remote Images From URLs

For AspJpeg to open a remote image located at a particular URL, this image must first be downloaded to the server where AspJpeg is running. To perform the download, Microsoft XML DOC's XMLHTTP object can be used.

The XMLHTTP object enables you to specify a URL to download the image from, and perform the download to a memory array, which can then be passed directly to AspJpeg's OpenBinary method. This frees your application from the necessity to create a temporary file on the server's hard drive:

<%
Set objHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP")
objHTTP.Open "GET", "http://www.aspjpeg.com/images/ps_logo.gif"
objHTTP.Send

Set Jpeg = Server.CreateObject("Persits.Jpeg")
Jpeg.OpenBinary(objHTTP.responseBody)
...
%>

In .NET, the code is somewhat more complicated as there is no object to perform a binary download straight to memory:

<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="ASPJPEGLib" %>

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

void Page_Load(Object Source, EventArgs E)
{
  String Url = "http://www.aspjpeg.com/images/ps_logo.gif";
  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;
  }

  IASPJpeg objJpeg = new ASPJpeg();
  objJpeg.OpenBinary( ImageBytes );
  ...
}

</script>