Você está na página 1de 8

Salvando e recuperando tipos Blob's com BDE e IBX(IB/Firebird)

Salvando e recuperando tipos Blob's com BDE e IBX(IB/Firebir Delphi 5.x Delphi 6.x Delphi 7.x

Interbase/Firebird Categoria: Interbase/Firebird Nvel de Habilidade: Classificao: Insero: 19/08/2003 Nmero de Votos : 9 Referncia: Gladiston Santana

Palavras Principais: Salvando e recuperando tipos Blob's com BDE e IBX(IB/Firebird) Usurio: Ramos de Souza Janones Questo/Problema: Salvando e recuperando tipos Blob's com BDE e IBX(IB/Firebird) Resposta:

Neste artigo, abordaremos um pouquinho sobre campos do tipo BLOB (Binary Large OBject). Tentarei ser genrico, pois campos do tipo BLOB existem em praticamente todos os banco de dados. Entregarei alguns exemplos de como salvar/recuperar campos do tipo BLOB usando dois mtodos bastante conhecidos pelos programadores familiarizados com o Delphi : BDE, que apesar de ter sido descontinuado pela Borland ainda largamente utilizado para acessar Sybase, Oracle, MSSQL, Paradox, e outros. IBX, com exclusividade para o banco de dados Interbase/Firebird. Entendendo o Problema Por incrvel que possa parecer, o tipo BLOB bastante recente. Ele no existia a alguns anos atrs., onde numa estrutura de dados contvamos apenas com tipos tais como : data, caractere, numrico e lgico. Desde ento, a demanda por banco de dados ficou maior, e as necessidades tambm mudaram. Lembro-me de que uma das mais elogiadas capacidades do Dbase era o uso do campo MEMO, usando este tipo de dado, podamos guardar textos at 32KB, ual !!!! Isso era fantastico para a poca. Talvez seja indispensvel dizer que atualmente 32KB to curto que uma simples mensagem em HTML pode atingir esse tamanho. Bem, voc deve estar se perguntando : onde quero chegar ? Logo aps o Dbase, graas ao revolucionrio Sistema Operacional da Microsoft : o Windows 3.1, alguns tipos de arquivos comearam a ganhar contedo multimdia. Os Banco de dados ganharam a tarefa de poder guardar em sua base, todos os tipos multimdia existentes. Vrias tipos de dados comearam a florescer : "Image" (imagem) ,"Formated Memo" (texto RTF), smallint (inteiro curto), CURRENCY (moeda) e muitos outros. Mas tinha um problema, cada software tinha os seus tipos especficos, muitos banco de dados suportavam imagens no formato Bitmap, outros no formato PCX. Assim tnhamos que nos preocupar com o banco de dados e quais os formatos que ele suportava. Alem disso, no auge do ambiente visual, ficavam surgindo formatos multimdia a todo instante. E os principais fabricantes de banco de dados no tinham a mesma velocidade para implementa-los em seu software. Quando achou-se que um campo do tipo "Memo" j era suficiente, surgia a necessidade de guardar "Memos Formatados" (Formated Memo), textos do tipo Rich Text (.rtf) para guardar textos com formatao para apresentao no windows. Quando achou-se que Bitmap era o padro adequado para se guardar uma imagem, um formato de imagem novo e mais econmico surgiu : JPeG (.jpg), e assim por diante. Quando Surgiu a necessidade de guardar documentos do office no banco de dados, ento foi criado o campo do tipo "Ol". Percebeu onde quero chegar ? O problema constante da poca que a indstria de software no parava de promover novos formatos de mdia de dados. Eis que chega a soluo para o problema.... Para solucionar este problema, uma empresa de nome Borland criou uma soluo que depois foi seguida pela maioria dos principais fabricantes de banco de dados.

