Какой уровень качества использует Image.Save () для файлов JPEG? - PullRequest
33 голосов
/ 18 октября 2010

Я просто удивился, когда загрузил файл 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 ]

19 голосов
/ 18 октября 2010

Используя отражатель, получается, Image.Save() сводится к функции GDI + GdipSaveImageToFile , с encoderParams NULL.Поэтому я думаю, что вопрос в том, что делает кодировщик JPEG, когда он получает ноль encoderParams.75% было предложено здесь, но я не могу найти какой-либо надежной ссылки.

РЕДАКТИРОВАТЬ Вы, вероятно, могли бы убедиться в этом сами, запустив вашу программу выше для значений качества 1..100и сравнивая их с сохраненным jpg с качеством по умолчанию (например, с помощью fc.exe / B)

5 голосов
/ 18 октября 2010

IIRC, это 75%, но я не помню, где я это читал.

0 голосов
/ 18 октября 2010

Когда вы сохраняете изображение в виде файла JPEG с уровнем качества <100%, вы вносите в сохраненное изображение артефакты, которые являются побочным эффектом процесса сжатия.Вот почему повторное сохранение изображения на 100% фактически увеличивает размер вашего файла по сравнению с оригиналом - по иронии судьбы в растровом изображении присутствует больше информации. </p>

Именно поэтому вы всегда должны пытаться сохранить вформат без потерь (например, PNG), если вы собираетесь впоследствии вносить какие-либо изменения в свой файл, в противном случае вы будете влиять на качество вывода с помощью многочисленных преобразований с потерями.

0 голосов
/ 18 октября 2010

Я мало что знаю о методе Image.Save, но могу вам сказать, что добавление этой жирной линии логично уменьшит размер изображения jpg.Это связано с тем, как jpg сохраняется (и кодируется).

Толстая черная линия обеспечивает очень простое и меньшее кодирование (если я правильно помню, это подходит в основном после дискретного косинусного преобразования), поэтомуизмененное изображение может быть сохранено с использованием меньшего количества данных (байтов).

jpg шаги кодирования

Что касается изменений в размере (без добавленной строки), я неуверен, какое изображение вы снова открыли и сохранили

Для дальнейшего изучения я открываю и сохраняю без явной настройки качества и размер файла был точно такой же

Если вы открыли старый(исходный нормальный размер) изображения и сохранил его, тогда возможно сжатие по умолчанию и сжатие исходного изображения одинаковы.Если вы открыли новое (в 4 раза больше) изображение и сохранили его, то, возможно, сжатие по умолчанию для метода сохранения получено из образа (как это было при загрузке).

Опять же, я не знаюметод сохранения, так что я просто подбрасываю идеи (может быть, они помогут вам).

...