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).

 

imagem 

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.

imagem 

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

 

imagem 

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).