Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi JPEG CompressionQuality ermitteln (https://www.delphipraxis.net/124880-jpeg-compressionquality-ermitteln.html)

e-gon 26. Nov 2008 20:23


JPEG CompressionQuality ermitteln
 
Hallo,

kennt jemand eine Möglichkeit aus einer JPEG-Grafik die Komprimierungsrate zu ermitteln?

Delphi-Quellcode:
Quality := JPEG.CompressionQuality
geht leider nicht. Quality ist immer 0. Das liegt wahrscheinlich daran, dass die Komprimierung eines JPEGs nicht direkt in der Datei abgelegt wird sondern nur indirekt in die Huffman-Tabelle steht und die eher bescheidene JPEG-Unit nicht in der Lage ist die Qualität zu ermitteln.
Aber vielleicht kennt jemand eine andere Möglichkeit die Komprimierung auszulesen?

Danke für Eure Antwort!

e-gon

e-gon 26. Nov 2008 21:05

Re: JPEG CompressionQuality ermitteln
 
Sorry, hat sich erledigt!
Ich habe vergessen JPEG zu initialisieren... http://www.delphipraxis.net/posting.php?mode=iframe
ouch!

Schwedenbitter 16. Okt 2017 15:42

AW: Re: JPEG CompressionQuality ermitteln
 
Auch wenn das schon etwas älter ist. Ich wärme es auf, weil ich auch gern die Lösung wüsste und es einer der ersten Funde ist, wenn man in der DP und auch bei google sucht. Es wäre daher toll, wenn dann in genau diesem Beitrag eine/die Lösung stünde.

Zitat:

Zitat von e-gon (Beitrag 850930)
Ich habe vergessen JPEG zu initialisieren... http://www.delphipraxis.net/posting.php?mode=iframe

a) Wie geht dieses "initialisieren"? Ich würde auch gern die richtige CompressionQuality in Erfahrung bringen.
b) Der Link funktioniert leider nicht (mehr?), so dass ich das nicht nachvollziehen kann.

TiGü 17. Okt 2017 08:17

AW: JPEG CompressionQuality ermitteln
 
Hast du eine TJPEGImage-Instanz vorzuliegen?
Dann kannst du doch das über die Property auslesen:
http://docwiki.embarcadero.com/Libra...ressionQuality

TiGü 17. Okt 2017 08:39

AW: JPEG CompressionQuality ermitteln
 
Ach guck, das ist ja immer 90?! Das wird anscheinend wirklich gar nicht ausgelesen.

Schwedenbitter 17. Okt 2017 09:03

AW: JPEG CompressionQuality ermitteln
 
Zitat:

Zitat von TiGü (Beitrag 1383484)
Ach guck, das ist ja immer 90?! Das wird anscheinend wirklich gar nicht ausgelesen.

Ich wollte mir gerade die Mühe machen, mal ein paar Bilder mit unterschiedlichen Raten zu packen und Dich die CompressionQuality auslesen zu lassen :twisted:
Das wird nicht ausgelesen, sondern beim Erstellen der Klasse in Create mittels
Delphi-Quellcode:
FQuality := JPEGDefaults.CompressionQuality;
gesetzt. Das wiederum ist eben 90. Wenn man mit der Suche nach FQuality forscht, stellt man schnell fest, dass diese nur gelesen wird. :roll:

TiGü 17. Okt 2017 12:14

AW: JPEG CompressionQuality ermitteln
 
Schade, ich dachte man kann es über WIC und die Metadaten auslesen, aber in meiner Beispieldatei (mit Smartphone gemacht und Paint.NET bearbeitet) gibt es kein Compression-Feld.

Programme wie IrfanView geben ja das richtige aus...hm...grübel!

Kannst ja mal trotzdem versuchen.

Delphi-Quellcode:
uses
  Winapi.Windows, Winapi.Wincodec, Winapi.ActiveX;

...

