Какой уровень качества использует Image.Save() для jpeg файлов?

Я только что получил настоящий сюрприз, когда загрузил файл jpg и обернулся и сохранил его с качеством 100, а размер был почти в 4 раза оригиналом. Чтобы продолжить исследование, я открываю и сохраняю без явной настройки качества, и размер файла был точно таким же. Я понял, что это произошло потому, что ничего не изменилось, поэтому он просто записывал одни и те же биты обратно в файл. Чтобы проверить это предположение, я нарисовал большую жирную линию по диагонали по изображению и сохранил снова, не устанавливая качество (на этот раз я ожидал, что файл подскочит, потому что он будет "грязным" ), но он уменьшился ~ 10Kb!

В этот момент я действительно не понимаю, что происходит, когда я просто вызываю Image.Save() w/out, определяя качество сжатия. Как размер файла настолько близок (после изменения изображения) до исходного размера, когда качество еще не установлено, когда я устанавливаю качество до 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;
    });
}

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

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

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

Чтобы продолжить исследование, я открываю и сохраняю без явной настройки качества, и размер файла был точно таким же

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

Опять же, я не знаю метод save, поэтому я просто бросаю идеи (может быть, они дадут вам преимущество).

Ответ 4

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

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