C #: ricerca dell’algoritmo di compressione PNG / libreria

Devo comprimere o almeno eliminare la qualità di alcune immagini PNG che gli utenti stanno caricando sul mio sito. L’ho già ridimensionato ma ciò non fa molto per le dimensioni dell’immagine.

Ricerca di un algoritmo di compressione png / immagine o perdita di qualità o libreria per .net 4.0 o inferiore.


Ecco come attualmente salverò / convertirò le mie immagini:

Image mainImg = ImageHelper.ResizeImage(bmp, 600, 500, false); mainImg.Save(filePath, System.Drawing.Imaging.ImageFormat.Png); 

Sfortunatamente, .NET (e GDI +, su cui sono basate le librerie grafiche .NET) non supporta alcun parametro di codifica per PNG. Infatti, se chiami GetEncoderParameterList sull’immagine con il codificatore PNG Clsid, riceverai un’eccezione “Non implementata”.

Ancora più sfortunato è che sia ImageFormat che ImageCodecInfo sono classi sigillate e non è ansible aggiungere nuovi codec a ciò che .NET può accedere in modo nativo. Microsoft ha lasciato cadere la palla su questo.

Ciò significa che le tue alternative sono, in ordine decrescente di masochismo: 1) Implementare una funzione di salvataggio da sola in .NET che implementa RFC 2083, 2) Implementare una funzione di salvataggio basata sul porting di libpng su .NET, 3) Chiamare il codice non gestito che era costruito direttamente da libpng

libpng ha una grande documentazione ed è gratuito, sia in termini di disponibilità che di licenza.

Il PNG è generalmente uno schema di compressione senza perdita di dati , il che significa che la qualità dell’immagine non viene mai ridotta a meno che non si riduca il numero di pixel (dimensione) o la profondità del colore. Esistono tre modi per ridurre le dimensioni del file delle immagini PNG:

  • Riduci il numero di pixel (ridimensionando l’immagine); c’è un’evidente perdita di risoluzione qui
  • Utilizzo di filtri diversi di precompressione / parametri del compressore DEFLATE ( OptiPNG è il mio strumento preferito per scegliere automaticamente la migliore combinazione di filtri / impostazioni del compressore)
  • Riducendo la profondità del colore dal vero colore a 256 (o meno) colors si otterrà un notevole risparmio di byte, ma di solito a grandi costi visivi (specialmente per le immagini fotografiche)

Sembra che .NET non abbia un modo integrato per cambiare i filtri di precompressione o i parametri di compressione dei PNG, quindi dovrai usare una libreria esterna. OptiPNG o uno degli altri strumenti di ottimizzazione PNG non sono librerie native .NET, quindi dovrai affrontare P / Invocare le librerie o eseguire un processo separato per … elaborare ogni immagine. Tuttavia, stai spesso osservando un risparmio intorno al 5% o meno (anche se ne ho visto fino al 40%) poiché questo è in definitiva un processo senza perdita di dati.

Ti consiglio di non ridurre la profondità del colore nello scenario automatizzato che descrivi, perché i risultati possono sembrare davvero terribili (si pensi alle vecchie GIF retinate). (Tuttavia, se stai facendo l’ottimizzazione manuale, guarda Color Quantizer su Windows e ImageAlpha su Mac.)

Realisticamente, il modo migliore per ridurre le dimensioni del file a scapito della qualità è convertirlo in JPEG, che non richiede dipendenze esterne ed è progettato per essere un algoritmo di compressione con perdita:

 mainImg.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg); // make sure you change `filePath` to end with jpg instead of png. 

Sfortunatamente, l’image processor di .Net per png non eseguirà alcuna euristica di ottimizzazione sull’output. La soluzione migliore è avere un file binario optipng / pngcrush disponibile sul server, rendere l’output ridimensionato su un file temporaneo, quindi utilizzare pngcrush su di esso tramite System.Diagnostics.Process.

Per la maggior parte, se i caricamenti sono fotografie e il formato originale è JPEG, sarà meglio servirti utilizzando l’output JPEG.