C #: Buscando algoritmo de compresión PNG / biblioteca

Necesito comprimir o, al menos, disminuir la calidad de algunas imágenes png que los usuarios están cargando en mi sitio. Ya lo redimensioné pero eso no hace mucho por el tamaño de la imagen.

Se busca una compresión png / compresión de imagen o un algoritmo o biblioteca de pérdida de calidad para .net 4.0 o menos.


Así es como actualmente guardo / convierto mis imágenes:

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

Desafortunadamente, .NET (y GDI +, en el que están comstackdas las bibliotecas de gráficos .NET) no admite ningún parámetro de encoding para PNG. De hecho, si llama a GetEncoderParameterList en su imagen con el codificador PNG Clsid, obtendrá una excepción “No implementado”.

Aún más desafortunado es que tanto ImageFormat como ImageCodecInfo son clases selladas y no se puede simplemente agregar nuevos códecs a lo que .NET puede acceder de forma nativa. Microsoft dejó caer la pelota en este caso.

Esto significa que sus alternativas son, en orden decreciente de masoquismo: 1) Implemente una función de guardar por su cuenta en .NET que implemente RFC 2083, 2) Implemente una función de guardado basada en portar libpng a .NET, 3) Llame al código no administrado que fue construido desde libpng directamente

libpng tiene una gran documentación y es gratuito, tanto en disponibilidad como en permisividad de licencia.

PNG generalmente es un esquema de compresión sin pérdida, lo que significa que la calidad de la imagen nunca se reduce a menos que reduzca el conteo de píxeles (tamaño) o la profundidad del color. Hay tres formas de reducir el tamaño del archivo de las imágenes PNG:

  • Reduzca el conteo de píxeles (reduciendo la escala de la imagen); hay una pérdida evidente de resolución aquí
  • Usar filtros de precompresión diferentes / parámetros del compresor DEFLATE ( OptiPNG es mi herramienta favorita para elegir automáticamente la mejor combinación de filtros / ajustes del compresor)
  • La reducción de la profundidad de color del color verdadero a 256 (o menos) colores le dará ahorros sustanciales de bytes, pero generalmente a un gran costo visual (especialmente para imágenes fotográficas)

Parece que .NET no tiene una forma incorporada de cambiar los filtros de precompresión o los parámetros del compresor de PNG, por lo que tendrá que usar una biblioteca externa. OptiPNG o cualquiera de las otras herramientas de optimización PNG no son bibliotecas .NET nativas, por lo que tendrá que ocuparse de P / Invocar las bibliotecas o ejecutar un proceso separado para procesar cada imagen. Sin embargo, a menudo observa ahorros de alrededor del 5% o menos (aunque he visto tanto como el 40%), ya que este es, en última instancia, un proceso sin pérdidas.

Recomendaría no reducir la profundidad de color en el escenario automatizado que describa, porque los resultados pueden parecer verdaderamente horribles (piense en los GIF vacilantes de antaño). (Sin embargo, si realiza la optimización manual, consulte Color Quantizer en Windows e ImageAlpha en Mac).

De manera realista, la mejor forma de reducir el tamaño del archivo a expensas de la calidad es simplemente convertirlo a JPEG, que no requiere dependencias externas, y está diseñado para ser un algoritmo de compresión con pérdida:

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

Desafortunadamente, el procesador de imágenes de .Net para png no realizará ninguna heurística de optimización en la salida. Su mejor opción es tener un binario optipng / pngcrush disponible en el servidor, renderizar el resultado redimensionado a un archivo temporal, y luego usar pngcrush en él a través de System.Diagnostics.Process.

En la mayoría de los casos, si las cargas son fotografías y el formato original es JPEG, se lo servirá mejor al usar salida JPEG.