마음의 안정을 찾기 위하여 - [Delphi][Graphics] detecting graphic formats
1961419
193
322
관리자새글쓰기
태그위치로그방명록
별일없다의 생각
dawnsea's me2day/2010
색상(RGB)코드 추출기(Color...
Connection Generator/2010
최승호PD, '4대강 거짓말 검...
Green Monkey**/2010
Syng의 생각
syng's me2DAY/2010
천재 작곡가 윤일상이 기획,...
엘븐킹's Digital Factory/2010
[Delphi][Graphics] detecting graphic formats
Delphi/Graphics, Draw | 2021/10/08 09:57


If you’re storing an image in a blob field or the like, I guess it’s not uncommon to have another field that specifies the graphic type. Really though, there’s no need, since the common graphic formats (‘common’ in a Delphi context at least) all have distinct signatures that allow for their easy identification –

  • Windows Bitmap (BMP): the ASCII characters ‘BM’.
  • GIF: the three ASCII characters ‘GIF’.
  • JPEG: a ‘new marker’ indicator ($FF) followed by a ‘start of image’ marker ($D8).
  • PNG: in order, the following eight ASCII characters – #137, ‘P’, ‘N’, ‘G’, #13, #10, #26 and #10.
  • TIFF: ‘II’ or ‘MM’ followed by $002A or $2A00 respectively.
  • Windows icon (ICO): the second word has the value $0001.
  • Windows Metafile (WMF): the first DWORD has the value $9AC6CDD7.
  • Windows Enhanced Metafile (EMF): the first DWORD must equal $00000001, followed by $464D4520 (i.e., ‘EMF’ when read back to front) in the eleventh.
  • Of this ‘standard’ set, the ICO format is obviously a bit indeterminate when it comes to making a quick check, but the rest are unique enough. In practice, the lack of a proper signature for ICO just means you should test for it last.



Anyhow, putting this knowledge together, you can write something like this:


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;



The graphic classes returned here are the ‘in the box’ set for recent Delphi versions; depending on which particular Delphi version and third party libraries you use, the ones that are most appropriate to yourself may differ of course.

With the FindGraphicClass function at hand, we can then write a further utility routine that loads a TPicture instance from a TBlobField like thus:



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;



This last routine may then be used like this (where ‘cdsPicture’ and ‘Image1’ are a TBlobField and TImage respectively that are created at design time):


procedure TForm1.btnTestLoadPictureClick(Sender: TObject);
begin
  LoadPictureFromBlobField(cdsPicture, Image1.Picture);
end;
2021/10/08 09:57 2021/10/08 09:57
Article tag list Go to top
View Comment 0
Trackback URL :: 이 글에는 트랙백을 보낼 수 없습니다
 
 
 
 
PREV : [1][2][3][4][5] ... [855] :
«   2021/11   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        
전체 (855)
출판 준비 (0)
My-Pro... (41)
사는 ... (492)
블로그... (22)
My Lib... (32)
게임 ... (23)
개발관... (3)
Smart ... (1)
Delphi (75)
C Builder (0)
Object... (0)
VC, MF... (9)
Window... (1)
Open API (3)
Visual... (0)
Java, JSP (2)
ASP.NET (0)
PHP (4)
Database (12)
리눅스 (28)
Windows (23)
Device... (1)
Embedded (1)
게임 ... (0)
Web Se... (2)
Web, S... (19)
잡다한... (5)
프로젝트 (0)
Personal (0)
대통령... (9)
Link (2)