Criou-se o tipo "BLOB" (Binary Large OBject), esse tipo seria apenas um recipiente para campos de origem diversas, podendo ser at mesmo objetos definidos pelo prprio usurio. Num BLOB pode-se guardar imagem, som, textos longos, textos longos formatados, ou qualquer coisa que vinhesse a aparecer no futuro. Alm disso, se um registro contivesse uma imagem, o prximo registro poderia conter um trecho musical e assim por diante. Um campo BLOB no est vinculado a nenhum tipo de dado em especifico, ele multi-formato e varivel. De fato, o campo BLOB tornou-se ento padro industrial, no entanto, dependendo da linguagem de programao utilizada, a gravao e recuperao desses tipos de dados podem mudar. A seguir demonstrarei de modo prtico como gravar e recuperar campos BLOBs usando o prprio Delphi. Aplicando a soluo 'blob' com o Delphi com qualquer banco de dados via BDE. Para manipular campos do tipo BLOB em Delphi, muito "fcil". Coloquei o "fcil" entre aspas, porque preciso saber que a manipulao de BLOBs indifere se iremos trabalhar com textos, imagens, sons ou qualquer outra coisa. Usando o BDE juntamente com o TDatabase, os mtodo para gravao e recuperao de um blob ser sempre o mesmo. No exemplo a seguir, vou demonstrar como guardar um Documento do Word (na verdade pode ser qualquer documento ou arquivo) num campo do tipo BLOB : var m : TQuery; begin m:=TQuery.Create(self); m.DatabaseName:='Um\databasename\qualquer'; m.sql.add('UPDATE TABELA_TAL'); m.sql.add('SET campo_blob=:_nomearq'); m.sql.add('WHERE campo_chave =1'); try m.ParamByName('_nomearq').LoadFromFile('C:\TEMP\TESTE.DOC',ftBlob); m.ExecSQL; except on e:exception do begin ShowMessage(e.message); end; end; end;

Como pode ver no exemplo acima, salvar um documento qualquer dentro dum BLOB fcil. O mais dificil de se trabalhar com um BLOB recupera-los. Por que ? Por uma razo bem simpes : objetos BLOB no tem tamanho definido e teoricamente pode ter tamanho ilimitado. Isso bastante interessante, no entanto, a memria de nosso computador no ilimitado. Por exemplo : se mandarmos nosso programa ler um Objeto BLOB de 80MB, e no tivermos 80MB de RAM livre em nosso computador para executa-lo, um erro "inesperado" ir ocorrer. Para contornar este problema temos um objeto do Windows chamado TStream, que permite ler objetos binrios (como os campos BLOB) sob-demanda, ou seja, um pedao de cada vez. E para facilitar ainda mais, a borland resolveu criar um objeto BlobStream (parecido com o TStream) s para tratar especificamente os campos BLOBs associados uma Querie. Alm disso, no Delphi temos variaes do TStream : TFileStream, TMemoryStream e outros. Assim que descubrimos como trabalhar BLOBs usando TStream's no mais precisaremos nos preocupar se havemos ou no de usar um componente especfico para manipular um tipo BLOB em especial, deveras, o TStream capaz de tratar qualquer tipo BLOB's independente de plataforma, sistema operacional ou banco de dados. No exemplo a seguir, vou recuperar o documento do exemplo anterior e salva-lo novamente no disco. Para simplificar a operao vou usar o BlobStream para recuperar o campo BLOB e transferi-lo para o disco (nesse caso o TfileStream) :

var BlobStream : TBlobStream; FileStream : TFileStream; m : Tquery; begin

m:=TQuery.Create(self); m.DatabaseName:='Um\databasename\qualquer'; m.sql.add('SELECT campo_chave, campo_blob'); m.sql.add('FROM TABELA_TAL'); m.sql.add('WHERE campo_chave =1'); // Salvando o arquivo em disco try m.Open; BlobStream := TBlobStream.Create(m.Fieldbyname('campo_blob') as TBlobField, bmRead); FileStream := TFileStream.Create('C:\TEMP\MEU_DOC.DOC', fmCreate or fmOpenWrite); FileStream.CopyFrom(BlobStream, 0); ShowMessage('Documento salvo em disco. Clique em [OK] para prosseguir ...'); finally // Liberando memoria FileStream.Free; BlobStream.Free; m.Free; end; end;

