Delphi-PRAXiS
Seite 8 von 8   « Erste     678   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi JPG-Datei drehen und speichern -> Verlust der Exif-Daten (https://www.delphipraxis.net/52770-jpg-datei-drehen-und-speichern-verlust-der-exif-daten.html)

Willie1 20. Jul 2020 16:08

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Hallo Bennik,
den Umstieg auf die neue GDI+ Bibliothek kann ich mit meinen Augen nicht leisten. Die Variablennamen sind alle anders, dass schaffe ich nicht! Ich muss beim alten GDI+ bleiben.

PGPPropertyItem erkennt mein Compiler nicht, obwohl ich GDIPlus und GDPlusHeelpers eingebunden habe.

Dein Programm müsste ich wieder zurück anpassen.

Benmik 20. Jul 2020 19:59

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Das tut mir leid, dass du so Probleme mit deinen Augen hast. Du musst ja auch keineswegs umsteigen. Die GDI+-Bibliothek bleibt ja gleich, es ist nur der Delphi-Wrapper, der bei Mitov etwas moderner und bequemer ist.

Zitat:

Zitat von Willie1 (Beitrag 1469932)
PGPPropertyItem erkennt mein Compiler nicht...

Das liegt an der fehlenden Einbindung von IGDIPlus.pas von Mitov. Den Link hatte ich ja angegeben.

Kennst du das Tastenkürzel STRG + SHIFT + E für das Refaktorisieren von Bezeichnern aller Art? Damit erleichtert man sich die Arbeit. Aber wie gesagt, wenn du bei der "alten" Art bleibst, verlierst du nichts an Funktionalität oder Geschwindigkeit.

Willie1 21. Jul 2020 15:39

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Ich werde mich einarbeiten.
Da ich meine Bilder grundsätzlich nicht drehe und inzwischen fast alle Programme das Drehen nach dem Or.-Tag ausführen, vermisse ich das richtige Drehen nicht.
Ich werde es mit RotateFlip machen. Nur zur Anzeige reicht das.
W.

Benmik 31. Jul 2020 17:36

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Ich habe die Prozedur zum Drehen von JPG an zwei Stellen verbessert.

Zum einen ist es das Auslesen des EXIF-Datums, das jetzt ordentlich geschieht.

Zum anderen habe ich bemerkt, dass der Code bei 64-Bit-Apps nicht funktionierte. Das war mir zunächst ein Rätsel, da es keinerlei Fehlermeldung gab, die DLL ganz offensichtlich korrekt angesteuert und auch die Datei verlustfrei neu gespeichert wurde; nur gedreht wurde sie nicht! Erst als ich auf die Idee kam, bei
Delphi-Quellcode:
EncoderTransformValue
den Typ von
Delphi-Quellcode:
Integer
zu
Delphi-Quellcode:
NativeInt
zu ändern, ging es plötzlich. (Das erinnert mich an Sir Rufo: Kaum macht man's richtig, schon funktioniert's!)
Delphi-Quellcode:
uses ... IGDIPlus;

procedure DreheMitIGDIPlus;
Var i:integer;
  Orientation: UInt32;
  EXIFDatum:TDateTime;
  DatListe:TStringDynArray;
  IGDPImage: IGPImage;
  PPropOItem,PPropDItem: PGPPropertyItem;
  PropBufferSize,DateBufferSize: Cardinal;
  DreheXGrad: TIGPEncoderValue;
  EncoderParams: TIGPEncoderParameters;
  EncoderTransformValue:NativeInt; // NICHT integer, sonst keine Funktion bei 64-Bit-Apps!
  TempDatname:string;
  EncoderCLSID: TGUID;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  procedure Initialisiere;
  begin
    PropBufferSize := 0;
    PPropOItem := nil;
    EncoderParams.Count := 1;
    EncoderParams.Parameter[0].Guid := EncoderTransformation;
    EncoderParams.Parameter[0].DataType := EncoderParameterValueTypeLong;
    EncoderParams.Parameter[0].NumberOfValues := 1;
    GetEncoderClsid('image/jpeg', EncoderCLSID);
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  function BufferGesetzt:Boolean;
  begin
    If (PropBufferSize > 0) and (DateBufferSize > 0)
      then exit(True);
    PropBufferSize := IGDPImage.GetPropertyItemSize(GPPropertyTagOrientation);
    If PropBufferSize > 0
      then GetMem(PPropOItem, PropBufferSize);
    DateBufferSize := IGDPImage.GetPropertyItemSize(GPPropertyTagDateTime);
    If DateBufferSize > 0
      then GetMem(PPropDItem, DateBufferSize);
    Result := (PropBufferSize > 0) and (DateBufferSize > 0);
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  function BestimmeRotation(var DreheXGrad:TIGPEncoderValue):Boolean;
  var Orientation: UInt32;
  begin
    IGDPImage.GetPropertyItem(GPPropertyTagOrientation, PropBufferSize, PPropOItem);
    Orientation := PUInt32(PPropOItem.value)^;
    Case Orientation of
      3: DreheXGrad := EncoderValueTransformRotate180;
      6: DreheXGrad := EncoderValueTransformRotate90;
      8: DreheXGrad := EncoderValueTransformRotate270;
      else DreheXGrad := TIGPEncoderValue(100); // zum Testen "else DreheXGrad := EncoderValueTransformRotate90;" , wenn man keine Hochkant-Bilder hat
    end;
    Result := (DreheXGrad in [EncoderValueTransformRotate90..EncoderValueTransformRotate270]);
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  function BestimmeEXIFDatum:TDateTime;
  var i:Cardinal; DateOrig: array of Byte; TxtEXIFDatum:string;
  begin
    IGDPImage.GetPropertyItem(GPPropertyTagDateTime, DateBufferSize, PPropDItem);
    SetLength(DateOrig,DateBufferSize);
    Move(PPropDItem.Value,DateOrig[1],DateBufferSize);
    // DateBufferSize ist immer deutlich größer als die 19 Bytes des Datumeintrags. Die Byteanzahl vor dem Eintrag ist nicht konstant.
    i := 0;
    While i < (DateBufferSize - PPropDItem.Length) do begin
      // Format des Datumseintrags ist JJJJ:MM:TT HH:MM:SS - die 4 Doppelpunkte stehen in normiertem Abstand zueinander
      If (DateOrig[i] = $3A) and (DateOrig[i + 3] = $3A) and (DateOrig[i + 9] = $3A) and (DateOrig[i + 12] = $3A)
        then break;
      Inc(i);
    end;
    TxtEXIFDatum := Copy(TEncoding.ASCII.GetString(DateOrig),i - 3,19);
    Try
      Result :=
        EncodeDate(StrToInt(Copy(TxtEXIFDatum, 1, 4)),StrToInt(Copy(TxtEXIFDatum, 6, 2)),StrToInt(Copy(TxtEXIFDatum, 9, 2))) +
        EncodeTime(StrToInt(Copy(TxtEXIFDatum, 12, 2)),StrToInt(Copy(TxtEXIFDatum, 15, 2)),StrToInt(Copy(TxtEXIFDatum, 18, 2)), 0);
    Except
      Result := 0;
    End;
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  function SpeichereJPG:Boolean;
  begin
    Result := False;
    TempDatname := TPath.ChangeExtension(DatListe[i],'$$$');
    If TFile.Exists(TempDatname)
      then exit;
    IGDPImage.Save(WideString(TempDatname),EncoderCLSID,@EncoderParams);
    IGDPImage := nil;
    If TFile.Exists(TempDatname) then begin
      Result := DeleteFile(DatListe[i]);
      If Result
        then Result := RenameFile(TempDatname,DatListe[i])
        else DeleteFile(TempDatname);
    end;
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  function SetzeDatumAufEXIF(Datname:string;EXIFDatum:TDateTime):Boolean;
  begin
    Result := True;
    Try
      TFile.SetCreationTime(Datname,EXIFDatum);
      TFile.SetLastWriteTime(Datname,EXIFDatum);
    Except
      Result := False;
    End;
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
  procedure RäumeAuf;
  begin
    FreeMem(PPropOItem);
    FreeMem(PPropDItem);
    IGDPImage := nil;
  end;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
begin
  Initialisiere;
  Try
    DatListe := TDirectory.GetFiles(Verz,'*.jpg');
    For i := 0 to High(Datliste) do begin // zum Testen auf "0 to 0" setzen
      IGDPImage := TIGPImage.Create(DatListe[i]);
      If not BufferGesetzt
        then exit;
      EXIFDatum := BestimmeEXIFDatum;
      If BestimmeRotation(DreheXGrad) then begin
        EncoderTransformValue := Ord(DreheXGrad);
        EncoderParams.Parameter[0].Value := @EncoderTransformValue;
        Orientation := 1; // zum Testen z.B. auf 3 setzen, wenn man keine Hochkant-Bilder hat
        PPropOItem.Value := @Orientation;
        IGDPImage.SetPropertyItem(PPropOItem^);
        If not SpeichereJPG
          then exit;
        SetzeDatumAufEXIF(DatListe[i],EXIFDatum);
      end;
      IGDPImage := nil;
    end;
  Finally
    RäumeAuf;
  end;
end;

MartinK 20. Aug 2021 16:29

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Da sind einige sehr wertvolle Infos für mich in diesem Thread.

Ich bräuchte noch mindestens ein weiteres Feature und tue mich leider mit dem interpretieren der IGDIPlus.pas leider schwer.

Ich möchte vor dem speichern mit "IGDPImage.Save" gerne noch die Kompressionsrate/Qualität angeben.
Hat hierzu jemand weiter Infos oder kann mir einen Tipp geben?

Benmik 22. Aug 2021 00:01

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Hilft dir das hier weiter?

MartinK 22. Aug 2021 09:47

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Herzlichen Dank Benmik. Das hilft mir schon um einiges weiter.
Ein Problem gelöst .... nächstes aufgetaucht ;)

