Detecção de formatos gráficos em Delphi

formato de imagens em delphi

Fala galera da programação, tudo beleza?

Se você estiver armazenando uma imagem em um campo de blob ou similar, acho que não é incomum ter outro campo que especifique o tipo gráfico. Realmente, porém, não há necessidade, uma vez que os formatos gráficos comuns (“common” em um contexto Delphi pelo menos) têm assinaturas distintas que permitem sua fácil identificação.

 

Tipos mais comuns

Bitmap do Windows (BMP): os caracteres ASCII ‘BM’.
GIF: os três caracteres ASCII ‘GIF’.
JPEG: um indicador ‘new marker’ ($FF) seguido de um marcador ‘start of image’ ($D8).
PNG: por ordem, os seguintes oito caracteres ASCII – #137, ‘P’, ‘N’, ‘G’, #13, #10, #26 e #10.
TIFF: ‘II’ ou ‘MM’ seguidos de $002A ou $2A00, respetivamente.
Ícone do Windows (ICO): a segunda palavra tem o valor $0001.
Windows Metafile (WMF): o primeiro DWORD tem o valor $9AC6CDD7.
Windows Enhanced Metafile (EMF): o primeiro DWORD deve ser igual a $00000001, seguido de $464D4520 (ou seja, ‘EMF’ quando lido de trás para a frente) no décimo primeiro.
Deste conjunto “standard”, o formato ICO é obviamente um pouco indeterminado quando se trata de fazer uma verificação rápida, mas o resto é único o suficiente. Na prática, a falta de uma assinatura adequada para a ICO significa apenas que você deve testar por último.

De qualquer forma, a partir destas informações, podemos chegar no seguinte código:

uses SysUtils, Classes, Graphics, GIFImg, JPEG, PngImage;
 
const
  MinGraphicSize = 44; //we may test up to & including the 11th longword
 
function FindGraphicClass(const Buffer; const BufferSize: Int64;
  out GraphicClass: TGraphicClass): Boolean; overload;
var
  LongWords: array[Byte] of LongWord absolute Buffer;
  Words: array[Byte] of Word absolute Buffer;
begin
  GraphicClass := nil;
  Result := False;
  if BufferSize < MinGraphicSize then Exit;
  case Words[0] of
    $4D42: GraphicClass := TBitmap;
    $D8FF: GraphicClass := TJPEGImage;
    $4949: if Words[1] = $002A then GraphicClass := TWicImage; //i.e., TIFF
    $4D4D: if Words[1] = $2A00 then GraphicClass := TWicImage; //i.e., TIFF
  else
    if Int64(Buffer) = $A1A0A0D474E5089 then
      GraphicClass := TPNGImage
    else if LongWords[0] = $9AC6CDD7 then
      GraphicClass := TMetafile
    else if (LongWords[0] = 1) and (LongWords[10] = $464D4520) then
      GraphicClass := TMetafile
    else if StrLComp(PAnsiChar(@Buffer), 'GIF', 3) = 0 then
      GraphicClass := TGIFImage
    else if Words[1] = 1 then
      GraphicClass := TIcon;
  end;
  Result := (GraphicClass <> nil);
end;
 
function FindGraphicClass(Stream: TStream;
  out GraphicClass: TGraphicClass): Boolean; overload;
var
  Buffer: PByte;
  CurPos: Int64;
  BytesRead: Integer;
begin
  if Stream is TCustomMemoryStream then
  begin
    Buffer := TCustomMemoryStream(Stream).Memory;
    CurPos := Stream.Position;
    Inc(Buffer, CurPos);
    Result := FindGraphicClass(Buffer^, Stream.Size - CurPos, GraphicClass);
    Exit;
  end;
  GetMem(Buffer, MinGraphicSize);
  try
    BytesRead := Stream.Read(Buffer^, MinGraphicSize);
    Stream.Seek(-BytesRead, soCurrent);
    Result := FindGraphicClass(Buffer^, BytesRead, GraphicClass);
  finally
    FreeMem(Buffer);
  end;