function GetJpegCompression(const AJpegFilename: string): USHORT;
var
  HR: HRESULT;
  ImagingFactory: IWICImagingFactory;
  Decoder: IWICBitmapDecoder;
  Frame: IWICBitmapFrameDecode;
  MetaDataReader: IWICMetadataQueryReader;
  MetaDataPathName: PWideChar;
  Value: PROPVARIANT;
  IFDReader: IWICMetadataQueryReader;
  Compression: USHORT;

  procedure DebugShowAllPropertyNames(const AMetaDataQueryReader: IWICMetadataQueryReader);
  var
    iValue: Longint;
    Enumerator: IEnumString;
    MetaDataPathName: PWideChar;
  begin
    // Spaßeshalber alle Metadaten auflisten
    iValue := 0;
    HR := AMetaDataQueryReader.GetEnumerator(Enumerator);
    if Succeeded(HR) then
    begin
      while Enumerator.Next(1, MetaDataPathName, @iValue) = S_OK do
      begin
        OutputDebugString(MetaDataPathName);
      end;
    end;
  end;

begin
  Result := 0;
  HR := CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, ImagingFactory);
  if Succeeded(HR) then
  begin
    HR := ImagingFactory.CreateDecoderFromFilename(PChar(AJpegFilename), TGUID.Empty, GENERIC_READ,
      WICDecodeMetadataCacheOnDemand, Decoder);
    if Succeeded(HR) then
    begin
      HR := Decoder.GetFrame(0, Frame);
      if Succeeded(HR) then
      begin
        HR := Frame.GetMetadataQueryReader(MetaDataReader);
        if Succeeded(HR) then
        begin
          // https://msdn.microsoft.com/en-us/library/windows/desktop/ee719904(v=vs.85).aspx#_jpeg_metada

          MetaDataPathName := '/app1/ifd';
          PropVariantInit(Value);
          HR := MetaDataReader.GetMetadataByName(MetaDataPathName, Value);
          if Succeeded(HR) then
          begin
            if Value.vt = VT_UNKNOWN then
            begin
              HR := IUnknown(Value.ppunkVal).QueryInterface(IID_IWICMetadataQueryReader, IFDReader);
              PropVariantClear(Value);
              if Succeeded(HR) then
              begin
                DebugShowAllPropertyNames(IFDReader);

                PropVariantInit(Value);
                // das sollte eigentlich Compression sein -> bei mir leider nicht vorhanden
                MetaDataPathName := '/{ushort=259}';
                HR := IFDReader.GetMetadataByName(MetaDataPathName, Value);
                if Succeeded(HR) then
                begin
                  if Value.vt = VT_UI2 then
                  begin
                    HR := PropVariantToUInt16(Value, Compression);
                    if Succeeded(HR) then
                    begin
                      Result := Compression;
                    end;
                  end;
                end;
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;

TiGü 17. Okt 2017 12:44

AW: JPEG CompressionQuality ermitteln
 
Schade, mit GDI+ komm ich auch nicht ran.

Delphi-Quellcode:
function GdipCheck(const AResult: GPSTATUS): Boolean;
begin
  Result := AResult = GPSTATUS.Ok;
end;

function GdiPlusGetJpegCompression(const AJpegFilename: string): USHORT;
var
  token: ULONG;
  Input: TGdiplusStartupInput;
  Output: TGdiplusStartupOutput;
  status: GPSTATUS;
  image: GpImage;
  size: UINT;
  propertyItemID:PROPID;
  propertyItem: TPropertyItem;  
begin
  Result := 0;
  FillChar(Input, SizeOf(Input), 0);
  Input.GdiplusVersion := 1;
  FillChar(Output, SizeOf(Output), 0);
  GdiplusStartup(token, @Input, @Output);
  try
    status := GdipCreateBitmapFromFile(PChar(AJpegFilename), image);
    if GdipCheck(status) then
    begin  
      propertyItemID := PropertyTagJPEGQuality; // PropertyTagCompression
      status := GdipGetPropertyItemSize(image, propertyItemID, size);
      if GdipCheck(status) then
      begin
        ZeroMemory(@propertyItem, SizeOf(propertyItem));
        status := GdipGetPropertyItem(nil, propertyItemID, size, @propertyItem);
        if GdipCheck(status) then
        begin            
          Result := PWORD(propertyItem.value)^;
        end;
      end;
    end;
  finally
    GdiplusShutdown(token);
  end;
