Seção 4: Encontrando o início do JPEG no BLOB
Formato de tipo de objeto OLE - pegue três!
Agora tudo o que precisamos fazer é armazenar a imagem em disco (como um arquivo binário simples) e entender o que há dentro dela.
Todos os arquivos de imagem (formatos) possuem cabeçalhos de arquivo que identificam exclusivamente a imagem. Os arquivos de imagem JPG começam com a chamada tag SOI, cujo valor hexadecimal é $FFD8.
A linha de código a seguir armazena o valor do campo de imagem no arquivo relevante (BlobImage.dat) no diretório de trabalho. Coloque este código no evento OnCreate do formulário e remova-o após iniciar o projeto.
ADOTable1Picture.SaveToFile('BlobImage.dat');
Assim que tivermos este arquivo. Podemos usar o editor Hex para visualizar seu conteúdo.
Você acredita nisso? O acesso MS armazena o caminho para o objeto OLE conectado no campo do objeto OLE como parte da definição do objeto. Como a definição de armazenamento de objetos OLE não está documentada (!? Isso vem diretamente do MS), não há como saber o que os dados reais da imagem obterão antes de serem gravados.
Considere esta questão em duas partes. Primeiro: precisamos encontrar ‘FFD8’ e começar a ler a imagem a partir daí. Segundo: 'FFD8' nem sempre pode estar na mesma posição no arquivo. Conclusão: Precisamos de uma função que retorne a localização da tag SOI de um arquivo JPG armazenado como um objeto OLE no banco de dados Access.
A maneira correta – pegue quatro!
Com um campo do tipo Blob fornecido, nossa função deve retornar a posição da string 'FFD8' no ADOBlobStream. ReadBuffer lê dados do fluxo byte por byte. Cada chamada para ReadBuffer move a posição do fluxo byte por byte. A função retorna a posição do fluxo quando dois bytes juntos levam ao marcador SOI. Esta é a função:
função JpegStartsInBlob(PicField:TBlobField):inteiro;
var
bS: TADOBlobStream;
buffer: Palavra;
hx: sequência;
começar
Resultado:= -1;
bS := TADOBlobStream.Create(PicField, bmRead);
tentar
enquanto (Resultado = -1) e (bS.Position + 1 < bS.Size) faça
começar
bS.ReadBuffer(buffer, 1);
hx:=IntToHex(buffer, 2);
se hx = 'FF' então comece
bS.ReadBuffer(buffer, 1);
hx:=IntToHex(buffer, 2);
se hx = 'D8' então Resultado: = bS.Position - 2
senão se hx = 'FF' então
bS.Posição := bS.Posição-1;
fim; //se
fim; //enquanto
finalmente
bS.Livre
fim; //tentar
fim;
Assim que tivermos a localização do marcador SOI, podemos usá-lo para encontrar a localização da imagem no fluxo ADOBlob.
usa jpeg;
...
PRocedure TForm1.btnShowImageClick(Remetente: TObject);
var
bS: TADOBlobStream;
Foto: TJpegImage;
começar
bS := TADOBlobStream.Create(AdoTable1Picture, bmRead);
tentar
bS.Seek(JpegStartsInBlob(AdoTable1Picture),soFromBeginning);
Foto:=TJpegImage.Create;
tentar
Pic.LoadFromStream(bS);
ADOImage.Picture.Graphic:=Pic;
finalmente
Foto.Grátis;
fim;
finalmente
bS.Livre
fim;
fim;
Execute o projeto, OK!
Agora, quem pode dizer que programar não é divertido?
Nota: No programa de código real, adicionaremos código para ler e exibir a imagem da linha atual no evento AfterScroll do TDataSet (está no procedimento do evento ADOTable1AfterScroll). O evento AfterScroll ocorre quando o aplicativo rola de um registro para outro.
Idéia cinco!
É disso que trata este capítulo. Agora você pode armazenar e exibir todas as imagens JPG de seu interesse. Na última página deste artigo, disponibilizarei o código completo (unidade form1); toda a organização dos dados é colocada no evento OnCreate do formulário. Isso garante que todos os três componentes estejam conectados corretamente - você não precisa usar o Object Inspector ao projetar.
Admito que este capítulo não é para iniciantes, mas o mundo é um lugar cruel! Outra coisa: você percebe que no final você nem sabe como mudar (ou adicionar novas) fotos na mesa! Sim, isso é outra história!