end;

 

As classes gráficas retornadas aqui são as que estão disponíveis para versões recentes do Delphi. Então dependendo de qual versão específica do Delphi e bibliotecas de terceiros você usa, os que são mais apropriados para si mesmo podem diferir, é claro.

Com a função FindGraphicClass em mãos, podemos então escrever uma rotina de utilitário adicional que carrega uma instância TPicture de um TBlobField conforme o exemplo a seguir:

uses Consts, DB;
 
procedure LoadPictureFromBlobField(Field: TBlobField; Dest: TPicture);
var
  Graphic: TGraphic;
  GraphicClass: TGraphicClass;
  Stream: TMemoryStream;
begin
  Graphic := nil;
  Stream := TMemoryStream.Create;
  try
    Field.SaveToStream(Stream);
    if Stream.Size = 0 then
    begin
      Dest.Assign(nil);
      Exit;
    end;
    if not FindGraphicClass(Stream.Memory^, Stream.Size, GraphicClass) then
      raise EInvalidGraphic.Create(SInvalidImage);
    Graphic := GraphicClass.Create;
    Stream.Position := 0;
    Graphic.LoadFromStream(Stream);
    Dest.Assign(Graphic);
  finally
    Stream.Free;
    Graphic.Free;
  end;
end;

 

Esta última rotina pode então ser usada assim (onde “cdsPicture” e “Image1” são um TBlobField e TImage respectivamente que são criados no momento do design):

procedure TForm1.btnTestLoadPictureClick(Sender: TObject);
begin
  LoadPictureFromBlobField(cdsPicture, Image1.Picture);
end;

 

Conclusão

Em resumo, ser capaz de detectar o formato de arquivo de uma imagem é uma habilidade valiosa ao trabalhar com manipulação de imagens em Delphi. Esta capacidade não apenas permite que você carregue diferentes tipos de imagens em sua aplicação de forma eficiente, mas também facilita a validação de arquivos de imagem para garantir que estejam no formato esperado.

Ao examinar os primeiros bytes de um arquivo de imagem e compará-los com os padrões de assinatura de diferentes formatos gráficos, você pode determinar rapidamente o tipo de imagem que está lidando. Esta abordagem simples, usando Delphi, permite uma detecção precisa e eficaz de formatos gráficos, fornecendo uma base sólida para o desenvolvimento de aplicativos robustos e eficientes que lidam com imagens.

Ao implementar essa técnica em seus projetos, você estará melhor equipado para lidar com uma variedade de formatos de imagem e garantir uma experiência de usuário suave e consistente em suas aplicações Delphi.

 

Beleza pessoal? Espero que possa ajudar.

 

Dúvidas ou sugestões? Deixe o seu comentário.

 

Um abraço e até o próximo post. Valeu!

 

Fonte: https://delphihaven.wordpress.com/2011/01/22/tip-detecting-graphic-formats/

 

#Delphi

#DesenvolvimentoDeSoftware

#ManipulaçãoDeImagens

#GiovaniDaCruz

  • Publicado por Giovani Da Cruz
  • 7 views
  • 0 comentarios
  • 19 de abril de 2024

 

Está gostando do conteúdo?
Considere pagar um cafezinho para nossa equipe!

 

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Posts Relacionados a Categoria Delphi

Continue aprendendo

Aumente o seu conhecimento
Utilizando TParallel.For da Biblioteca de Programação Paralela em Delphi
6 de maio de 2024
Imagens e Fotos em Delphi e Lazarus (TImage e TDBImage)
4 de abril de 2024
Enviando Arquivos em Delphi Utilizando REST API: Uma Abordagem Prática
1 de março de 2024
5 dicas para converter String para Integer em Pascal / Delphi / Lazarus
18 de fevereiro de 2024
Como gravar um valor no registro do Windows em Delphi, Lazarus, Pascal
27 de janeiro de 2024