Einzelnen Beitrag anzeigen

Benmik

Registriert seit: 11. Apr 2009
542 Beiträge
 
Delphi 11 Alexandria
 
#56

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

  Alt 8. Jul 2020, 10:55
Hier noch die Verwendung von GDI+. Nur einfaches Beispiel, ohne Ressourcenschutz oder Ähnliches. Leider bietet die Save-Procedure nicht die Option des Überschreibens, daher ein bisschen Nachbau. GDI+ ist sehr schnell. Zu beachten ist, dass hier die Blockgröße 16 Pixel beträgt, Höhe/Breite also ein Vielfaches von 16 sein müssen.
Frustrierend ist, dass GDI+ als 32-Bit-DLL natürlich wieder mal nicht in 64-Bit-Anwendungen benutzt werden kann.
Delphi-Quellcode:
uses ... GDIPAPI, GDIPOBJ,GDIPUTIL;

procedure DreheMitGDIPlus1;
Var i:integer;
  DatListe:TStringDynArray;
  GPImage: TGPImage;
  EncoderCLSID: TGUID;
  Ergebnis : Status;
  TempDatname:string;
const
  Verz = 'C:\Test\';
begin
  DatListe := TDirectory.GetFiles(Verz,'*.jpg');
  GetEncoderClsid('image/jpeg', EncoderCLSID);
  For i := 0 to High(DatListe) do begin
    GPImage := TGPImage.Create(DatListe[i]);
    GPImage.RotateFlip(Rotate90FlipNone);
    TempDatname := TPath.ChangeExtension(DatListe[i],'$$$');
    Ergebnis := GPImage.Save(TempDatname,EncoderCLSID);
    GPImage.Free;
    If Ergebnis = Ok then begin
      If DeleteFile(DatListe[i])
        then RenameFile(TempDatname,DatListe[i])
        else DeleteFile(TempDatname);
    end;
  end;
end;
Die nachfolgende Version ist die "volle". An ihr ist besonders interessant, dass sie nicht nur selbständig ermittelt, ob das JPG überhaupt gedreht werden muss, sondern auch den Zugriff auf weitere GDI-Funktionen bietet. Auch kann außer dem PropertyTagOrientation noch eine Vielzahl von weiteren EXIF-Markern ausgelesen werden.
Delphi-Quellcode:
uses ... GDIPAPI, GDIPOBJ,GDIPUTIL;

procedure DreheMitGDIPlus2;
Var i:integer;
  DatListe:TStringDynArray;
  GPImage: TGPImage;
  PPropItem: PPropertyItem;
  BufferSize: Cardinal;
  Orientation: Byte;
  RotateBy: EncoderValue;
  EncoderCLSID: TGUID;
  EncoderParams: TEncoderParameters;
  EncoderTransformValue:integer;
  Ergebnis : Status;
  TempDatname:string;
const
  Verz = 'C:\Test\';
begin
  DatListe := TDirectory.GetFiles(Verz,'*.jpg');
  GetEncoderClsid('image/jpeg', EncoderCLSID);
  FillChar(EncoderParams, SizeOf(EncoderParams), 0);
  EncoderParams.Count := 1;
  EncoderParams.Parameter[0].Guid := EncoderTransformation;
  EncoderParams.Parameter[0].Type_ := EncoderParameterValueTypeLong;
  EncoderParams.Parameter[0].NumberOfValues := 1;
  For i := 0 to High(DatListe) do begin
    GPImage := TGPImage.Create(DatListe[i]);
    BufferSize := GPImage.GetPropertyItemSize(PropertyTagOrientation);
    If BufferSize > 0 then begin
      GetMem(PPropItem, BufferSize);
      Try
        GPImage.GetPropertyItem(PropertyTagOrientation, BufferSize, PPropItem);
        Orientation := PByte(PPropItem.value)^;
        case Orientation of
          3: RotateBy := EncoderValueTransformRotate180;
          6: RotateBy := EncoderValueTransformRotate90;
          8: RotateBy := EncoderValueTransformRotate270;
          else Continue;
        end;
        If (Orientation in [3,6,9]) then begin
          EncoderTransformValue := Ord(RotateBy);
          EncoderParams.Parameter[0].Value := @EncoderTransformValue;
          TempDatname := TPath.ChangeExtension(DatListe[i],'$$$');
          Ergebnis := GPImage.Save(WideString(TempDatname),EncoderCLSID,@EncoderParams);
          GPImage.Free;
          If Ergebnis = Ok then begin
            If DeleteFile(DatListe[i])
              then RenameFile(TempDatname,DatListe[i])
              else DeleteFile(TempDatname);
          end;
        end;
      Finally
        FreeMem(PPropItem);
      end;
    end;
  end;
end;

Geändert von Benmik ( 8. Jul 2020 um 14:50 Uhr) Grund: Blockgröße 16 Pixel
  Mit Zitat antworten Zitat