Aplicando a soluo 'blob' com o Delphi acessando o Interbase/Firebird via IBX (Interbase Express) No Interbase/Firebird tipos BLOBs tem uma espcie de qualificao, onde um blob pode ter um contedo binrio,texto-puro ou BLR, na realidade at existem outros tipos de BLOBs, mas que no abordarei neste artigo, mas se voce quiser saber mais sobre esses tipos diferentes de BLOBs no Interbase/Firebird veja o seguinte link : http://www.firebase.com.br/cgi-bin/firebase.cgi/artigo?ID=138 O que iremos abordar aqui ser como recuperar um objeto do tipo BLOB que conter uma fotografia usando apenas comandos da prpria linguagem sem necessidade de objetos visuais ou datawares. Os componentes dataware simplificam a nossa vida claro, mas vez ou outra talvez voce precise recuperar um contedo BLOB para qual ainda no existe um componente especifico para trata-lo diretamente da sua base de dados. o caso por exemplo do TDBImage que s sabe trabalhar com TFields. O segredo do nosso artigo continuar a usar os TStream's. Conforme falado antes, os TStreams so tipos de variveis que podem manipular de modo adequado grandes objetos, muitas vezes de tamanho indeterminado. So muitas as circunstncias em que podemos usar variveis do tipo TStream, em geral, para manipular objetos do tipo BLOB sem a necessidade de ficar necessitando de componentes dataware. Vou usar no exemplo a seguir uma variao do TStream, chamada de TMemoryStream. Eu at poderia utilizar o TStream diretamente, porm como o exemplo a seguir demonstra como jogar uma fotografia diretamente para o banco de dados, o tipo TMemoryStream possui uma vantagem de nunca fazer swap em disco. um tipo de varivel que usa Bufferizao como o TStream, porm faz isso sem necessitar de ficar fazendo swap em disco e como consequencia melhorando a perfomance do aplicativo. Alm disso, trabalhar com objetos na memria vantajoso tambm por questes de segurana, imagine que seu objeto BLOB seja sigiloso, caso voce venha a fazer swap em disco (TStream), um efeito colateral do windows gerar arquivos temporrios com o arquivo inteiro ou parte dele, muitas vezes esses arquivos no so apagados da forma adequada, possibilitando que outros (ou voce mesmo) possa bisbilhotar o que foi manipulado. Nota : O Exemplo a seguir funciona carregando Imagens do tipo Bitmap, no qual todas as verses de delphi so comptiveis usando TImage, no caso de voce preferir utilizar Jpeg's, TIFF ou outros formatos ento ao inves de usar 'Image1.Picture.Bitmap.LoadFromStream' prefira 'Image1.Picure.LoadFromFile' retirando a propriedade Bitmap, pois com a propriedade Bitmap somente possivel trabalhar com bitmap's. Porm ainda no final deste artigo ser explicado como usar Jpeg's com LoadFromStream. Gravando uma fotografia num campo do tipo BLOB : var m:TIBQuery; b:TMemoryStream; begin m:=TIBQuery.Create(Self); m.Database:=MyIBXDatabase; m.Transaction:=MyIBXDatabase.DefaultTransaction; m.sql.clear; m.sql.add('UPDATE TABELA_USUARIOS'); m.sql.add('SET nome=:_nome,'); m.sql.add(' cargo=:_cargo,'); m.sql.add(' bitmap_foto=:_bitmap_foto,'); m.sql.add(' last_update=CURRENT_DATE,');

m.sql.add(' last_owner=CURRENT_USER'); m.sql.add('WHERE id_usuario=1'); try m.parambyName('_nome').AsString:='Maria Jose'; m.parambyName('_cargo').AsString:='Estagiria'; // gravando a fotografia que se encontra num TImage comum // e transferindo-o diretamente para a tabela e sem nenhum // swap em disco b:=TMemoryStream.Create; Image1.Picture.Graphic.SaveToStream(b); // Image1 um TImage qualquer m.ParamByName('_bitmap_foto').LoadFromStream(b,ftBlob); m.ExecSQL; Application.MessageBox('Dados do usuario atualizados com sucesso !','Sucesso :'); except on e:exception do begin Application.MessageBox(Pchar(e.message),'Erro ao atualizar dados :'); b.Destroy; m.Free; Exit; end; end; b.Destroy; m.Free; end;