Die Encoder Parameter sind nur ein Array von 0..0

TIGPEncoderParameters = packed record
Count : UINT; // Number of parameters in this structure
Parameter : array[0..0] of TIGPEncoderParameter; // Parameter values
end;

Wenn ich jetzt mehrere Parameter in einem Rutsch definieren will, also zB "Orientierung" und "SaveQuality" geht das entsprechend nicht.
Oder irre ich mich da?

Finde es auch seltsam das es extra so etwas gibt wie ...
EncoderParameters.Count := 1;

MartinK 22. Aug 2021 10:08

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
und falls sich noch jemand anders ausser mir ebenfalls schwertut die selbstverfasste Wiki des Autors in den Weiten des WWW zu finden

http://www.mitov.com/wiki/index.php?...IPlus.IGPImage

Benmik 22. Aug 2021 20:18

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
 
Leider bin ich zurzeit nur beschränkt aktionsfähig; Internet z.B. nur über Handy, daher kann ich nur eingeschränkt Auskunft geben.

Denke daran, dass Mitov und Konsorten nur Wrapper für GDIPlus sind; bei Fragen kannst du also auch bei MSN nachschauen. Ich hatte damals dermaßen viele Wege ausprobiert, dass ich selbst erst nachschauen musste, für welche Variante ich mich eigentlich entschieden hatte. Wie ich jetzt sehe, ist es GdiPlus von Erik van Bilsen geworden (2009), allerdings modifiziert; ich habe dieses furchtbare GdiCheck, das bei der geringsten Kleinigkeit eine Exception ausgelöst hat, durch die Rückgabe des Status ersetzt (wie im Original von Microsoft). Warum Eric und nicht mehr Mitov, weiß ich nicht mehr.

Bei van Bilsen sehe ich, dass Add eine Menge von Überladungen hat; bei einer kann als Parameter auch ein Array von Parametern übergeben werden; das Argument ist dann ein Pointer auf das erste Arrayitem. Das müsste bei Mitov genauso sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:17 Uhr.
Seite 8 von 8   « Erste     678   

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