Какой уровень качества Image.Save() использует для файлов JPEG?
Я просто удивился, когда загрузил файл jpg, развернулся и сохранил его с качеством 100, а размер был почти в 4 раза больше оригинала. Для дальнейшего изучения я открываю и сохраняю без явной настройки качества и размер файла был точно таким же. Я подумал, что это потому, что ничего не изменилось, поэтому он просто записывает те же самые биты обратно в файл. Чтобы проверить это предположение, я нарисовал большую жирную линию по диагонали по всему изображению и снова сохранил без установки качества (на этот раз я ожидал, что файл подпрыгнет, потому что он будет "грязным"), но он уменьшился на ~10Kb!
На данный момент я действительно не понимаю, что происходит, когда я просто вызываю Image.Save() без указания качества сжатия. Как размер файла настолько близок (после изменения изображения) к исходному размеру, когда качество еще не установлено, когда я установил качество на 100 (в основном, без сжатия), размер файла в несколько раз больше исходного?
Я прочитал документацию по Image.Save(), и в ней нет подробностей о том, что происходит за кулисами. Я гуглил в разные стороны, но не могу найти никакой дополнительной информации, которая бы объясняла, что я вижу. Я работаю в течение 31 часа подряд, поэтому, возможно, я упускаю что-то очевидное;0)
Все это произошло, когда я реализовал некоторые библиотечные методы для сохранения изображений в базе данных. Я перегрузил наш метод "SaveImage", чтобы разрешить явно устанавливать качество, и во время моего тестирования я натолкнулся на странные (для меня) результаты, описанные выше. Любой свет, который вы можете пролить, будет оценен.
Вот код, который проиллюстрирует то, что я испытываю:
string filename = @"C:\temp\image testing\hh.jpg";
string destPath = @"C:\temp\image testing\";
using(Image image = Image.FromFile(filename))
{
ImageCodecInfo codecInfo = ImageUtils.GetEncoderInfo(ImageFormat.Jpeg);
// Set the quality
EncoderParameters parameters = new EncoderParameters(1);
// Quality: 10
parameters.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, 10L);
image.Save(destPath + "10.jpg", codecInfo, parameters);
// Quality: 75
parameters.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, 75L);
image.Save(destPath + "75.jpg", codecInfo, parameters);
// Quality: 100
parameters.Param[0] = new EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, 100L);
image.Save(destPath + "100.jpg", codecInfo, parameters);
// default
image.Save(destPath + "default.jpg", ImageFormat.Jpeg);
// Big line across image
using (Graphics g = Graphics.FromImage(image))
{
using(Pen pen = new Pen(Color.Red, 50F))
{
g.DrawLine(pen, 0, 0, image.Width, image.Height);
}
}
image.Save(destPath + "big red line.jpg", ImageFormat.Jpeg);
}
public static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
return ImageCodecInfo.GetImageEncoders().ToList().Find(delegate(ImageCodecInfo codec)
{
return codec.FormatID == format.Guid;
});
}
4 ответа
Используя отражатель, получается Image.Save()
сводится к функции GDI+ GdipSaveImageToFile, с encoderParams
НОЛЬ. Поэтому я думаю, что вопрос в том, что делает кодировщик JPEG, когда он получает ноль encoderParams
, 75% было предложено здесь, но я не могу найти твердую ссылку.
РЕДАКТИРОВАТЬ Вы, вероятно, могли бы убедиться в этом сами, запустив свою программу выше для значений качества 1..100 и сравнив их с jpg, сохраненным с качеством по умолчанию (используя, скажем, fc.exe /B)
Когда вы сохраняете изображение в виде файла JPEG с уровнем качества <100%, вы вносите в сохраненное изображение артефакты, которые являются побочным эффектом процесса сжатия. Вот почему повторное сохранение изображения на 100% фактически увеличивает размер вашего файла по сравнению с оригиналом - по иронии судьбы, в растровом изображении больше информации.
По этой же причине вам всегда следует пытаться сохранить файл в формате без потерь (например, PNG), если вы собираетесь впоследствии вносить какие-либо изменения в свой файл, иначе вы будете влиять на качество вывода с помощью многочисленных преобразований с потерями.
Я не очень разбираюсь в методе Image.Save, но могу вам сказать, что добавление этой жирной линии логически уменьшит размер изображения jpg. Это связано с тем, как jpg сохраняется (и кодируется).
Толстая черная линия обеспечивает очень простое и меньшее кодирование (если я правильно помню, это происходит в основном после дискретного косинусного преобразования), поэтому измененное изображение может быть сохранено с использованием меньшего количества данных (байтов).
Что касается изменений в размере (без добавления строки), я не уверен, какое изображение вы снова открыли и сохранили
Для дальнейшего изучения я открываю и сохраняю без явной настройки качества и размер файла был точно такой же
Если вы открыли старое (исходное изображение нормального размера) и сохранили его, то, возможно, сжатие по умолчанию и сжатие исходного изображения совпадают. Если вы открыли новое (в 4 раза больше) изображение и сохранили его, то, возможно, сжатие по умолчанию для метода сохранения будет получено из изображения (как это было при загрузке).
Опять же, я не знаю метод сохранения, поэтому я просто подбрасываю идеи (возможно, они помогут вам).