O cdigo acima transfere uma fotografia carregado num TImage para o campo do tipo BLOB sem a necessidade de nenhum swap em disco e exatamente por isso, ser uma gravao mais rpida. Alm disso, o codigo acima totalmente portvel para outras ocasies, por exemplo, imagine que voce queira transferir um arquivo que j se encontra no disco para o banco de dados, ento no exemplo acima, bastaria retirar toda a referencia de TMemoryStream e fazer um simples .LoadFromFile :

var m:TIBQuery; begin m:=TIBQuery.Create(Self); m.Database:=MyIBXDatabase; m.Transaction:=MyIBXDatabase.DefaultTransaction; m.sql.clear; m.sql.add('UPDATE TABELA_USUARIOS'); m.sql.add('SET nome=:_nome,'); m.sql.add(' cargo=:_cargo,'); m.sql.add(' bitmap_foto=:_bitmap_foto,'); m.sql.add(' last_update=CURRENT_DATE,'); m.sql.add(' last_owner=CURRENT_USER'); m.sql.add('WHERE id_usuario=1'); try m.parambyName('_nome').AsString:='Maria Jose'; m.parambyName('_cargo').AsString:='Estagiria'; // gravando a fotografia que se encontra num arquivo em disco // diretamente para o banco de dados m.ParamByName('_bitmap_foto').LoadFromFile('c:\local\do\arquivo.bmp',ftBlob); m.ExecSQL; Application.MessageBox('Dados do usuario atualizados com sucesso !','Sucesso :'); except on e:exception do begin Application.MessageBox(Pchar(e.message),'Erro ao atualizar dados :'); m.Free; Exit; end; end; m.Free; end; Percebeu como fcil realizar adaptaes ? Vamos ver agora como recupera-las ? Recuperando uma imagem num campo do tipo BLOB :

Para recuperar um contedo BLOB usando o IBX praticamente o mesmo processo de gravao, porm inverso: transferimos o contedo blob para uma varivel de memria (TStream) e manipulamos o objeto conforme o necessrio. O exemplo a seguir, vou recuperar uma fotografia dum campo BLOB e deposita-lo num TImage, todos talvez achem que seria mais fcil usar um TDBImage, porm note que o exemplo que irei passar poder funcionar com outros tipos de campos BLOBs e no somente imagens. O componente dataware TDBImage apenas trabalha com imagens no formato bitmap e quanto aos outros formatos (jpeg, tiff, gif, avi.) ? O componente TAnimate permite trabalhar com o formato .AVI, porm no existe nenhum TDBAnimate para recuperar um BLOB com este formato. nesse tipo de situao que trabalhamos com o tipo TStream que permite recuperar um objeto blob e transferi-lo para s mesmo e num momento mais adequado transferi-lo para um recipiente mais adequado ao formato, ou se no houver transferi-lo para disco para que possa ser manipulado por um outro aplicativo. Este recipiente para o qual o TStream poder transferir o objeto pode ser qualquer componente visual quer possua as propriedades : '.SaveToStream' ou '.LoadFromStream', que so praticamente todos os componentes multimdia. Por isso que estou insistindo em usar o modelo mais genrico com TStream, para que voc possa ampliar seus horizontes. O exemplo a seguir trabalha a possibilidade de recurar um Blob do tipo Bitmap usando LoadFromStream e sem nenhum swap em disco :

var m:TIbQuery; b:TStream; begin // Primeiramente vamos apagar a imagem contida no recipiente TImage Image1.Picture.Bitmap:=nil; m:=TIBQuery.Create(Self); m.Database:=MyIBXDatabase; m.Transaction:=MyIBXDatabase.DefaultTransaction; m.sql.clear; m.sql.add('SELECT bitmap_foto FROM TABELA_USUARIOS'); m.sql.add('WHERE id_usuario=1'); try m.Open; except on e:exception do begin Application.MessageBox(Pchar(e.message),'Erro ao buscar fotografia do usuario :'); Exit; end; end; // transferindo a fotografia para o objeto TStream b:=m.CreateBlobStream(m.FieldByName('bitmap_foto'),bmRead); // agora transferindo do TStream para um recipiente TImage Image1.Picture.Bitmap.LoadFromStream(b); b.Destroy; m.Free; end;

Com o cdigo acima recuperamos a fotografia do banco de dados sem precisar usar um TDBImage, apenas usando um TStream e copiando o contedo do TStream para um recipiente TImage. Algumas pessoas me contactaram por e-mail pedindo que por gentileza eu cedesse um exemplo para recuperar blobs do tipo Jpeg, pois so bem mais econmicos. Pois bem a seguir, dou um exemplo de como recuperar um blob do tipo JPeg, mas antes vou explicar a dificuldade que h com o TImage ao trabalhar outros formatos grficos. O windows nativamente trabalha somente com bitmaps, dessa forma o TImage j est pr-disposto a fazer operaes como OLE , Copiar, Colar, LoadFromFile, LoadFromStream e outras funes sempre neste mesmo formato, se voce usar o exemplo acima para trabalhar com Jpegs notar que perfeitamente possivel grava-los no banco de dados, no entanto, para receupera-los usando o mesmo exemplo vai ser um festival de 'acess violation', sabe dizer a razo do problema ? O que ocorre que o TImage s conhece nativamente bitmap, e caso voce faa um LoadFromStream, ocorrer ento a transferncia de dados num formato jpeg que ser tratado como bitmap, ops! o algortimo do TImage trabalhar com o formato Jpeg recebido como se fosse um bitmap causando ento pertubaes em seu sistema como por exemplo um festival de 'access violation on...' (violao de acesso).

Como resolver essa situao ? preciso registrar o formato Jpeg ao sistema, como fazer isso ? Simplesmente acrescentando a unit jpeg a clausula uses do programa, exemplo : unit exemplo; interface uses Windows, Messages,...,jpeg; ... A partir da, uma soluo simples e rpida trocar o LoadFromStream e passar a usar o LoadFromFile, pois oTImage associar a extenso do arquivo ao formato que se pretente usar, se por exemplo fizermos : Image1.LoadFromFile('c:\exemplo\foto1.jpg') ele saber que '.jpg' no um bitmap e procurar um formato grafico registrado no sistema que saiba trabalhar com tal extenso. Se voce acrescentou a unit jpeg ao sistema, tal registro j foi feito e o arquivo ser tratado corretamente pelo componente. Se a extenso no possuir nenhum registro ento automaticamente o TImage ir rejeitar carregar o arquivo. O registro dum formato grafico apenas uma classe derivada de TGraphic, por exemplo, ao usar a unit jpeg, automaticamente uma classe nova (filtro novo) ser criado : TJpegImage que exatamente por ser derivado de TGraphic ser possivel OLE, Copiar, Colar, LoadFromFile, LoadFromStream, e outras funes passaremm a reconhecer o formato Jpeg. Na realidade novos filtros graficos podem ser usados em todo ou qualquer sistema bastanto acrescentar classes derivadas de TGraphic. Exatamente por essa simplicidade j existem na internet filtros graficos para praticamente todos os formatos graficos : TIFF, JPEG, GIF, PCX, PNG, etc... Mas essa soluo talvez deixe alguns decepcionados, pois o LoadFromStream muito melhor, e em alguns casos como programaao em 'n' camadas o nico mtodo aceito. Ento vamos uma abordagem especfica para carregar 'Jpegs' atravs de LoadFromStream. Antes de mais nada, coloque a unit 'jpeg' na seo 'uses' de seu formulrio. Vamos ao exemplo : unit exemplo; uses ...,jpeg; . . . procedure TForm1.CarregarFotoJpeg; var m:TIbQuery; b:TStream; Jpg: TJpegImage; // sem a unit 'jpeg' essa classe no existiria begin Jpg := nil; // carregar foto m:=TIBQuery.Create(Self); m.Database:=MyIBXDatabase; m.Transaction:=MyIBXDatabase.DefaultTransaction; m.sql.clear; m.sql.add('SELECT jpeg_foto FROM TABELA_USUARIOS'); m.sql.add(''WHERE id_usuario=1'); try m.Open; except on e:exception do begin Application.MessageBox(Pchar(e.message),'Erro ao buscar fotografia do usuario :'); Exit; end; end; // transferindo a fotografia para o objeto TStream b:=m.CreateBlobStream(m.FieldByName('jpeg_foto'),bmRead); // se o registro no possui fotografia ento apagaremos a imagem // atual dentro do TImage, seno vai ficar parecendo que a // fotografia seguinte ser igual a anterior if b.Size > 0 then begin // aqui ta o problema, como recuperar o jpeg do banco // perceba que a variavel 'Jpg' do tipo TJpegImage que por sua vez uma classe TGraphic // e que portanto poder ser assinalada a propriedade Image1.Picure[.Graphic] try Jpg := TJpegImage.Create; Jpg.LoadFromStream(b); Image1.Picture.Assign(Jpg); except end; end

