Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   wie art der daten in blob erkennen? (https://www.delphipraxis.net/213636-wie-art-der-daten-blob-erkennen.html)

KodeZwerg 1. Sep 2023 12:00

AW: wie art der daten in blob erkennen?
 
@himitsu, ich kam mit Deiner Art leider nicht ganz zurecht aber habe es recht gut optimiert finde ich
Delphi-Quellcode:
program Project12;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Classes;

{$SCOPEDENUMS ON}
type
  TImageFormat = (Unknown, BMP, GIF, TIFF, JPEG, PNG, ICO);
{$SCOPEDENUMS OFF}

type
  TSignature = packed record
    Format: Integer;
    Offset: Integer;
    Signature: array of Integer;
  end;
  TSignatures = array of TSignature;

function GetSignatureList: TSignatures;
begin
  SetLength(Result, 14);
  Result[0].Format := Ord(TImageFormat.JPEG);
  Result[0].Offset := 0;
  Result[0].Signature := [$FF, $D8, $FF, $DB];
  Result[1].Format := Ord(TImageFormat.JPEG);
  Result[1].Offset := 0;
  Result[1].Signature := [$FF, $D8, $FF, $E0, $00, $10, $4A, $46];
  Result[2].Format := Ord(TImageFormat.JPEG);
  Result[2].Offset := 0;
  Result[2].Signature := [$49, $46, $00, $01];
  Result[3].Format := Ord(TImageFormat.JPEG);
  Result[3].Offset := 0;
  Result[3].Signature := [$FF, $D8, $FF, $EE];
  Result[4].Format := Ord(TImageFormat.JPEG);
  Result[4].Offset := 0;
  Result[4].Signature := [$FF, $D8, $FF, $E1, -1, -1, $45, $78];
  Result[5].Format := Ord(TImageFormat.JPEG);
  Result[5].Offset := 0;
  Result[5].Signature := [$69, $66, $00, $00];
  Result[6].Format := Ord(TImageFormat.JPEG);
  Result[6].Offset := 0;
  Result[6].Signature := [$FF, $D8, $FF, $E0];
  Result[7].Format := Ord(TImageFormat.PNG);
  Result[7].Offset := 0;
  Result[7].Signature := [$89, $50, $4E, $47, $0D, $0A, $1A, $0A];
  Result[8].Format := Ord(TImageFormat.GIF);
  Result[8].Offset := 0;
  Result[8].Signature := [$47, $49, $46, $38, $37, $61];
  Result[9].Format := Ord(TImageFormat.GIF);
  Result[9].Offset := 0;
  Result[9].Signature := [$47, $49, $46, $38, $39, $61];
  Result[10].Format := Ord(TImageFormat.BMP);
  Result[10].Offset := 0;
  Result[10].Signature := [$42, $4D];
  Result[11].Format := Ord(TImageFormat.ICO);
  Result[11].Offset := 0;
  Result[11].Signature := [$00, $00, $01, $00];
  Result[12].Format := Ord(TImageFormat.TIFF);
  Result[12].Offset := 0;
  Result[12].Signature := [$49, $49, $2A, $00];
  Result[13].Format := Ord(TImageFormat.TIFF);
  Result[13].Offset := 0;
  Result[13].Signature := [$4D, $4D, $00, $2A];
end;

function GetMaxSignatureSize(const ASignatures: TSignatures): Integer;
var
  i: Integer;
begin
  Result := 0;
  for i := Low(ASignatures) to High(ASignatures) do
    if (Length(ASignatures[i].Signature) > Result) then
      Result := Length(ASignatures[i].Signature);
end;

function CompareBytes(const AData: TBytes; const AOffset: Integer; const ASignature: array of Integer): Boolean;
var
  i: Integer;
begin
  Result := False;
  if (Length(AData) < (AOffset + Length(ASignature))) then
    Exit;
  for i := Low(ASignature) to High(ASignature) do
    if (ASignature[i] <> -1) then
      if (AData[i + AOffset] <> ASignature[i]) then
        Exit;
  Result := True;
end;

function GetBytesFormat(const AData: TBytes): TImageFormat;
var
  Signatures: TSignatures;
  i: Integer;
begin
  Signatures := GetSignatureList;
  for i := Low(Signatures) to High(Signatures) do
    if CompareBytes(AData, Signatures[i].Offset, Signatures[i].Signature) then
      Exit(TImageFormat(Signatures[i].Format));
  Result := TImageFormat.Unknown;
end;

function FilePartToBytes(const AFilename: string; const AOffset, ASize: Integer): TBytes;
var
  FileStream: TFileStream;
begin
  SetLength(Result, 0);
  FileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
  try
    if (FileStream.Size < (AOffset + ASize)) then
      Exit;
    SetLength(Result, ASize);
    FileStream.Position := AOffset;
    FileStream.ReadBuffer(Result[0], ASize);
  finally
    FileStream.Free;
  end;
end;

var
  Data: TBytes;
begin
  try
    if ParamCount > 0 then
      if FileExists(ParamStr(1)) then
        begin
          Data := FilePartToBytes(ParamStr(1), 0, GetMaxSignatureSize(GetSignatureList));
          case GetBytesFormat(Data) of
            TImageFormat.Unknown: WriteLn('Unknown');
            TImageFormat.JPEG: WriteLn('JPEG');
            TImageFormat.BMP: WriteLn('BMP');
            TImageFormat.PNG: WriteLn('PNG');
            TImageFormat.GIF: WriteLn('GIF');
            TImageFormat.TIFF: WriteLn('TIFF');
            TImageFormat.ICO: WriteLn('ICO');
          end;
          ReadLn;
        end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
@schorch666, die Idee den User entscheiden zu lassen mag ich, meine Idee basiert halt auf Signaturen um etwas automatisch anzukicken, wobei ich halt extrem eingeschränkt bin auf die paar Signaturen die man der Definition entnehmen kann, eine Klasse basierend auf dem Wiki wäre halt eine Variante einer möglichen automatisierung, wobei dann immer noch das zutun vom User notwendig sein kann um was-auch-immer-für-ein-format mit was-auch-immer zu öffnen.

himitsu 1. Sep 2023 14:56

AW: wie art der daten in blob erkennen?
 
Das Casten der TSignature war ja nur, weil ich es in einem Byte gespeichert hab.
Im Record kannst da den richtigen Typ benutzen.

Bei DatenRecords erstelle ich mir gern einen/mehrere Constuctor, um sie direkt einzeilig füllen zu können, auch direkt an Varioable/Property/Parameter übergebbar.
Quasi Delphi-Referenz durchsuchenTRect.Create anstatt einer externen Funktion ala Delphi-Referenz durchsuchenRect, bzw. Delphi-Referenz durchsuchenTPoint.Create und Delphi-Referenz durchsuchenPoint.
Schön wäre bestimmt es, wenn Emba hier den Constructor implitit für Casts benutzen würde, also
Delphi-Quellcode:
TSignature(...)
alternativ zu
Delphi-Quellcode:
TSignature.Create(...)
.


Delphi-Quellcode:
  TSignature = packed record
    Format: TSignature;
    Offset: Integer;
    Signature: array of Byte;
    constructor Create(AFormat: TSignature; AOffset: Integer; ASignature: array of Byte);
  end;
  TSignatures = array of TSignature;

function GetSignatureList: TSignatures;
begin
  {
  Result := nil;
  Result := Result + [TSignature.Create(TImageFormat.JPEG, 0, [$FF, $D8, $FF, $DB])];
  Result := Result + [TSignature.Create(TImageFormat.JPEG, 0, [$FF, $D8, $FF, $E0, $00, $10, $4A, $46])];
  ...
  }
  Result := [
    TSignature.Create(TImageFormat.JPEG, 0, [$FF, $D8, $FF, $DB]),
    TSignature.Create(TImageFormat.JPEG, 0, [$FF, $D8, $FF, $E0, $00, $10, $4A, $46]),
    ...
  ];
end;
Ja, der Code wird so weniger optimal, aber vom Code her wird es teilweise schöner.
Man könnte noch schauen, ob es mit einem INLINE; besser wird.

Delphi kennt ja seit 'ner Weile string-like Operatoren, wie man sie von Strings kennt, wie z.B. das
Delphi-Quellcode:
+
.

schorsch666 3. Sep 2023 10:30

AW: wie art der daten in blob erkennen?
 
schoenen sonntag @ALL,
ich habs jetzt so geloest, dass der/die/das user:
- einmal die moeglichkeit hat, mittels "speichern unter" "sein" dateiformat auszuwaehlen. und dann kann er die datei mittels doppelklick selber im entsprechenden "viewer" oeffnen
- und andererseits (fuer die schnelle loesung) auswaehlen kann "als grafik anzeigen" oder "als text anzeigen", denn dem TImage ist es egal, ob die datei ein suffix hat - wird entweder angezeigt oder eben nicht. und je nachdem, was er/sie/es auswaehlt, wird halt eine vorschau in einem TImage gezeigt oder in einem memo.. das muss jetzt erstmal schicken.

P.S.: hat jemand ne idee, wie ich .pdfs/word/excel - zumindest aber .pdf's anzeigen koennte?

also tks...

...de Schorsch

peterbelow 3. Sep 2023 12:24

AW: wie art der daten in blob erkennen?
 
Zitat:

Zitat von schorsch666 (Beitrag 1526426)
P.S.: hat jemand ne idee, wie ich .pdfs/word/excel - zumindest aber .pdf's anzeigen koennte?

Die einfachste Methode ist es, die Daten aus dem BLOB in eine Datei mit der korrekten Extension zu schreiben und diese dann per ShellExecute(Ex) durch Windows in der zugeordneten Anwendung öffnen zu lassen.

Wenn die so erzeugten Dateien nicht auf der Platte bleiben sollen, nachdem der Benutzer sie sich angesehen hat, kann man die Datei per API CreateFile öffnen bevor man sie an ShellExecute übergibt. Dabei spezifiziert man FILE_FLAG_DELETE_ON_CLOSE und FILE_ATTRIBUTE_TEMPORARY in den Flags und hält die Datei offen, bis das Programm beendet wird. Windows löscht die Datei dann automatisch wenn das letzte Filehandle gesschlossen wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:59 Uhr.
Seite 3 von 3     123   

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