![]() |
JPEG CompressionQuality ermitteln
Hallo,
kennt jemand eine Möglichkeit aus einer JPEG-Grafik die Komprimierungsrate zu ermitteln?
Delphi-Quellcode:
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.
Quality := JPEG.CompressionQuality
Aber vielleicht kennt jemand eine andere Möglichkeit die Komprimierung auszulesen? Danke für Eure Antwort! e-gon |
Re: JPEG CompressionQuality ermitteln
Sorry, hat sich erledigt!
Ich habe vergessen JPEG zu initialisieren... ![]() ouch! |
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:
b) Der Link funktioniert leider nicht (mehr?), so dass ich das nicht nachvollziehen kann. |
AW: JPEG CompressionQuality ermitteln
Hast du eine TJPEGImage-Instanz vorzuliegen?
Dann kannst du doch das über die Property auslesen: ![]() |
AW: JPEG CompressionQuality ermitteln
Ach guck, das ist ja immer 90?! Das wird anscheinend wirklich gar nicht ausgelesen.
|
AW: JPEG CompressionQuality ermitteln
Zitat:
Das wird nicht ausgelesen, sondern beim Erstellen der Klasse in Create mittels
Delphi-Quellcode:
gesetzt. Das wiederum ist eben 90. Wenn man mit der Suche nach FQuality forscht, stellt man schnell fest, dass diese nur gelesen wird. :roll:
FQuality := JPEGDefaults.CompressionQuality;
|
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; |
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; |
AW: JPEG CompressionQuality ermitteln
Ich habe das - etwas unorthodox - für mich selbst jetzt so gelöst:
Delphi-Quellcode:
Vermutlich lässt sich das sogar noch optimieren. Vielleicht findet über die Zeit jemand eine saubere(re) Lösung.
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; |
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 14: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