else begin // Essa seria a maneira natural de eliminar um desenho dentro do // TImage, pois se fizessemos um Image1.Picture.Graphic:=nil como // sugerem alguns exemplos na internet, provocariamos um 'access violation', // pois um nulo no pode ser tratado como bitmap ou jpeg. Image1.Picture.Assign(nil); end; // Vamos liberar um pouco de memria jpg.Free; b.Destroy; m.Free; end; O acrscimo da unit chamada jpeg na seo 'uses' (ex. uses jpeg) cria um novo tipo de dado derivada de TGraphic chamada TJpegImage e exatamente com esta classe que poderemos trabalhar com Jpegs. Se voce for tentar trabalhar com Jpeg's sem primeiramente registra-lo ento o TImage ir achar que a imagem recebida via LoadFromStream ser um bitmap, e como eu disse anteriormente ser um festival de 'access violation'. Quando todos os registros cujo campo blob ser sempre Bitmap ou ser sempre Jpeg os exemplos acima funcionam perfeitamente. No entanto, o TImage funciona com um filtro grafico por vez, o que isso quer dizer ? Isso quer dizer o seguinte, se houver a possibilidade de um mesmo TImage carregar um bitmap e a seguir tentar carregar um Jpeg ele vai causar um 'access violation' de novo. O LoadfromStream nao determina em nenhum parametro qual ser o formato grafico que se est transmitindo para o TImage, ento o TImage por sua vez re-utiliza o algoritimo de tratamento de imagem usado pela ultima vez. O LoadFromFile por sua vez no possui esse tipo de problema, pois determina o formato a ser carregado dependendo da extenso do arquivo. Se voce for cabea-dura e usar o LoadFromStream num nico TImage carregando um formato Jpeg e depois tentar carregar um Bitmap, advinha o que ocorrer : 'access violation' de novo. Significa isso que eu no possa usar dois formatos graficos num mesmo TImage de forma variavel ? De forma alguma, basta voce no trabalhar diretamente com o TImage, usar um filtro grafico para retornar um resultado compativel com TGraphic e depois usar a propriedade TImage.Picture para receber o resultado. Ao tratar um bitmap, antes de fazer um LoadFromStream, converta-o para TGraphic e antes de tratar um Jpeg converta-o tambem para TGraphic dessa forma o TImage.Picture poder trabalhar com ambos os contedos. Ento vamos a um exemplo que tambm carrega bitmaps, porm ao nves de usar Image1.Picture.Bitmap, usar um mtodo mais seguro e livre de erros, algo muito semelhante ao exemplo anterior que carregava um Jpeg : procedure TForm1.CarregarFotoBmp; var m:TIbQuery; b:TStream; Bmp: TBitmap; begin Bmp := nil; // carregar foto m:=TIBQuery.Create(Self); m.Database:=MyIBXDatabase; m.Transaction:=MyIBXDatabase.DefaultTransaction; m.sql.clear; m.sql.add('SELECT bitmap_foto FROM TABELA_USUARIOS'); m.sql.add('WHERE id_usuario=1'); try m.Open; except on e:exception do begin Application.MessageBox(Pchar(e.message),'Erro ao buscar fotografia do usuario :'); Exit; end; end; // transferindo a fotografia para o objeto TStream b:=m.CreateBlobStream(m.FieldByName('bitmap_foto'),bmRead); // se o registro no possui fotografia ento apagaremos a imagem // atual dentro do TImage, seno vai parecer que a fotografia seguinte // ser igual a anterior if b.Size > 0 then begin // Se voce t acompanhando o problema perceber que para recuperar o bitmap // o exemplo o mesmo usado para 'Jpeg', isso porque o tipoe TBitmap a exemplo do // tipo TJpegImage derivam e so usados pela classe TGraphic

