Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Bildformat anhand Header erkennen (https://www.delphipraxis.net/155578-bildformat-anhand-header-erkennen.html)

NickelM 29. Okt 2010 16:43

Bildformat anhand Header erkennen
 
Hi ihr Programmierer,

Ich less mit über die neue Kontactstruktur von Vista das Kontaktbild von einem Kontakt als Stream heraus.
Wenn es die Standartbilder sind geht Bitmap super. Wenn jemand aber ein PNG Image auswählt funkt dies nicht mehr.
So jetzt wollt ich mal fragen, ob man anhand bestimmter Bytes in dem Stream, das Format erkennen kann.
Hab schon gegooglet, aber nichts gefunden oder ich bin blind :shock: oder suche unter dem falschen Begriff.

Gruss NickelM

himitsu 29. Okt 2010 17:36

AW: Bildformat anhand Header erkennen
 
Wie lädst du denn das Bild?
Und hast du PNG überhaupt in dein Programm eingebunden?

siehe Abschnitte "Dateikopf":
http://de.wikipedia.org/wiki/Portable_Network_Graphics
http://de.wikipedia.org/wiki/Windows_Bitmap

NickelM 29. Okt 2010 21:45

AW: Bildformat anhand Header erkennen
 
Eingebunden ja.
Es ist ja so ich bekomm dne Stream. Ich will dann das Bild in eine ListBox zeichnen (mit einer TImageList.
Funkt auch wenn ich das Format kenne.
So wenn ich das jetzt richtig verstehe sind das also immer die ersten 2 Bytes die den Dateityp identifizieren.
Danke ich guge mal ob ich es damit hinbekomme.

EDIT: Habe es durch den Post herausgefunden. Es gibt ein Header Record names TBitmapFileHeader;
Mit dem kann ich erkenne ob bitmap,gif und jpeg bis jetzt. Ich denk ich find dadruch auch die anderen raus. Danke

toms 30. Okt 2010 00:05

AW: Bildformat anhand Header erkennen
 
Habe etwas experimentiert:

Delphi-Quellcode:
const
  GIF_HEADER = AnsiChar($47) + AnsiChar($49) + AnsiChar($46);
  JPG_HEADER = AnsiChar($FF) + AnsiChar($D8) + AnsiChar($FF) + AnsiChar($E0);
  BMP_HEADER = AnsiChar($42) + AnsiChar($4D);
  PNG_HEADER = AnsiChar($89) + AnsiChar($50) + AnsiChar($4E) + AnsiChar($47);
  PSD_HEADER = AnsiChar($38) + AnsiChar($42) + AnsiChar($50) + AnsiChar($53);
  TIF_HEADER = AnsiChar($49) + AnsiChar($49) + AnsiChar($2A);
  TIF_HEADER2 = AnsiChar(77) + AnsiChar(77) + AnsiChar(00);
  WMF_HEADER = AnsiChar($D7) + AnsiChar($CD) + AnsiChar($C6) + AnsiChar($9A);

  MAX_SIGNATURES = 7;

  Signatures: array[0..MAX_SIGNATURES] of TImageSignature = (
    (ImageType: ifGIF; Name: 'Image/GIF'; Signature: GIF_HEADER),
    (ImageType: ifJPG; Name: 'Image/JPEG'; Signature: JPG_HEADER),
    (ImageType: ifPNG; Name: 'Image/PNG'; Signature: PNG_HEADER),
    (ImageType: ifBMP; Name: 'Image/BMP'; Signature: BMP_HEADER),
    (ImageType: ifTIF; Name: 'Image/TIFF'; Signature: TIF_HEADER),
    (ImageType: ifTIF; Name: 'Image/TIFF'; Signature: TIF_HEADER2),
    (ImageType: ifWMF; Name: 'Image/WMF'; Signature: WMF_HEADER),
    (ImageType: ifPSD; Name: 'Image/PSD'; Signature: PSD_HEADER));

type
  TImageType = (ifUnknown, ifJPG, ifGIF, ifBMP, ifPNG, ifPSD, ifTIF, ifWMF);

  TImageSignature = record
    ImageType: TImageType;
    Name: string;
    Signature: AnsiString;
  end;

function CheckImageSignature(AStream: TStream; Signature: AnsiString; Offset:
  Integer): Boolean;
var
  Buffer: AnsiString;
  Count: Integer;
  BytesRead: Integer;
begin
  Result := False;
  try
    Count := Length(Signature);
    AStream.Position := Offset;
    SetLength(Buffer, Count);
    BytesRead := AStream.Read(Buffer[1], Count);
    Result := (BytesRead = Count) and (Buffer = Signature);
  except
  end;
end;

function GetImageType(FileName: string): TImageSignature;
var
  Stream: TFileStream;
  MemStr: TMemoryStream;
  i: Integer;
begin
  Result.ImageType := ifUnknown;
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    MemStr := TMemoryStream.Create;
    try
      MemStr.CopyFrom(Stream, 5);
      if MemStr.Size > 4 then
      begin
        Result.ImageType := ifUnknown;
        for i := Low(Signatures) to High(Signatures) do
        begin
          if CheckImageSignature(MemStr, Signatures[i].Signature, 0) then
          begin
            Result.ImageType := Signatures[i].ImageType;
            Result.Name := Signatures[i].Name;
            Break;
          end;
        end;
      end;
    finally
      MemStr.Free;
    end;
  finally
    Stream.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  ImgSig: TImageSignature;
begin
  if OpenDialog1.Execute then
  begin
    FileName := OpenDialog1.FileName;
    ImgSig := GetImageType(FileName);
    Label1.Caption := ImgSig.Name;
  end;
end;

Luckie 30. Okt 2010 00:15

AW: Bildformat anhand Header erkennen
 
Und das ganze jetzt noch in einer schönen Klasse. :wink:

toms 30. Okt 2010 00:23

AW: Bildformat anhand Header erkennen
 
Zitat:

Zitat von Luckie (Beitrag 1058583)
Und das ganze jetzt noch in einer schönen Klasse. :wink:

Das sei dem Coder überlassen was aus dem "Rohcode" angestellt wird...

Luckie 30. Okt 2010 00:29

AW: Bildformat anhand Header erkennen
 
Mal sehen, ob ich morgen dazu komme.

NickelM 31. Okt 2010 00:35

AW: Bildformat anhand Header erkennen
 
Danke für den Schönen Code habe es aber schon hinbekommen.
Geht auch einfacher :

Delphi-Quellcode:
const
GifType = 18759; //uses gifimg
BitmapType = 19778;
PngType = 20617; //uses pngimage
JpegType = 55551; //uses jpeg

var
InfoHeader : TBitmapFileHeader;
Stream : TMemoryStream;
begin
  if Assigned(S) then
  begin
  S.Read(InfoHeader,SizeOf(TBitmapFileHeader));
  S.Position := 0;
  case InfoHeader.bfType of

  PngType:
  begin

  end;

  JpegType:
  begin

  end;

  GifType:
  begin

  end;

  BitmapType:
  begin

  end;
end;

end;
So das Funkt nur wenn die Windows Unit eingebunden ist für die Leute die Konsolenanwendungen schreiben :-D

toms 31. Okt 2010 06:00

AW: Bildformat anhand Header erkennen
 
TBitmapFileHeader ist nur für Datein mit Typ "BM" gedacht. TBitmapFileHeader.bfType gibt auch nur immer 2 bytes zurück.
Die Signaturen von JPEG etc. sind jedoch länger und so werden die Dateien unter Umständen nicht korrekt erkannt. Somit bevorzuge ich meine Variante, auch wenn sie etwas länger ist.

Anbei noch eine leicht abgeänderte Variante:

Delphi-Quellcode:
type
  TImageType = (ifUnknown, ifJPG, ifGIF, ifBMP, ifPNG, ifPSD, ifTIF, ifWMF);

type
  TImageSignature = record
    ImgType: TImageType;
    ImgName: string;
    ImgSig: AnsiString;
  end;

function GetImageType(FileName: string): TImageSignature;
const
  MAX_SIGNATURES = 8;

  Signatures: array[0..MAX_SIGNATURES] of TImageSignature = (
    (ImgType: ifGIF; ImgName: 'Image/GIF'; ImgSig: #$47#$49#$46#$38),
    (ImgType: ifJPG; ImgName: 'Image/JPEG'; ImgSig: #$FF#$D8#$FF#$E0),
    (ImgType: ifJPG; ImgName: 'Image/JPEG'; ImgSig: #$FF#$D8#$FF#$E1),
    (ImgType: ifPNG; ImgName: 'Image/PNG'; ImgSig: #$89#$50#$4E#$47),
    (ImgType: ifBMP; ImgName: 'Image/BMP'; ImgSig: #$42#$4D),
    (ImgType: ifTIF; ImgName: 'Image/TIFF'; ImgSig: #$49#$49#$2A),
    (ImgType: ifTIF; ImgName: 'Image/TIFF'; ImgSig: #$4D#$4D#$00),
    (ImgType: ifWMF; ImgName: 'Image/WMF'; ImgSig: #$D7#$CD#$C6#$9A),
    (ImgType: ifPSD; ImgName: 'Image/PSD'; ImgSig: #$38#$42#$50#$53));

  function CheckImageSignature(AStream: TStream; Signature: AnsiString; Offset:
    Integer): Boolean;
  var
    Buffer: AnsiString;
    Count: Integer;
    BytesRead: Integer;
  begin
    Result := False;
    try
      Count := Length(Signature);
      AStream.Position := Offset;
      SetLength(Buffer, Count);
      BytesRead := AStream.Read(Buffer[1], Count);
      Result := (BytesRead = Count) and (Buffer = Signature);
    except
    end;
  end;

var
  Stream: TFileStream;
  MemStr: TMemoryStream;
  i: Integer;
begin
  FillChar(Result, SizeOf(Result), 0);
  Result.ImgType := ifUnknown;
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    MemStr := TMemoryStream.Create;
    try
      MemStr.CopyFrom(Stream, 5);
      if MemStr.Size > 4 then
      begin
        for i := Low(Signatures) to High(Signatures) do
        begin
          if CheckImageSignature(MemStr, Signatures[i].ImgSig, 0) then
          begin
            Result.ImgType := Signatures[i].ImgType;
            Result.ImgName := Signatures[i].ImgName;
            Result.ImgSig := Signatures[i].ImgSig;
            Break;
          end;
        end;
      end;
    finally
      MemStr.Free;
    end;
  finally
    Stream.Free;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  ImgSig: TImageSignature;
begin
  if OpenDialog1.Execute then
  begin
    FileName := OpenDialog1.FileName;
    ImgSig := GetImageType(FileName);
    case ImgSig.ImgType of

      ifPNG:
        begin
          //...
        end;

      ifJPG:
        begin
         //...
        end;

      ifGif:
        begin
         //...
        end;

      ifBMP:
        begin
         //...
        end;
    end;
  end;
end;

Satty67 31. Okt 2010 09:14

AW: Bildformat anhand Header erkennen
 
Bis auf eine kleine Änderung
Delphi-Quellcode:
  MAX_SIGNATURES = 9;
  Signatures: array[0..(MAX_SIGNATURES -1)] of TImageSignature =
hab' ich das gleich in meine FileUtils mit rein genommen. Danke für's zusammenstellen.

Finde auch nicht, dass alles in eine Klasse gehört, selbst wenn es sich manchmal anbietet. Seit ich viel mit C# arbeite, bin ich sehr froh, das man in Delphi da freier ist. Passt zumindest bei mir als Funktion besser zu den anderen kleinen File-Funktionen.

NickelM 31. Okt 2010 11:41

AW: Bildformat anhand Header erkennen
 
Würde es in meinem Fall auch nur die ersten 2 Bytes tun?
Weil die daten lade ich sowieso mit den entsprechenden TGraphic Klassen dann, Wie z.b. TJpegImage oder TPngImage.
ob es dann die signatur von eine jpg oder jpeg hat ist doch in dem Fall egal oder nicht?


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz