2010-12-11 11 views
15

Ho bisogno di comprimere o almeno di 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.C#: ricerca dell'algoritmo di compressione PNG/libreria

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


È così che ho attualmente salvare/convertire le mie immagini:

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

"per .net 4.0 o sotto": scusate, ne ho solo uno per .NET 5.0;) –

+0

Qual è la vostra risposta per .NET 5 per curiosità? – Dylan

+0

Scommetto che ce ne saranno alcuni basati solo su 4.5 :) –

risposta

22

Purtroppo, .NET (e GDI +, che le librerie grafiche .NET sono costruiti su) non supporta i parametri 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 è possibile aggiungere nuovi codec a ciò che .NET può accedere in modo nativo. Microsoft ha lasciato cadere la palla su questo.

Questo significa che le alternative sono, in ordine di masochismo decrescente: 1) implementare una funzione di salvataggio da soli in .NET che implementa RFC 2083, 2) Implementare una funzione di salvataggio in base al largo porting libpng a.NET, 3) Chiama codice non gestito che è stato generato direttamente da libpng

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

+0

Grazie per l'intuizione. –

+0

+1 per chiamare il codice non gestito ... di solito basta usare un processore basato su console. – Tracker1

+0

Che mi dici di FreeImage? – jjxtra

7

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

  • Ridurre il conteggio dei pixel (mediante il downscaling dell'immagine); c'è una perdita evidente di risoluzione qui
  • utilizzando un diverso filtro di precompressione/sgonfiare parametri del compressore (OptiPNG è il mio strumento preferito per scegliere automaticamente la migliore combinazione di filtri/impostazioni del compressore)
  • riducendo la profondità del colore da vero colore a 256 (o meno) i colori vi darà un risparmio di byte consistenti, ma di solito a caro prezzo visiva (soprattutto per le immagini fotografiche)

sembra .NET non hanno un modo integrato per cambiare i filtri di precompressione o parametri del compressore di PNG, quindi dovrai usare una libreria esterna. OptiPNG o uno qualsiasi degli strumenti di ottimizzazione PNG other 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.

Consiglierei contro la riduzione della profondità del colore nello scenario automatizzato che descrivi, perché i risultati possono sembrare davvero terribili (si pensi a GIF retinate di vecchio). (Tuttavia, se stai facendo l'ottimizzazione manuale, guarda su Windows e ImageAlpha su Mac.)

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

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

Questo non è esattamente vero. PNG implementa un concetto di filtri di compressione che vengono utilizzati per ridurre le dimensioni dell'immagine senza perdere la qualità. Non garantisce nulla, ma in alcune situazioni il miglioramento potrebbe essere piuttosto significativo. Puoi leggere qui: http://www.libpng.org/pub/png/pngintro.html – detunized

+0

Ma sono d'accordo con josh3736, il modo più semplice e affidabile sarebbe quello di andare con JPEG. – detunized

+0

@detunized: Sì, ma i filtri di compressione potrebbero non implementare la compressione con perdita, che è ciò che @Shawn sta veramente chiedendo. Ad ogni modo, qualsiasi PNG caricato dai suoi utenti necessariamente avrà già applicato filtri di compressione, quindi non è possibile ridurre ulteriormente le dimensioni del file. – josh3736

0

Sfortunatamente, il processore di immagini .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 servirsi dell'output JPEG.