// e que portanto poder ser assinalada a propriedade Image1.Picure[.Graphic] try Bmp := TBitmap.Create; Bmp.LoadFromStream(b); Image1.Picture.Assign(Bmp); except end; end else begin // Essa seria a maneira natural de eliminar um desenho dentro do // TImage, pois se fizessemos um Image1.Picture.Graphic:=nil como // sugerem alguns exemplos na internet, provocariamos um 'access violation', // pois um nulo no pode ser tratado como bitmap ou jpeg. Image1.Picture.Assign(nil); end; // Vamos liberar um pouco de memria Bmp.Free; b.Destroy; m.Free; end; Pronto ! O exemplo acima passa a trabalhar com o formato Bitmap de forma a converter a imagem para TGraphic e a partir desse poder usar TImage.Picture de forma muito transparente. Agora voce possui duas funes semelhantes que convertem o formato grafico Bitmap/Jpeg para TImage para ser usado na propriedade TImage.Picture. Se houvessem outros formatos graficos, o formato da funo acima permaneceria exatamente o mesmo, bastando ao invs de 'Bmp: TBitmap' experimentar um novo filtro grafico 'myPng: TPng'', usando estes mtodos voce poder tranquilamente carregar bitmap, jpeg e outros formatos graficos usando LoadFromStream sem nenhum medo de 'Access Violation'. TMemoryStream e TStream, por que ? Na realidade o que eu quero mostrar com esses exemplos que se soubermos recuperar ou salvar objetos BLOBs usando apenas TStream's e suas variantes estaremos dando um passo liberdade de programao multiformatos. Se voc ainda est acostumado a usar componentes dataaware como TDBMemo, TDBRichText, TDBImage,... para usar com contedos BLOBs saiba que voc ainda est no nvel muito bsico de programao com banco de dados. Se algum lhe pedisse para armazenar efeitos sonoros wave-tables num banco de dados, talvez voc procurar um componente TDBWAV que no existe na palheta do Delphi e por causa disso lamente dizendo que o Delphi no trabalha com esse formato, o que na realidade uma mentira deslavada! Qualquer tipo de contedo, qualquer que seja o formato, pode ser armazenado e recuperado do banco de dados com o uso de operaes simples TStream e suas variantes.

Nota do Autor : Como pode ver, precisamos desmistificar os BLOBs, eles so muito teis comunidade. Referencias: Um outro exemplo bastante interessante de como tocar .AVI armazenados dentro do banco de dados : http://community.borland.com/article/0,1410,16181,00.html Estes exemplos de salvar e carregar BLOBs resumem-se a poucas linhas graas ao recurso OOP do Delphi, se tivessemos que criar um recurso parecido sem usar OOP, usando por exemplo o Visual Basic, veja como ficaria : http://support.microsoft.com/support/kb/articles/Q103/2/57.asp Autor : Gladiston Santana Home Page : www.gladisto.hpg.com.br