![]() |
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. |
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:
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. |
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. |
AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
Ich habe die
![]() 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:
den Typ von
EncoderTransformValue
Delphi-Quellcode:
zu
Integer
Delphi-Quellcode:
zu ändern, ging es plötzlich. (Das erinnert mich an Sir Rufo: Kaum macht man's richtig, schon funktioniert's!)
NativeInt
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; |
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? |
AW: JPG-Datei drehen und speichern -> Verlust der Exif-Daten
Hilft dir
![]() |
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; |
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
![]() |
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 09:13 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