ExposureRoom Home
  Log in Sign Up
Shiv's Website
Shiv Kumar
United States
Friends: 71
Focused on : 2
 
       
                                                             

Reducing Image Size on-the-fly (thumbnails)

Not Rated YetNot Rated YetNot Rated YetNot Rated YetNot Rated Yet0votes
January 15, 2008 11:18 AM  Views:107   Favorited:0 Comments:0
Filed Under:  Programming
Tags:  Delphi, ISAPI
 

On to more fun things! In this article, we’re going to send images (from within a database) to a web browser. But we won't just stream out images straight out of the database. We'll stream out a thumbnail version of each image that we'll create on-the-fly.We will also explore using the TQueryTableProducer component that comes as part of Delphi’s web broker technology.

Sending Data

This part is really simple. Actually, Delphi makes it really simple. We won’t need to write any code for this so let's start building the project.

  1. Start a new ISAPI Web server (extension) application.
  2. Drop down a TQuery component and change its name to qryData.
  3. Set the Database property of qryData to DBDEMOS.
  4. Set the Active property to True.
  5. Set the SQL property to SELECT * FROM BIOLIFE.
  6. Drop down a TQueryTableProducer component on the Web Data Module.
  7. Drop down its Query property and set it to qryData.
  8. Double click on the Web Data Module (or right click on it and choose "Action Editor...") and create a new action item.
  9. Set the PathInfo property of this action item to
    /data
    .
  10. Change the Name property of the action item to
    waData
  11. Set the Default property to
    True
  12. Drop down the Producer property of the action item and set it to
    QueryTableProducer1
    .
  13. Drop down a TSession component and set its AutoSessionName property to
    True
    .
  14. From the Project | Options menu, set the output directory to C:\inetpub\scripts (or the scripts folder of your web server. This step is followed in all ISAPI/CGI projects.

Your Object inspector and Web Data Module should look like that shown in Figure 1.

ISAPI3F1.png

Figure1: Showing the Object inspector and Web Data Module thus far.

Explanation

There can be only one action item per application with its default property set to True. What this really does is, it allows you to call your ISAPI/CGI application from a browser without the need to specify an action. So the URLs http://www.mydomain.com/scripts/myserverextension.dll/data and http://www.mydomain.com/scripts/myserverextension.dll will return the same page. In other words, the same action is executed in this case since the action item with the pathinfo - /data has been set as the default action.

Setting the Producer property of the action item to the QueryTableProducer1 causes the Response.Content property of the web module to be automatically set to QueryTableProducer1.Content in the OnAction event of the action item. One could create an OnAction event for this action item and write the line

Response.Content := QueryTableProducer1.Content;

to achieve the same end result without setting the Producer property. In this case we'll use the property and so we won’t write any code in the OnAction event.

Every request from the web server causes your ISAPI application to spawn a new thread within which a new instance of the web data module is created. To allow for multiple simultaneous access to a we use a TSession component and set its AutoSessionName property to True so it generates a new session name for every session (thread). For CGI applications this is not required (and should not be done) since every request from the web server creates a new instance of your CGI application (simulating multiple simultaneous users, each using an instance of your application) thereby allowing for multiple simultaneous access to your database.

Seeing the output

Save your project as Biolife.dpr and compile your application. This should create a DLL by the name of Biolife.dll in the scripts folder of your web server. In your browser, type in the URL

http://mypcname/scripts/biolife.dll (replace mypcname with the IP address or machine name of the machine running the web server). You should see a page like the one shown in Figure 2.

ISAPI3F2.png
Figure 2: Showing the output generated by the QueryTableProducer component.

Notice how the Notes Field has the word (MEMO) in it instead of the actual memo text. Notice also that the Graphic field shows the word (GRAPHIC) instead of the actual graphic. In the remainder of this article, we will attempt to correct this.

Before we get the memo and graphic fields to show, we'll remove some of the unnecessary fields so we see only the fields we want in our browser. This process will also demonstrate to you, how you can re-order the fields in the output if you need to do that using the TxxxTableProducer components that come with Delphi.

Using the TQueryTableProducer

The TQueryTableProducer component has a response editor that can be invoked by double clicking on it or right clicking on it and choosing the "Response editor" pop up menu option. Before you do this, you need to set the TQuery, qryData's Active property to True. The Response Editor should like that that shown in Figure 3 after you've set the Active property of qryData to True and double click on the QueryTableProducer1 component.

ISAPI3F3.png
Figure 3: The QueryTableProducer's Response Editor

You will notice here that you see all the fields of the dataset, since our SQL statement does not explicitly specify fields. You could change the SQL statement such that you see only the fields you are interested in. This will speed up your application as well, but for now we'll see how we can accomplish field ordering and selection using the table producer component's response editor. Before we can start manipulating fields, you need to first add all fields (kind of like instantiating fields of a dataset). To do this, click on the "Add All Fields" tool bar button in the response editor. Once you've done that, you can:

  1. Drag-drop fields to re-order them or use the toolbar buttons with up-down arrows.
  2. Select each field in turn and set its properties listed in the object inspector.

You can also set the table properties (HTML table) using the response editor. Lets delete the fields, Length(cm), Length_in and Common_Name. This should give us some extra space to show the notes field and graphic field in the browser, instead of the words (MEMO) and (GRAPHIC). We'll also set the Border property of the HTML table (in the response editor) to 1. You should see the effect of doing this in the response editor.

Getting the Notes Field to show in the browser

To be able to see the Notes field in the browser we need to write some code in the OnFormatCell event of the QueryTableProducer component. This event is fired automatically before rendering each cell in the HTML table. At this point, you have the ability to change the content of the cell, the background color and the horizontal and vertical alignments of the content of the cell etc.

procedure TWebModule1.QueryTableProducer1FormatCell(Sender: TObject;
  CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
  var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
CellData: String);

You will notice, that there are a number of parameters passed in this event. For the purpose of showing the contents of the Notes field, we need to change the value of the CellData variable to the contents of the memo field. Write the following code in this event. Before writing any code, lets go ahead and create the field objects (instantiate) for the qryData dataset. Instantiating field objects is not required for things to work, but in this case we will. We will create field objects only for the fields we are interested in. Figure 4 shows the field objects that we need to instantiate.

ISAPI3F4.png

Figure 4: Showing the Fields instantiated in qryData's fields editor.

Now in the OnFormatCell event, write the following code:

procedure TWebModule1.QueryTableProducer1FormatCell(Sender: TObject;
CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
CellData: String);
begin
  { Row 0 is the Column Header, so check for CellRow > 0 }
  if (CellRow > 0) and (CellColumn = 4) then
    CellData := qryDataNotes.Value;//Memo Field data
end;

If you recompile your project and refresh your browser, you should see a result similar to that shown in Figure 5.

ISAPI3F5.png
Figure 5: The output in the browser showing the contents of the Memo field.

Notice that the Notes field now shows the contents rather than the word (NOTES). The graphic field still shows the word (GRAPHIC) since we haven't yet done anything to change that.

Showing the Graphics Field in the browser

Getting the browser to show the graphic along with the data is a bit trickier than what we had to do to get the Notes field’s contents to show. Trickier, not harder. Nothing in Delphi is hard.

Lets see what the concept is before we attempt to do this in code. The CellData (in the OnFormatCell event) for the graphics field is being set to (GRAPHIC) by the QueryTableProducer. That's why we see (GRAPHIC) in the browser instead of the graphic itself. If we change the CellData variable for the Graphic column to an HTML <IMG> tag then we should see an image instead. The problem, however is that we need to extract the image from the table and show that image. If we wanted to show an image that resided on the hard drive, we could have simply given the correct URL in the SRC attribute of the <IMG> tag and the browsers would have loaded the required image and shown it.

The concept is similar however. The change is that the image needs to come from the table and not the hard drive. We can write a procedure in our ISAPI to extract the image from the table for the given record. This image then needs to be streamed out to the browser. To get the browser to load the image, we simply give the SRC attribute of the <IMG> tag as an action item in our ISAPI. The action will then have the responsibility of sending back the corresponding image. All this may seem complicated at this point, but it really isn't. We'll work this out step by step to simplify the process.

First we need to change the CellData to an HTML <IMG> tag. Add code such that your OnFormatCell event looks like the following:

procedure TWebModule1.QueryTableProducer1FormatCell(Sender: TObject;
CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
CellData: String);
begin
  { Row 0 is the Column Header, so check for CellRow > 0 }
  if (CellRow > 0) and (CellColumn = 4) then
    CellData := qryDataNotes.Value;//Memo Field data
  { Change the CellData from (GRAPHIC) to an HTML <IMAGE> TAG }
  if (CellRow > 0) and (CellColumn = 5) then
    CellData :=
      Format('<IMG SRC="%s/image?No=%s">',
        [Request.ScriptName,
         qryDataSpeciesNo.AsString]);
end;

The result of the Format procedure and therefore the value of the CellData variable will be something like this:

<IMG SRC="/biolife.dll/image?No=90020">

Notice that there is a reference to a /image action item in our ISAPI. We don't have this action item as yet, but we will create one soon. A parameter that we send in the form of a Name=Value pair, to this action item is No=90020. 90020 being the Species No value for the first record in the biolife table. This will change to correspond with each record's Species No value.

In our /image action item's OnAction event, we can extract this parameter using the Request object's QueryFields property. Using the Species No value, we can zero in on the required record, extract the image from the field and send it back to the browser as a response.

Let's first create a new action item and set the pathinfo property to /image and call it waImage as shown in Figure 6.

ISAPI3F6.png
Figure 6: Showing the Actions Editor with the waImage Action item created.

If you compile your ISAPI and refresh your browser, you should see an output like that shown in Figure 7.

ISAPI3F7.png
Figure 7: Showing the place holders for images in our database.

Notice how the actual image is not shown, since we have yet to do something about that, but the word (GRAPHIC) has now been replaced with what the browser shows for an image it has not been able to find. Since we have yet to write code in the waImage action item's OnAction event, this is expected.

  1. Add the Graphics and JPEG unit to the uses clause of the interface section of the Web data module.
  2. Then drop down another TQuery component on the web data module
  3. Set the Name property to qryImage
  4. Set the DatabaseName property to DBDEMOS.
  5. Set the SQL property to

SELECT Graphic FROM BIOLIFE
WHERE BIOLIFE."Species No" = :SpeciesNo

We'll be streaming the image out as a jpeg image and we'll use another query componet, qryImage to "zero in" on the record with the species no given to us. The code in the OnAction event of the waImage action item should look like this:

procedure TWebModule1.WebModule1waImageAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  JPEG    : TJPEGImage;
  MemStrm : TMemoryStream;
  Bitmap  : TBitmap;
begin
{ In this action event, we "extract" the Species No parameter from the QueryFields
property of the Request object and use that to get the image from the
table.Then we stream out the image as a Jpeg image
}
  try
    JPEG := TJPEGImage.Create;
    MemStrm := TMemoryStream.Create;
    Bitmap := TBitmap.Create;
    try
      with qryImage do
      begin
        { Assign the :SpeciesNo paramter the value received in the Request
          object's QueryFields property. Remember that it comes as eg. No=90020
        }
        Close;
        Params[0].AsInteger := StrToInt(Request.QueryFields.Values['No']);
        Prepare;
        Open;
        { Assign the image from the database to a Bitmap object since the
          field type is a TGraphicField.}
        Bitmap.Assign(FieldByName('GRAPHIC'));
        JPEG.Assign(Bitmap);
        { Save the JPEG image to the memory stream object}
        JPEG.SaveToStream(MemStrm);
        { Set the position to the start }
        MemStrm.Position := 0;
        { The content type needs to be set to image/jpeg. Default is 'text/html' }
        Response.ContentType := 'image/jpeg';
        Response.ContentStream := MemStrm;
        Unprepare;
        Close;
      end;
    finally
      JPEG.Free;
      { We don't need to  free MemStrm since the WebServer will do that }
      Bitmap.Free;
    end; { try - finally }
  except
    on E : Exception do
    begin
      Response.ContentType := 'text/html';
      Response.Content := '<B>ERROR</B><BR>'   #13#10   E.Message;
    end;
  end; { try - except }
end;

What we do in here is extract the Species No from the QueryFields property of the Request object and assign that to the :SpeciesNo parameter of the SQL statement used to "zero in" on the correct record. Next we extract the graphic from this record and assign it to a TBitmap object. The graphic in the table happens to be a bitmap in this case. To convert the bitmap to a jpeg image, we simply assign the Bitmap to the JPEG image. To be able to stream the image we save the JPEG image to a memory stream object.

Before we can actually send back the stream, we need to let the browser know what kind of data to expect. We do this by setting the response object's ContentType to ‘image/jpeg’. Once we've done this, we send the response using the SendResponse method of the Response object.

If you now recompile the ISAPI and refresh the browser you should see an output like that shown in Figure 8.

ISAPI3F8.png
Figure 8: Showing the contents of the Notes field and Graphic field in the browser.

There we have it. The Notes field and the Graphic field shown in the browser along with the other fields. On a slow network, this kind of thing could take a long time to process, since there are a number of images involved. We could change this application to first show hyper linked names of each of the species. When one clicks on these links, one is shown the Notes field and the Graphics field either is a separate browser window or using HTML frames in the same window but in the bottom half. We could also show the notes and graphic fields in another page (so you will need to hit the "BACK" button on your browser to see the list of Species names once again).

All of this is made simple enough with the QueryTableProducer component. Your knowledge of HTML comes into play here, since we now know how to extract the image and memo fields and show it in the browser.

Rather than change this application's behavior, we'll add to it. What we'll do is create additional action items that will produce a different output. What we want to do now is show a page that contains only the Common Name column of the table with hyperlinks. When one clicks on the hyperlink, one should be shown the Notes Field and the Graphic field for the record in question.

1. Drop another TQueryTableProducer component on the form.
2. Set its Query property to qryData.
3. Double click on it to invoke the Response Editor.
4. Add All Fields.
5. Then delete all fields except for the Common_Name field.
6. Select the Common_Name field in the Response Editor.
7. Set its Title's align property to haLeft.

The Response Editor should look like that shown in Figure 9.

ISAPI3F9.png
Figure 9: Showing the Response Editor for our second QueryTableProducer component.

In the Web Data Module, create a new action item.

1. Set its Name property to waNames.
2. Set its PathInfo property to /names.
3. Set its Producer property to QueryTableProducer2.

Your web data module should look like that shown in Figure 10

ISAPI3F10.png
Figure 10: Showing the updated Web Data Module.

What we've done so far is linked a second QueryTableProducer component to our qryData query component. We've made sure that only the Common_Name field is produced in the output. We then created a new action item with the pathinfo of /names. Next we linked the Producer property of this action item to QueryTableProducer2.

If we re-compile our ISAPI and change the URL in our browser to http://myservername/scripts/biolife.dll/names, we should see an HTML page similar to that shown in Figure 11.

ISAPI3F11.png
Figure 11: Showing the Result of the /names action of our ISAPI DLL.

The names are not yet hyper linked. To do this, we generate the OnFormatCell event of QueryTableProducer2 and write the following code in there:

procedure TWebModule1.QueryTableProducer2FormatCell(Sender: TObject;
CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
CellData: String);
begin
  if (CellRow > 0) and (CellColumn = 0) then
    CellData := Format('<A HREF="%s/Details?No=%s">%s</A>',
      [Request.ScriptName,
       qryDataSpeciesNo.AsString,
       qryDataSpeciesName.AsString]);
end;

The result of the Format function will look like this:

<A HREF="/scripts/biolife.dll/Details?No=90020">Clown Triggerfish</A>

We reference an action item with a pathinfo of /details that expects to see a parameter called No. We don’t have an action item with a PathInfo of /details yet. But we will soon.

If you re-compile the ISAPI and refresh the browser, you should see an output similar to that shown in Figure 12.

ISAPI3F12.png
Figure 12: Showing the Names hyper-linked in the browser.

If you move your mouse over each of these hyperlinks, you should see in the status bar of the browser (as shown in Figure 12 above) that each species has its associated species no.

If you click on any of the hyperlinks now, you'll get an error since we have not created an action item with a pathinfo of /details. So lets go ahead and create it now.

Create a new action item.

1. Set its PathInfo property to /details.
2. Set its Name property to waDetails.

Your Actions Editor should look like that shown in Figure 13.

ISAPI3F13.png
Figure 13: Showing the Action Editor with the new action items 

To keep things simple, we'll drop another TQuery component on the web data module

  1. Set its Name property to qryNotes.
  2. Set its DatabaseName property to DBDEMOS.
  3. Set its SQL property to:

SELECT Notes FROM BIOLIFE
WHERE BIOLIFE."Species No" = :SpeciesNo

We'll use this query component to zero in on the required record and get the value of the Notes field to be displayed in the browser.

In the OnAction event of the waDetails action item, write the following code:

procedure TWebModule1.WebModule1waDetailsAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
{ Manually create an HTML table with two columns. Populate the first
one with the contents of the Notes field. The second column will contain
the graphic from the table. Here we'll only put an HTML <IMG> tag
with the correct URL to extract the required image from the table using
the species no parameter sent to us here in the QueryFields property
of the Request object
}
  Response.Content := '<H3>Notes</H3><BR>'   #13#10  
  '<TABLE>'   #13#10  
  ' <TR>'   #13#10  
  ' <TD>';
  { Zero in on the correct record in the table }
  with qryNotes do
  begin
    { Assign the :SpeciesNo paramter the value received in the Request
      object's QueryFields property. Remember that it comes as eg. No=90020
    }
    Close;
    Params[0].AsInteger := StrToInt(Request.QueryFields.Values['No']);
    Prepare;
    Open;
  end;
  Response.Content := Response.Content  
    { Put the value of the Notes field in the First cell }
    qryNotes.FieldByName('Notes').AsString   '</TD>'   #13#10  
    { Put an <IMG> tag in the second cell and set its SRC parameter's value
     to the waImage action item, sending it the species no received in the
     Request object's QueryFields property.
    }
    ' <TD><IMAGE SRC="'   Request.ScriptName   '/image?No='  
    Request.QueryFields.Values['No']   '"></TD>'   #13#10  
    ' </TR>'   #13#10  
    '</TABLE>';
end;

You will find the explanation of the code in the comments above. I'll explain the part with the <IMAGE> HTML tag some more. Just like we did the first time, all we're doing is setting the SRC parameter of the <IMAGE> tag to our waImage action item (pathInfo of /image). This action item can extract the graphic and stream it out to the browser given the species no of the record for which we require an image.

If you re-compile the ISAPI and refresh your browser and then click on a hyperlink, you should see an as showin in Figure 14:

ISAPI3F14.png
Figure 14: Showing the notes and Graphic field

I have noticed that if an ISAPI/CGI is attempting to send a number of images in this fashion, things tend to get a bit funny. If you play with this application a bit, you may see that at times the browser won't show the right image for the Common Name that you clicked on, or that you won't see an image at all, or you may even get access violation errors.

To get around this problem, the solution I found was to use Response.SendStream(MemStrm) instead of the earlier, Response.ContentStream := MemStrm;.

I suggest you make this change to the code in the OnAction event of the waImage action item.

This brings us to the end of this project. We've learned how to use the TQueryTableProducer component. How to use the OnFormatCell event to change the resulting output. Then we learned how we can extract an image from a database table and stream it out to the browser. As an excersize for the reader, I suggest trying to showing the Notes and Graphic in the same page in the bottom half of the browser using HTML Frames.

Your output should look like that shown in Figure 15:

ISAPI3F15.png
Figure 15: Showing the output using HTML Frames

You don't really have to make too much of a change to the existing project if you don't want to. However, you will need to create an HTML file with the following HTML in it. Note however, that you could change the project to generate this HTML file in question. The HTML should look like this:

<!-- frames -->
<frameset rows="50%,50%" border="0">
<frame name="Data" src="http://YourPCName/scripts/biolife.dll/names" marginwidth="10" marginheight="5" scrolling="auto" frameborder="no">
<frame name="Detail" src="" marginwidth="10" marginheight="10" scrolling="auto" frameborder="no"> 
</frameset>

In the project, change the format string in the OnFormatCell event of TQueryTableProducer2 from

<A HREF="%s/Details?No=%s">%s</A>'

to

<A HREF="%s/Details?No=%s" TARGET="Detail">%s</A>'

This will instruct the browser to show the Notes field and Graphic field in the frame called "Detail". Which is the frame at the bottom half of the HTML file you created. Note that the Name of the frame is case sensitive.

Creating Image Thumbnails

Generally, due to speed considerations, we’d like to be able to create thumbnail images of the images we’re sending to the browser, giving the user the option of seeing the image in actual size if s/he so desires.

Delphi makes it really simple to create thumbnail images on the fly. The procedure listed below does exactly that.

procedure TWebModule1.ReduceBitmap(var smBitmap : TBitmap; orgBitmap : TBitmap;
  Reduction : Integer = 1);
var
  Rect : TRect;
begin
  smBitmap.Width := orgBitmap.Width div Reduction;
  smBitmap.Height := orgBitmap.Height div Reduction;
  Rect.Top := 0;
  Rect.Left := 0;
  Rect.Right := smBitmap.Width;
  Rect.Bottom := smBitmap.Height;
  smBitmap.Canvas.StretchDraw(Rect,orgBitmap);
end;

Two bitmap objects are sent to this procedure. smBitmap is the bitmap that contains the reduced bitmap while orgBitmap is the bitmap that contain the bitmap to be reduced. Reduction is the factor by which to reduce the bitmap.

To implement thumbnails in our project we’ll have to make a few following changes. Note however that we’ll implement thumbnail images only for the waData action item. This is out default action item. We’d also like to be able to click on the images seen in output created by this action to see the image in its normal size.

First let us make the changes required in the waImage action item’s OnAction event. The following is the code listing of this event:

procedure TWebModule1.WebModule1waImageAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  JPEG    : TJPEGImage;
  MemStrm : TMemoryStream;
  Bitmap  : TBitmap;
  smBitmap: TBitmap;
begin

{ In this action event, we "extract" the Species No parameter from the QueryFields
property of the Request object and use that to get the image from the
table.Then we stream out the image as a Jpeg image
} try
    JPEG := TJPEGImage.Create;
    MemStrm := TMemoryStream.Create;
    Bitmap := TBitmap.Create;
    smBitmap := TBitmap.Create;
    try
      with qryImage do
      begin
        { Assign the :SpeciesNo paramter the value received in the Request
          object's QueryFields property. Remember that it comes as eg. No=90020
        }
        Close;
        Params[0].AsInteger := StrToInt(Request.QueryFields.Values['No']);
        Prepare;
        Open;
        { Assign the image from the database to a Bitmap object since the
        field type is a TGraphicField.}
        Bitmap.Assign(FieldByName('GRAPHIC'));
        ReduceBitmap(smBitmap, Bitmap,StrToIntDef(Request.QueryFields.Values['Size'],1));
        JPEG.Assign(smBitmap);
        { Save the JPEG image to the memory stream object}
        JPEG.SaveToStream(MemStrm);
        { Set the position to the start }
        MemStrm.Position := 0;
        { The content type needs to be set to image/jpeg. Default is 'text/html' }
        Response.ContentType := 'image/jpeg';
        Response.CotentStream := MemStrm;
        Unprepare;
        Close;
      end;
    finally
      JPEG.Free;
      { We don't need to free MemStrm since the WebServer will do that }
      Bitmap.Free;
      smBitmap.Free;
    end;
  except
    on E : Exception do
    begin
      Response.ContentType := 'text/html';
      Response.Content := '<b>ERROR</b><br>'   #13#10   E.Message;
    end;
  end;
end;

The lines of code that have either been added or changed are marked in bold-italic. Notice that the line

ReduceBitmap(smBitmap,Bitmap,StrToIntDef(Request.QueryFields.Values['Size'],1));

Is expecting to see a parameter called "Size" in the QueryFields property of the Request object. There is no problem if this parameter doe not exist. But if we want the images to be reduced then we need to specify this parameter. To do that we need to modify the QueryTableProducer1’s OnFormatCell event as shown below:

procedure TWebModule1.QueryTableProducer1FormatCell(Sender: TObject;
  CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
  var Align: THTMLAlign; var VAlign: THTMLVAlign; var CustomAttrs,
  CellData: String);
begin
{ Row 0 is the Column Header, so check for CellRow > 0 }
  if (CellRow > 0) and (CellColumn = 4) then
    CellData := qryDataNotes.Value;//Memo Field data
{ Change the CellData from (GRAPHIC) to an HTML <IMG> TAG }
if (CellRow > 0) and (CellColumn = 5) then
    CellData :=
      Format('<A HREF="%s/image?No=%s&Size=1"><IMG SRC="%s/image?No=%s&Size=2" BORDER="0"></A>',
       [Request.ScriptName,
        qryDataSpeciesNo.AsString,
        Request.ScriptName,
        qryDataSpeciesNo.AsString]);
end;

Once again, the lines of code that have been modified or added are marked in bold-italic. The result of the Format function above will look like this:

<A HREF="/scripts/biolife.dll/image?No=90020&Size=1"><IMG SRC="/scripts/biolife.dll/image?No=90020&Size=2" BORDER="0"></A>

This is standard HTML but you will notice that the URL for the image source specifies the size parameter of 2 (half size), while the link’s HREF parameter’s URL specifies the size to be 1 (full size.

Make sure you add the

ReduceBitmap
procedure to your project and then recompile your project. Change the URL in your browser such that it invokes the default action of our ISAPI. The resulting page of the default action should now look similar to that shown in Figure 16:

ISAPI3F16.png
Figure 16: Showing the final result of the ISAPI application we've built thus far.

Notice that the images are now half the size. We have effectively reduced the response time of this page by half. Also, you should notice that each image is hyper linked (the BORDER=0 parameter of the IMG tag has been used to remove the border). Clicking on any of the images will show you a page containing the full sized version of that image as shown in Figure 17.

ISAPI3F17.png
Figure 17: Showing the full size image after clicking on the thumbnail version

Creating thumbnails in this fashion comes extremely handy since one doesn’t need to maintain two or more versions of each image being used in ones web applications. In cases where the images being used reside on the hard disk as jpeg files, Delphi’s TJPEGImage class makes it a breeze to create thumbnails. Simply setting the scale property does the trick. Well, almost. Also keep in mind that one can create grayscale versions of the images if required by setting the grayscale property (both the TBimap and TJPEGImage class have this property) to True.

Comments have been Disabled for this post





Menus

Theme

Privacy Policy  |  Terms Of Service  |  Contact Us  |  Support  |  Help/FAQs  |  News