AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi JPG-Datei drehen und speichern -> Verlust der Exif-Daten
Thema durchsuchen
Ansicht
Themen-Optionen

JPG-Datei drehen und speichern -> Verlust der Exif-Daten

Ein Thema von axelf98 · begonnen am 3. Sep 2005 · letzter Beitrag vom 22. Aug 2021
Antwort Antwort
Willie1

Registriert seit: 28. Mai 2008
742 Beiträge
 
Delphi 10.1 Berlin Starter
 
#1

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 20. Jul 2020, 11:19
Delphi-Quellcode:
  PropertyItem = record // NOT PACKED !!
    id : PROPID; // ID of this property
    length : ULONG; // Length of the property value, in bytes
    type_ : WORD; // Type of the value, as one of TAG_TYPE_XXX
    value : Pointer; // property value
  end;
  TPropertyItem = PropertyItem;
  PPropertyItem = ^TPropertyItem;
Bei Orientation ist Type_ : PropertyTagTypeShort = 3 entspricht Word.

Ich bin Hobbyprogrammierer, ich kann mich irren. W.
Gut hören kann ich schlecht, schlecht sehen kann ich gut - Ersteres stimmt nicht, das zweite schon.
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#2

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 20. Jul 2020, 14:08
Ich bin Hobbyprogrammierer, ich kann mich irren.
Das kenn ich!

Du hast recht, das hat der gute Boian Mitov geändert. Im Original-EXIF haben alle Einträge eine 12-Byte-Struktur, wovon die letzten 4 Bytes die Werte (oder den Offset) beinhalten. Vermutlich gibt es keine numerischen Werte, die die Grenzen eines Word überschreiten.

Eins muss man in der Unit IGDIPlus noch ändern: Ist ein Tag nicht vorhanden, dann gibt es eine Warnung. Das kann man bei 3.000 JPGs nicht wollen.

Geändert von Benmik (20. Jul 2020 um 14:12 Uhr)
  Mit Zitat antworten Zitat
Willie1

Registriert seit: 28. Mai 2008
742 Beiträge
 
Delphi 10.1 Berlin Starter
 
#3

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 20. Jul 2020, 16:08
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.
Gut hören kann ich schlecht, schlecht sehen kann ich gut - Ersteres stimmt nicht, das zweite schon.

Geändert von Willie1 (20. Jul 2020 um 16:26 Uhr)
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#4

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 20. Jul 2020, 19:59
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.

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.
  Mit Zitat antworten Zitat
Willie1

Registriert seit: 28. Mai 2008
742 Beiträge
 
Delphi 10.1 Berlin Starter
 
#5

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 21. Jul 2020, 15:39
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.
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#6

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 31. Jul 2020, 17:36
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 EncoderTransformValue den Typ von Integer zu 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;
  Mit Zitat antworten Zitat
MartinK

Registriert seit: 21. Jun 2009
Ort: Germering (Germany)
89 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#7

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 20. Aug 2021, 16:29
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?
Martin Kuhn
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
578 Beiträge
 
Delphi 12 Athens
 
#8

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 22. Aug 2021, 00:01
Hilft dir das hier weiter?
  Mit Zitat antworten Zitat
MartinK

Registriert seit: 21. Jun 2009
Ort: Germering (Germany)
89 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#9

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 22. Aug 2021, 09:47
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;
Martin Kuhn
  Mit Zitat antworten Zitat
MartinK

Registriert seit: 21. Jun 2009
Ort: Germering (Germany)
89 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#10

AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten

  Alt 22. Aug 2021, 10:08
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
Martin Kuhn
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:57 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