С#: поиск алгоритма/библиотеки сжатия PNG
Мне нужно сжать или, по крайней мере, снизить качество некоторых png-изображений, которые пользователи загружают на мой сайт. Я уже изменил его размер, но это не сильно влияет на размер изображения.
Поиск алгоритма сжатия или потери качества png/изображений или библиотеки для .net 4.0 или ниже.
Вот как я в настоящее время сохраняю/конвертирую мои изображения:
Image mainImg = ImageHelper.ResizeImage(bmp, 600, 500, false);
mainImg.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
Ответы
Ответ 1
К сожалению,.NET(и GDI +, на которых построены графические библиотеки .NET) не поддерживает никаких параметров кодирования для PNG. Фактически, если вы вызываете GetEncoderParameterList на свой образ с помощью PNG-кодировщика Clsid, вы получите исключение "Не реализовано".
Еще более печально, что оба ImageFormat и ImageCodecInfo являются закрытыми классами, и вы не можете просто добавлять новые кодеки к тому, к чему может получить доступ .NET. Microsoft сбросила мяч на этом.
Это означает, что ваши альтернативы в порядке убывания мазохизма:
1) Внедрите функцию сохранения самостоятельно в .NET, которая реализует RFC 2083,
2) Реализовать функцию сохранения, основанную на переносе libpng на .NET,
3) Вызвать неуправляемый код, который был создан непосредственно из libpng.
libpng имеет отличную документацию и свободен, как в доступности, так и во вседозволенности.
Ответ 2
PNG обычно представляет собой схему сжатия без потерь, что означает, что качество изображения никогда не уменьшается, если вы не уменьшите количество пикселей (размер) или глубину цвета, Существует три способа уменьшить размер файлов PNG:
- Уменьшить количество пикселей (путем уменьшения масштаба изображения); там очевидная потеря разрешения здесь.
- Использование различных параметров предварительного сжатия/параметров компрессора DEFLATE (OptiPNG - мой любимый инструмент для автоматического выбора наилучшей комбинации фильтров/компрессоров настройки)
- Уменьшение глубины цвета от истинного цвета до 256 (или менее) цветов даст вам существенную экономию байтов, но обычно с большими визуальными затратами (особенно для фотографических изображений).
Похоже, что .NET не имеет встроенного способа изменения фильтров предварительного сжатия или параметров компрессора PNG, поэтому вам придется использовать внешнюю библиотеку. OptiPNG или любой из других инструментов оптимизации PNG не являются родными .NET-библиотеками, поэтому вам придется иметь дело с P/Invoking для библиотек или запускать отдельный процесс для.. обрабатывать каждое изображение. Тем не менее, вы часто смотрите на экономию около 5% или меньше (хотя я видел до 40%), поскольку это, в конечном счете, процесс без потерь.
Я бы рекомендовал не уменьшать глубину цвета в автоматизированном сценарии, который вы описываете, потому что результаты могут выглядеть поистине ужасно (думают, что затушеванные GIF старые). (Однако, если вы делаете ручную оптимизацию, посмотрите Color Quantizer в Windows и ImageAlpha на Mac.)
Реально, лучший способ уменьшить размер файла за счет качества - просто преобразовать в JPEG, который не требует внешних зависимостей и предназначен для алгоритма сжатия с потерями:
mainImg.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg); // make sure you change `filePath` to end with jpg instead of png.
Ответ 3
К сожалению,.Net-процессор изображений для png не будет делать никаких эвристик оптимизации на выходе. Лучше всего иметь двоичный файл optipng/pngcrush, доступный на сервере, отображать измененный результат во временный файл, а затем использовать pngcrush на нем с помощью System.Diagnostics.Process.
По большей части, если загрузка является фотографией, а исходный формат - JPEG, вам лучше будет работать с использованием выходного файла JPEG.