Lazarus, MS Access y uso de imagenes (Bitmap)

MS Access guarda las imagenes en campos de tipo objeto OLE. La informacion que guarda es el stream del archivo .bmp con una cabecera que contiene la aplicacion con la que tiene que abrir el stream. El stream entero es inservible para trabajar directamente con freepascal/Lazarus asi que lo que viene a continuacion es una manera de usar ese objeto OLE para incrustarlo en un Dbf y poder trabajar mas agilmente en Lazarus.

A continuacion vamos a mostrar distintos contenidos de streams para entender que vamos haciendo.

Archivo BMP :

streambmp

Como se puede ver “BM” marca el inicio del stream.

Archivo BMP incrustado en un campo de tipo objeto OLE de MS Access :

streammdb

Aqui se puede observar la cabecera que comentabamos antes.

Archivo BMP incrutado en un campo de tipo BLOB en un Dbf :

streamdbf

Observamos que la cabecera se reduce en comparacion al objeto OLE.

Para conseguir nuestro objetivo lo primero que tenemos que hacer es determinar la posicion del “BM” para poder extraer la informacion que nos interesa, para este fin usamos la siguiente funcion:


function buscaPosicionBM(STmp : TStream) : Integer;
var
  i : Integer;
begin
  STmp.Seek(0,0);
  for i:=0 to 100 do
    begin
      if STmp.ReadByte = 66 then
        if STmp.ReadByte = 77 then
          buscaPosicionBM:=STmp.Position-2;
    end;
end;

Y a continuacion toda la chicha, o sea, cargamos el objeto OLE en un stream, le quitamos la informacion innecesaria para nosotros y lo metemos en un campo blob de un Dbf.

procedure carga;
var
  Stream, StreamClean : TStream;
  FieldStr : String;
  PFieldStr : PChar;
  posicion : Integer;
begin
  // Cargamos el objeto OLE al Stream
  Stream := TMemoryStream.Create;
  Stream := q.CreateBlobStream(q.FieldByName('DIBUJO'), bmRead);

  // Conseguimos la posicion del "BM"
  posicion :=buscaPosicionBM(Stream);

  // Creamos el stream para añadir despues al Dbf
  StreamClean := TMemoryStream.Create;

  // Añadimos la cabecera para el Dbf
  StreamClean.WriteByte(3);
  StreamClean.WriteByte(0);
  StreamClean.WriteByte(0);
  StreamClean.WriteByte(0);
  StreamClean.WriteByte(98);
  StreamClean.WriteByte(109);
  StreamClean.WriteByte(112);

  // Nos posicionamos correctamente y copiamos la informacion necesaria
  Stream.Seek(posicion, soFromBeginning);
  StreamClean.Position:=7;
  StreamClean.CopyFrom(Stream,Stream.Size - posicion);
  StreamClean.Seek(0,0);
  SetLength(FieldStr, StreamClean.Size);
  PFieldStr := PChar(FieldStr);
  StreamClean.Read(PFieldStr^, StreamClean.Size);

  // Volcamos el Stream creado al Dbf
  reportDbf.Append;
  reportDbf.FieldByName('Codigo').Assign(q.FieldByName('Codigo'));
  reportDbf.FieldByName('descripcion').Assign(q.FieldByName('descripcion'));
  reportDbf.FieldByName('dibujo').Value := FieldStr;
  reportDbf.Post;

  // Liberamos recursos
  Stream.Free;
  archivoLog.Free;
end;

Comentar que q es un TSQLQuery de SQLdb, reportDbf es un TDbf y he usado el programa Hexplorer para ver los entresijos de los streams.

Si algo no ha quedado muy claro me dejais un comentario e intentare explicarme lo mejor que pueda O:)

Share on Twitter