Einzelnen Beitrag anzeigen

TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.062 Beiträge
 
Delphi 10.4 Sydney
 
#20

AW: JPEG CompressionQuality ermitteln

  Alt 26. Okt 2017, 12:42
Die hatte ich schon entdeckt. Mir fehlen im Grunde "nur" 3 Dinge:
  1. Wie speichert man das Originalbild in einen Stream, ohne neu zu komprimieren (zur Ermittlung der Ausgangsgröße)?
  2. Wie setzt man die Kompressionsrate? Das hat EWeiss schon sehr schön gezeigt. Auch wenn das recht kompliziert aussieht. Danke dafür!
  3. Wie speichert man die Datei dieses Mal neu komprimiert testweise in einen Stream und ermittelt dessen Größe? (Also wie 1.)

msdn.microsoft.com ist immer mein erster Anlaufpunkt. Oft haben sie auch Code dabei.
Ich stufe mich selbst aber als Laien - also nix Delpi-Programmierer - ein und versuche trotzdem halbwegs zu verstehen, was ich tue. Und da stolpere ich über so Sachen wie ISTREAM & Co. die scheinbar so gar nichts mit dem mir bekannnten T(Memory)Stream gemeinsam haben. Und ich sehe auch am übersetzten Code von EWeiss, dass es offenbar doch nicht einfacher geht, wie ich es erhofft hatte. Mit GDI+ werden es scheinbar zwangsläufig mehr als die 20 Zeilen...

P.S. Gibt es eine Funktion, mit der man TStatus in String übersetzen lassen kann? Ich kann das auch selbst. Aber wenn es das gibt, muss ich mir nicht die Arbeit machen.
Kann ich auf all diese Fragen und offenen Punkte mit einem Quellcodeschnipsel antworten?
Beim Result musste sehen wie du es brauchst.
Komprimierte Größe im Verhältnis zu unkomprimierte Größe oder andersrum.
Ggf. hauste da noch ne * 100 dazu. Wie du magst.

Delphi-Quellcode:
function GetCompressRatio(const AJpegFilename: string): Double;
var
  Status: Winapi.GDIPAPI.TStatus;
  Image: Winapi.GDIPOBJ.TGPImage;
  OriginalStream, CompressStream: System.Classes.TMemoryStream;
  OriginalStreamAdapter, CompressStreamAdapter: Winapi.ActiveX.IStream;
  ImageFormat, EncoderCLSID: TGUID;
  EncoderParams: Winapi.GDIPAPI.TEncoderParameters;
  SaveQuality: Vcl.Imaging.jpeg.TJPEGQualityRange; // Integer geht natürlich auch!
begin
  Result := 0;
  OriginalStream := TMemoryStream.Create;
  CompressStream := TMemoryStream.Create;

  // mit soOwned räumt der TStreamAdapter den TMemoryStream auf
  OriginalStreamAdapter := TStreamAdapter.Create(OriginalStream, soOwned);
  CompressStreamAdapter := TStreamAdapter.Create(CompressStream, soOwned);

  Image := Winapi.GDIPOBJ.TGPImage.Create(AJpegFilename);
  try
    if Assigned(Image) and (Image.GetWidth > 0) and (Image.GetHeight > 0) then
    begin
      Status := Image.GetRawFormat(ImageFormat);
      if (Status = TStatus.Ok) and (ImageFormat = ImageFormatJPEG) then
      begin
        if Winapi.GDIPUTIL.GetEncoderClsid('image/jpeg', EncoderCLSID) > -1 then
        begin
          // Bild OHNE Komprimierung im Stream speichern
          Status := Image.Save(OriginalStreamAdapter, EncoderCLSID);
          OutputDebugString(PWideChar(Winapi.GDIPUTIL.GetStatus(Status)));

          SaveQuality := 50; // oder was du magst für die Kompressionsrate

          FillChar(EncoderParams, SizeOf(EncoderParams), 0);
          EncoderParams.Count := 1;
          EncoderParams.Parameter[0].Guid := EncoderQuality;
          EncoderParams.Parameter[0].NumberOfValues := 1;
          EncoderParams.Parameter[0].Type_ := EncoderParameterValueTypeLong;
          EncoderParams.Parameter[0].Value := @SaveQuality;

          // Bild MIT Komprimierung im Stream speichern
          Status := Image.Save(CompressStreamAdapter, EncoderCLSID, @EncoderParams);
          OutputDebugString(PWideChar(Winapi.GDIPUTIL.GetStatus(Status)));

          Result := CompressStream.Size / OriginalStream.Size;
        end;
      end
      else
        OutputDebugString(PWideChar(Winapi.GDIPUTIL.GetStatus(Status)));
    end;
  finally
    Image.Free;
  end;
end;

Geändert von TiGü (26. Okt 2017 um 12:45 Uhr)
  Mit Zitat antworten Zitat