|
|
|
En este ejemplo veremos como mostrar una imagen en una página Web, creando la página en forma dinámica con una aplicación ISAPI. Usaremos una tabla de Interbase, los componentes IBX, y permitiremos que se almacenen imágenes con distintos formatos: BMP, JPG y GIF[1].
La tabla que usaremos es muy simple:
CREATE
TABLE PERSONAS (
ID_PERSONA INTEGER NOT NULL,
NOMBRE VARCHAR(30) NOT NULL,
FOTO BLOB SUB_TYPE 0 SEGMENT SIZE 80,
FORMATO_FOTO VARCHAR(3),
CONSTRAINT PERSONAS_PK PRIMARY KEY
(ID_PERSONA)
);
Y la página Web es más simple todavía. En la imagen siguiente se ve mostrando uno de los registros:

La página mostrada consta de un formulario (ya que en algún momento extenderemos la aplicación para que deje modificar los datos desde la página directamente) con controles para ver los datos, incluida la imagen. Hay dos botones en la parte inferior, que permiten la navegación a través de los registros.
El código HTML de la página es el siguiente:
<html>
<head>
<title>Prueba de navegacion con
fotos</title>
<meta
http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
</head>
<body
bgcolor="#FFFFFF">
<form
name="form1" method="post" action="pruFotoDLL.dll?ID=<#ID>">
<p>ID:
<input type="text"
name="edID" value="<#ID>">
</p>
<p>Nombre:
<input type="text"
name="edNombre" value="<#Nombre>">
</p>
<p>Foto: <img
src="pruFotoDLL.DLL/foto?ID=<#ID>"
align="top"></p>
<p>
<input type="submit"
name="bAnterior" value="Anterior">
<input type="submit"
name="bSiguiente" value="Siguiente">
</p>
</form>
</body>
</html>
Hay un par de Tags de control, que serán reemplazados por nuestra aplicación ISAPI al procesar la página:
· #ID: se reemplazará con el contenido del campo ID_Persona
· #Nombre: se reemplazará con el contenido del campo Nombre
Como se estarán imaginando, estos tags se pueden trabajar en una sola acción de la aplicación; será la acción predeterminada. Pero veamos primero el WebModule de la aplicación, y su lista de acciones:


Tenemos dos acciones: una se encargará de devolver únicamente la imagen, y se accede con el path ‘/foto’. La otra es la acción predeterminada, que devolverá la página en sí con los tags reemplazados. Comencemos por ver la acción predeterminada:
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);begin
IBQuery1.Locate('ID_PERSONA',Request.QueryFields.Values['ID'],[]); if Request.ContentFields.Values['bAnterior']<>'' then IBQuery1.Prior; if Request.ContentFields.Values['bSiguiente']<>'' then IBQuery1.Next; Response.Content:= PageProducer1.Content;end;
Como podemos notar, es muy sencillo; he optado por hacerlo de esta manera porque el objetivo del ejemplo es ver cómo se pueden mostrar imágenes, no optimizar el acceso. En particular me causa escozor usar Locate en lugar de armar una condición WHERE en el query... pero atengámonos al programa.
Comienza la acción buscando el registro que se estaba viendo al momento de enviar la página; lo ubicamos por el valor del campo ID, que se envía como parámetro en la línea de comandos y por lo tanto nos llega a la aplicación en Request.QueryFields. A continuación sólo tenemos que avanzar o retroceder según el botón que se haya presionado, y generar la página llamando a PageProducer1.Content.
El proceso de los tags en PageProducer1 es directo:
procedure TWebModule1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
const TagString: String; TagParams: TStrings; var ReplaceText: String);begin
if TagString='ID' then ReplaceText:= IBQuery1ID_PERSONA.AsString else if TagString='Nombre' then ReplaceText:= IBQuery1NOMRBE.AsString;end;
La diversión empieza con el Tag de imagen. Veámoslo en detalle.
<img
src="pruFotoDLL.DLL/foto?ID=<#ID>" align="top">
¿De dónde sale la imagen? La propiedad ‘src’ (source) nos direcciona nuevamente a la DLL de nuestra aplicación, esta vez con un path determinado: ‘/foto’. El parámetro ID es el mismo que vimos más arriba.
Al llegar esta petición a la aplicación, se ejecuta la acción WebActionItem2:
procedure TWebModule1.WebModule1WebActionItem2Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);var
m: TStream; p: tPicture; j: TjpegImage; g: TGIFImage;begin
try IBQuery1.Locate('ID_PERSONA',Request.QueryFields.Values['ID'],[]); p:= TPicture.Create; j:= Tjpegimage.Create; g:= TGIFImage.Create; if IBQuery1FORMATO_FOTO.AsString='BMP' thenbegin
p.Assign(IBQuery1FOTO); //Esto solo funciona con BMP... j.Assign(p.Graphic); //Lo convierte a JPEGend else
begin m:= IBQuery1.CreateBlobStream(IBQuery1FOTO,bmRead); if IBQuery1FORMATO_FOTO.AsString='JPG' then j.LoadFromStream(m)else
g.LoadFromStream(m); m.Free; end; m:= TMemoryStream.Create; if IBQuery1FORMATO_FOTO.AsString='GIF' then begin g.SaveToStream(m); Response.ContentType:= 'image/gif';end else begin //Cualquiera de los otros dos casos, la imagen est en j y es JPEG
j.savetostream(m);
Response.ContentType:= 'image/jpeg'; end; m.Position:= 0; Response.ContentStream:= m; Response.SendResponse; except on e:Exception do Response.Content:= '<html><body>ERROR!<br>'+e.message+'<br></body></html>'; end; p.Free;// m.Free;
j.Free; g.Free; Handled:= True;end;
Bueno, esto ya es un poco más largo y parece más difícil. Veamos.
· Recordemos que la tarea de esta acción es devolver una imagen y nada más. No hay proceso de tags o cosas por el estilo. De aquí que la respuesta tenga un tipo ‘image’, dado en la propiedad Response.ContentType.
· Lo primero es lo primero: debemos localizar el registro donde está la imagen. Usamos un Locate, nuevamente.
· A continuación creamos una instancia de cada uno de los componentes que contendrán las imágenes: Tpicture para BMP, TjpegImage para JPG, y TGIFImage para GIF.
· Según el formato de la imagen, cargamos la misma en el componente adecuado: tanto las de formato BMP como JPG van a parar al objeto JPEGImage, mientras que las de formato GIF se almacenan temporalmente en el GIFImage.
· A continuación generamos la respuesta. Como dijimos más arriba, el tipo de contenido es distinto si se trata sólo de una imagen; es más, difiere también si es JPEG o GIF (recordemos que si la imagen es BMP se transforma en JPG). Procesamos pues las dos opciones que nos quedan, y
· Finalmente escribimos la respuesta usando el método ContentStream y lo enviamos con SendResponse.
· Si hay un error, generamos una página muy simple mostrando el mensaje
Notemos la línea comentada al final (m.free). Según parece, la aplicación se encarga de liberar el stream que utiliza para la respuesta de forma automática. Suena lógico, ya que el envío se realiza en forma asincrónica –es decir, la aplicación sigue su curso mientras por otro lado se envía la imagen. Y entonces, cómo sabríamos en qué momento se terminó el envío?
Y esto es todo por hoy.
[1] Necesitará para esto el componente TGIFImage, que se puede obtener gratis de Internet en www.jedi.org