Arquivos Binários no Paradox para quem gosta de Paradox J
Mais que criar novos sistemas, as empresas de software devem manter seus sistemas legados. Muitas vezes estas não possuem possibilidade de investimento para novas tecnologias e precisam então aperfeiçoar o uso das tecnologias existentes.
Uma limitação ou escolha de muitas empresas é trabalhar com sistema de arquivos, utilizando, por exemplo, Paradox. É mais simples para usar, desenvolver, alguns irão dizer.
Para quem já é leitor da revista ClubeDelphi há tempos, vai se lembrar da edição 32 da revista com a matéria, “BDE+Paradox? Azar, eu Gosto!”, que buscou mostrar como melhorar a robustez de sistemas que trabalham com estas tecnologias.
Respondi uma dúvida estes dias sobre como armazenar imagens em arquivos Paradox e como faz um bom tempo que não trabalho com BDE+Paradox pensei que seria aqui uma boa oportunidade para fazer alguns exemplos nesta excelente tecnologia. Nunca menospreze um arquivo Paradox. Ele é quem mantém o cache de dados quando você acessa um banco de dados Oracle usando BDE+CachedUpdates. Ou seja, sem o Paradox, seus sistemas não são nada! J
Criando a tabela do exemplo e alias do BDE!
Irei definir uma tabela usando que ferramenta? Database Desktop! Veja na Figura 1 a estrutura da tabela ArquivosBinarios.db, que possui um campo chave (Numérico), um campo binário (Binary) e um campo para armazenar uma imagem (Graphic).
Figura 1: Definição dos campos da tabela no Database Desktop
Para realizar a definição da tabela você deve entrar no Database Desktop (menu Tools do Delphi), executar o menu File -> New -> Table, selecionar o tipo como Paradox 7 e então definir os campos indicados na Figura 1. Salve o arquivo ArquivosBinarios.db em uma pasta de sua escolha para armazenar o nosso “banco de dados”.
Feita a definição da tabela, precisamos agora criar um alias no BDE para apontar a esta tabela. Para esta tarefa, podemos utilizar o SQL Explorer (acessível pelo menu Database -> Explore no Delphi) ou então fazer o processo pelo BDE Administrator (acessível pelo Painel de Controle).
No SQL Explorer você deve indicar o menu Object -> New, selecionar o tipo “Standard” como o tipo do alias, e então indicar o nome do alias: DBArquivosBinarios. Agora você deve configurar a propriedade PATH apontando para o caminho onde está o arquivo “.db” criado no passo anterior.
Tente visualizar os dados da tabela, como mostra a Figura 2.
Figura 2: SQL Explorer mostrando o alias DBArquivosBinarios criado e a tabela ArquivosBinarios.
Construindo a interface da aplicação de exemplo
Configure os seguintes componentes na sua tela. A Figura 3 mostra a interface resultante.
Componente |
TTable |
Name |
TblArquivosBinarios |
Database |
DBArquivosBinarios |
TableName |
ArquivosBinarios |
Active |
True |
Componente |
TDataSource |
Name |
dSrc |
DataSet |
TblArquivosBinarios |
Componente |
TDBGrid |
Name |
DBGrid |
DataSource |
dSrc |
Componente |
TLabel |
Name |
lblCampoGraphic |
Componente |
TDBImage |
Name |
DBImgCampoGraphic |
DataSource |
dSrc |
DataField |
CampoGraphic |
Componente |
TLabel |
Name |
lblCampoBinary |
Caption |
CampoBinary |
Componente |
TImage |
Name |
ImgCampoBinary |
Componente |
TButton |
Caption |
Carregar BMP |
Name |
BtnCarregarImagemCampoGraphicBMP |
Componente |
TButton |
Caption |
Carregar JPG |
Name |
BtnCarregarImagemCampoGraphicJPG |
Componente |
TButton |
Caption |
Carregar BMP |
Name |
BtnCarregarImagemCampoBinaryBMP |
Componente |
TButton |
Caption |
Carregar JPG |
Name |
BtnCarregarImagemCampoBinaryJPG |
Figura 3: Interface da tela construída para o exemplo
Carregando arquivos para um TDataSet
Para qualquer DataSet utilizado em programas Delphi temos a possibilidade de trabalhar com campos BLOB, ou Binary Large Object. Na Listagem 1 segue uma função para realizar a carga de um arquivo para um campo BLOB de um DataSet. Esta função recebe um nome de campo para trabalhar, recebe um filtro a ser aplicado em um componente chamado OpenDialog e realiza a carga deste arquivo para o campo.
Note que o tipo de cast (transformação/conversão) utilizado no TField sempre é para TBlobField. Um dos campos da nossa tabela de exemplo é do tipo TGraphicField, que é um tipo de TBlobField, então o processo funciona da mesma forma.
Veja que foram definidas duas constantes para facilitar a configuração do Componente TOpenDialog, para que ao realizar a seleção de um BMP (FILTRO_BMP), apenas arquivos bitmaps sejam listados. O mesmo para arquivos com a extensão JPG (FILTRO_JPG).
Importante: Para possibilitar o trabalho com arquivos JPG, você deve acrescentar na cláusula uses a unit JPEG.
Listagem 1. Código para realizar a carga de um arquivo para um campo BLOB de um DataSet.
...
interface
uses
...,JPEG,...;
const
FILTRO_JPG = 'JPEG Image (*.jpg)|*.jpg';
FILTRO_BMP = 'BMP Image (*.bmp)|*.bmp';
...
implementation
...
procedure TFormPrincipal.CarregarArquivo(ADataField, AFiltro: String);
begin
OpenDialog.Filter := AFiltro;
if(OpenDialog.Execute) then
begin
if(TblArquivosBinarios.RecordCount = 0) then
TblArquivosBinarios.Insert
else
TblArquivosBinarios.Edit;
try
(TblArquivosBinarios.FieldByName(ADataField) as
TBlobField).LoadFromFile(OpenDialog.FileName);
if(TblArquivosBinarios.State = dsEdit) then
TblArquivosBinarios.Post;
except
on e:Exception do
begin
ShowMessage('Erro ao armazenar arquivo ' + OpenDialog.FileName +
#13#10 +
'Erro (' + e.ClassName + '): ' + e.Message);
end;
end;
end;
end;
Carregar imagem para mostrar em um TDBImage
Ao tentar carregar uma imagem diferente de um bitmap em um componente TDBImage recebemos um erro indicando “Bitmap image is not valid”. Com isto, podemos concluir que para apresentar em um TDBImage, a imagem armazenada no banco de dados deve ser do tipo Bitmap.
Resumindo: Uma imagem do tipo JPEG pode ser armazenada em um arquivo Paradox, mas terá problemas ao ser mostrada em um componente TDBImage.
Na Listagem 2 conseguimos visualizar o evento de Click de dois botões, que fazem a carga no CampoGraphic, ligado ao TDBImage. Ao executar a aplicação, você reberá um erro com a mensagem “Bitmap image is not valid” ao tentar carregar um JPG.
Listagem 2. Código para fazer a carga de arquivos para o campo ligado ao componente TDBImage
procedure TFormPrincipal.BtnCarregarImagemCampoGraphicBMPClick(
Sender: TObject);
begin
CarregarArquivo('CampoGraphic', FILTRO_BMP);
end;
procedure TFormPrincipal.BtnCarregarImagemCampoGraphicJPGClick(
Sender: TObject);
begin
CarregarArquivo('CampoGraphic', FILTRO_JPG);
end;
A execução da função é simples, através da chamada para a função CarregarArquivo, passando por parâmetro o nome do campo a ser trabalhado e o tipo de filtro a ser utilizado. O filtro vai indicar se o componente OpenDialog deve mostrar arquivos BMP ou JPG.
Carregar imagem para mostrar em um TImage
Para quem deseja trabalhar com arquivos JPG, a solução é trocar a visualização dos arquivos para um TImage. Armazenando imagens JPG no seu arquivo Paradox você consegue minimizar o espaço utilizado em disco (visto que possui um excelente grau de compressão), no espaço utilizado pelos arquivos .MB (auxiliares ao arquivo principal .DB) que armazenam os dados de campos BLOB por exemplo.
Veja na Listagem 3 a declaração dos eventos de click que gravam um arquivo de imagem no CampoBinary e depois mostram a mesma no componente TImage. Para facilitar o processo estou gravando a imagem em disco e em seguida carregando a mesma no componente TImage.
Listagem 3. Código para carregar imagens no banco de dados e mostrar as mesmas em componente TImage.
procedure TFormPrincipal.BtnCarregarImagemCampoBinaryJPGClick(
Sender: TObject);
begin
CarregarArquivo('CampoBinary', FILTRO_JPG);
TblArquivosBinariosCampoBinary.SaveToFile('c:\imgBinary.jpg');
ImgCampoBinary.Picture.LoadFromFile('c:\imgBinary.jpg');
end;
procedure TFormPrincipal.BtnCarregarImagemCampoBinaryBMPClick(
Sender: TObject);
begin
CarregarArquivo('CampoBinary', FILTRO_BMP);
TblArquivosBinariosCampoBinary.SaveToFile('c:\imgBinary.bmp');
ImgCampoBinary.Picture.LoadFromFile('c:\imgBinary.bmp');
end;
Podemos melhorar a carga dos arquivos para o componente TImage, deixando de utilizar os arquivos auxiliares em disco para trabalhar somente em memória, como pode ser visto na Listagem 4. Veja o uso da função CreateBlobStream, que é uma função do TDataSet e não do TField que permite criar uma representação TStream a partir de um campo.
Trabalhamos também com as classes TBitmap e com a classe TJPEGImage para manipular os fluxos em memória (TStream).
Listagem 4. Fazendo a carga do campo do banco de dados para o TImage sem utilizar arquivos auxiliares.
procedure TFormPrincipal. CarregarImagemJPG (ABlobField: TBlobField);
var stCampoBinary : TStream;
jpgImage : TJPEGImage;
begin
stCampoBinary := TblArquivosBinarios.CreateBlobStream(ABlobField,bmRead);
jpgImage := TJPEGImage.Create;
try
jpgImage.LoadFromStream(stCampoBinary);
ImgCampoBinary.Picture.Assign(jpgImage);
finally
stCampoBinary.Free;
jpgImage.Free;
end;
end;
procedure TFormPrincipal.CarregarImagemBMP(ABlobField: TBlobField);
var stCampoBinary : TStream;
bmpImage : TBitmap;
begin
stCampoBinary := TblArquivosBinarios.CreateBlobStream(ABlobField,bmRead);
bmpImage := TBitmap.Create;
try
bmpImage.LoadFromStream(stCampoBinary);
ImgCampoBinary.Picture.Assign(bmpImage);
finally
stCampoBinary.Free;
bmpImage.Free;
end;
end;
procedure TFormPrincipal.BtnCarregarImagemCampoBinaryJPGClick(
Sender: TObject);
begin
CarregarArquivo('CampoBinary', FILTRO_JPG);
CarregarImagemJPG(TblArquivosBinariosCampoBinary);
end;
procedure TFormPrincipal.BtnCarregarImagemCampoBinaryBMPClick(
Sender: TObject);
begin
CarregarArquivo('CampoBinary', FILTRO_BMP);
CarregarImagemBMP(TblArquivosBinariosCampoBinary);
end;
Conclusões
Espero que com esta dica fique mais fácil para os desenvolvedores agregarem em suas aplicações o uso de imagens JPEG e Bitmaps e poder trabalhar com estes formatos em aplicações com acesso a banco de dados.
Para poder controlar quando mostrar a imagem do banco no TImage, pensando em uma aplicação de manutenção de dados, você pode utilizar o evento OnDataChange do DataSource e verificar se a propriedade BlobSize do campo do tipo TBlobField é maior que zero. Se estiver maior que zero se deve então carregar a imagem do banco de dados no controle ,usando as funções CarregarImagemBMP e CarregarImagemJPG.
Quem precisar armazenar arquivos com diferentes extensões em banco de dados, o ideal é criar um campo extra na tabela para permitir indicar o nome do arquivo ou pelo menos a sua extensão. Desta forma quando for necessário recuperar o campo binário e gravar o mesmo em disco se saberá a extensão correta.
E claro, não deixe de ler a edição 32 da ClubeDelphi! Até a próxima!
Links
www.firebase.com.br/fb/artigo.php?id=301
Artigo que mostra como trabalhar com imagens JPG em campos Firebird. Você pode olhar nesta dica como controlar o momento de mostrar as imagens no TImage (evento OnDataChange do TDataSource).