end;

Schwedenbitter 25. Okt 2017 09:15

AW: JPEG CompressionQuality ermitteln
 
Ich habe das - etwas unorthodox - für mich selbst jetzt so gelöst:
Delphi-Quellcode:
Function CalcCompressionQuality(Const JPG: TJPEGImage;
   Const MustFit: Boolean = False): TJPEGQualityRange;
Var
   aMS            : TMemoryStream;
   aBMP            : TBitmap;
   aJPG            : TJPEGImage;
   aSize            : Int64;
   lQ, hQ         : Integer;
   Piv, oldPiv      : Integer;                        // Ausgangswert = 0
Begin
   aMS:= TMemoryStream.Create;                     // TMemoryStream erzeugen
   aBMP:= TBitmap.Create;                           // TBitmap erzeugen
   aJPG:= TJPEGImage.Create;                        // TJPEGImage erzeugen
   Try
      JPG.SaveToStream(aMS);                        // in Stream ablegen
      aSize:= aMS.Size;                              // Originalgröße ermitteln
      aBMP.Assign(JPG);                              // Bild ins TBitmap kopieren
      lQ:=   Low(Result);                           // untere Grenze
      hQ:=   High(Result);                        // obere Grenze
      Piv:= (hQ - lQ) Div 2;                        // in der Mitte anfangen
      Repeat
         aMS.Clear;                                 // Stream leeren
         aJPG.CompressionQuality:= Piv;            // Kompressionsrate setzen
         aJPG.Assign(aBMP);                        // Bitmap kopieren/komprimieren
         aJPG.SaveToStream(aMS);                     // JPG in Stream kopieren
         oldPiv:= Piv;                              // altes Pivot-Element merken
         If (aMS.Size > aSize) Then                  // Ergebnis ist zu groß
         Begin
            hQ:= Piv;                              // obere Grenze = aktueller Wert
            Piv:= Piv - ((hQ -  lQ) Div 2);         // neuen Wert berechnen
         End
         Else Begin                                 // Ergebnis kleiner oder gleich
            lQ:= Piv;                              // untere Grenze = aktueller Wert
            Piv:= Piv + ((hQ - lQ) Div 2);         // neuen Wert berechnen
         End;
      Until (Piv = oldPiv);                        // noch näher geht es nicht

      If (MustFit) And                              // auf keinen Fall größer !!!
         (aMS.Size > aSize) Then                     // immer noch zu groß
            Result:= Pred(Piv)                     //   => eine Nummer kleiner
      Else   Result:= Piv;            // aMS.Size = aSize => exakten Wert übergeben
   Finally
      aMS.Free;                                    // TMemoryStream freigeben
      aBMP.Free;                                    // TBitmap freigeben
      aJPG.Free;                                    // TJPEGImage freigeben
   End;
End;
Vermutlich lässt sich das sogar noch optimieren. Vielleicht findet über die Zeit jemand eine saubere(re) Lösung.

mensch72 25. Okt 2017 09:36

AW: JPEG CompressionQuality ermitteln
 
Die Kompressionsrate eines JPG errechnet sich doch mathematisch rückwärts ganz simpel aus der JPG-Dateigröße im Verhältnis zum Speicherbedarf des RGB-PixelArrays:
x = (JPGfileSize*100%) / (Width*Height*3)

Wer es auf die meist 32Bit(ARGB) Speichergröße von Bitmaps im PC beziehen will rechnet eben mit "x4"
x = (JPGfileSize*100%) / (Width*Height*4)

JPGheader und JPGmetadaten sind genau wie "BitmapInfoHeader" hier zu vernachlässigen, weil es rückwärts eh stets nur eine Näherung ist.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:47 Uhr.
Seite 1 von 3  1 23      

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