2016-05-03 29 views
0

Um Datei-Upload-Größen auf einen Webservice zu reduzieren, begrenzen wir die Höhe/Breite von Bilddateien auf einen maximalen Wert.
Für JPG-Dateien funktioniert das gut: eine (nach unten) Bildgrößenänderung führt zu einer reduzierten Dateigröße.Größe des PNG-Speichers reduzieren

Nicht so für PNG-Dateien, aber: in den meisten Fällen unseres Code führt größere Dateigrößen:

procedure TFrmImageCheckAndResize.ResizePNGImage; 
var 
    lSrcPNGImage, lTrgPNGImage: TdxPNGImage; 
    lSrcBitmap,lDestBitMap: TcxAlphaBitmap; 
    lNewWidth,lNewHeight: Integer; 
    lFactor: Real; 
begin 
    lSrcPNGImage := TdxPNGImage.Create; 
    lSrcPNGImage.LoadFromFile(FFileName); 
    lSrcBitmap := TcxAlphaBitmap.CreateSize(lSrcPNGImage.Width, lSrcPNGImage.Height, True); 
    lSrcBitmap.Canvas.Draw(0, 0, lSrcPNGImage); 
    if lSrcPNGImage.Width > lSrcPNGImage.Height then 
    if lSrcPNGImage.Width > FEditImageRes.Value then 
     lFactor := lSrcPNGImage.Width 
    else 
     lFactor := 0 
    else 
    if lSrcPNGImage.Height > FEditImageRes.Value then 
     lFactor := lSrcPNGImage.Height 
    else 
     lFactor := 0; 
    if lFactor <> 0 then 
    begin 
    lFactor := lFactor/FEditImageRes.Value; 
    lNewWidth := Trunc(lSrcPNGImage.Width/lFactor); 
    lNewHeight := Trunc(lSrcPNGImage.Height/lFactor); 
    lDestBitMap := TcxAlphaBitmap.CreateSize(lNewWidth,lNewHeight, True); 
    cxSmoothResizeBitmap(lSrcBitMap, lDestBitMap, true); 
    lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lDestBitmap); 
    end 
    else 
    begin 
    lDestBitmap := nil; // Silence the compiler 
    lTrgPNGImage := TdxPNGImage.CreateFromBitmap(lSrcBitmap); 
    end; 
    lTrgPNGImage.SaveToFile(StringReplace(FFileName,'.','_' + IntToStr(FEditImageRes.Value) + '.',[])); 
    lSrcBitmap.Free; 
    lDestBitmap.Free; 
    lTrgPNGImage.Free; 
    lSrcPNGImage.Free; 
end; 

FFileName ist das Bild von der Festplatte geladen, FEditImageRes.Value enthält die größte Dimension, die wir zu reduzieren.

Beachten Sie, dass wir Developer Express-Komponenten verwenden und dass dieser Code Alphakanal (Transparenz) beibehält.
Ich bin nicht an beides gebunden.

Ich habe eine ticket with DevExpress gepostet, aber es ist kein Problem in ihrem Code.

Ich sah, was andere Software tut:

enter image description here

In Paint.Net, wenn ich die oben 890 * 161 Screenshot 512 * 93 reduziere ich gemischte Ergebnisse sehen auf dem Algorithmus in Abhängigkeit verwendet für die Größe ändern:

15.697 Original.png 
21.904 Resized_BiCubic.png 
19.995 Resized_Bilineair.png 
22.905 Resized_Fant.png 
6.729 Resized_NearestNeigbour.png 

enter image description here

Für dieses Foto 550x386 auf 512 reduziert * 353 die Paint.Net Ergebnisse sind:

375.229 Photo.png 
419.122 Photo_Bicubic.png 
402.277 Photo_Bilineair.png 
407.959 Photo_Fant.png 
416.619 Photo_NearestNeighbor.png 

So ist es ziemlich unvorhersehbar sieht, was die Ergebnisse sein werden.

Frage:
Gibt es etwas, was ich tun kann (Änderung an meinem Code), um sicherzustellen, dass (am meisten) resized PNG-Dateien tatsächlich eine reduzierte Dateigröße haben?

+2

PNG sieht wie das falsche Format für das Bild aus, sollte JPG –

+0

sein Die Komprimierung ist verlustfrei. Wenn Sie die Größe reduzieren, behält ein feiner Algorithmus mehr Informationen bei - eine große Dateigröße mit einem schärferen Bild. Ein grober Algorithmus behält weniger Informationen bei, ein weicheres - verschwommenes Bild mit geringerer Dateigröße. Sie müssen sich auf einen Algorithmus festlegen, der visuell ungefähr die gleiche Schärfe wie das Originalbild aufweist, das eine kleinere Dateigröße erzeugen sollte, ohne das Bild zu beschädigen. Wenn die Bilder vom gemischten Typ sind (z. B. Grafik gegen Foto), wäre dies unmöglich. –

+0

Wird photo.png in paint.net gespeichert? Wenn nicht, ist dieser Vergleich nicht gültig. –

Antwort

3

Einige Regeln, wie kleinste Bildgröße erhalten möglich mit TPngImage von vcl.imaging.PngImage

Erstens ist es CompressionLevel Eigenschaft hat, können Sie Integer-Wert gesetzt 0..9, 0 ist keine Kompression ar alle, 9 beste Kompression (aber langsamste). Standardmäßig ist 7 eingestellt. Hinweis: PNG ist immer verlustfrei, diese Einstellung wirkt sich nur auf die Zeit aus, die zum Speichern des Bildes benötigt wird.

Zweitens gibt es Filters Eigenschaft, standardmäßig ist der Wert [pfSub], aber um die beste Komprimierung zu erreichen, sollten Sie es auf [pfNone, pfSub, pfUp, pfAverage, pfPaeth] setzen.Dies sind Vorhersagefilter, die auf jede Bildzeile angewendet werden, um die Korrelation zwischen Nachbarn zu verwenden, um eine bessere Komprimierung zu erhalten. Wenn alle Filter eingestellt sind, wird jeder versucht und der beste wird verwendet.

Stellen Sie sicher, dass die Eigenschaft InterlaceMethod auf imNone festgelegt ist. Vielleicht wurden Ihre Originalbilder interlaced, in diesem Fall ist die Dateigröße um 5,20% im Vergleich zu Nicht-Interlaced erhöht.

Es gibt eine weitere Möglichkeit, niedrigere Bildgröße zu bekommen, das ist MaxIDATSize Eigenschaft zu Wert ein wenig mehr als Ihre Bildgröße zu erhöhen. Punkt ist, PNG-Pixeldaten werden in einem oder mehreren IDAT-Chunks gespeichert, jeder hat 4 Bytes seiner Größe, dann 4 Bytes seines Namens ('IDAT'), dann Daten und dann 4 Bytes CRC. Standardmäßig ist die Größe jedes Chunks 65535 Byte. In einem großen Bild haben Sie also viele davon und in 12 Byte pro Stück Abfall. Aber Anstieg ist hier sehr klein, 0,2%, nicht so sehr.

In der Tat macht PNGImage mit solchen Einstellungen ziemlich kleine Dateien, normalerweise 10..20% kleiner als Paint.NET, aber spezialisierte Programme können PNG noch besser komprimieren.

Über Größenanpassung. Wenn Sie versuchen, die Größe von Screenshots zu ändern, ist eine größere Datei oft der Fall. Original-Screenshot hat wenige Farben, in Ihrem Fall ist es 431, sehr wegen der Farbverläufe. Es gibt große Bereiche gleicher Farbe, die sehr gut gespeichert sind. Nach der Größenänderung ist jeder scharfe Übergang von einer Farbe zu einer anderen verschwommen, so dass mehr "gemischte" Farben erzeugt werden, es ist wirklich schwieriger zu komprimieren. Wie Sie sehen, ergibt der nächste Nachbar die kleinste Dateigröße, weil er keine neuen Farben erzeugt, die nicht bereits im Originalbild waren.

Ihr zweites Beispiel, 550x386 Foto muss niedrigere Dateigröße nach der Größenanpassung haben, und tatsächlich habe ich es geschafft, Größe auf 512x353 Foto auf 303 kB komprimiert zu komprimieren. Paint.net verwendet überhaupt keine Vorhersagefilter, deshalb hat es eine schreckliche Komprimierung von Fotos und anderen echten Farbbildern.