Free Web Hosting by Netfirms
Web Hosting by Netfirms | Free Domain Names by Netfirms

Mostrar imágenes almacenadas en una tabla a través de una página WEB

 

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' then
    begin
      p.Assign(IBQuery1FOTO);  //Esto solo funciona con BMP...
      j.Assign(p.Graphic); //Lo convierte a JPEG
    end 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