Почему Java ImageIO выравнивает цвета JPEG

Когда я читаю определенные файлы JPG, цвета сглаживаются. Вот простой пример, который читает jpg и просто записывает одно и то же изображение в другой файл.

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class JPegReadTest {
    public static void main(String[] args) {
        if (args.length == 2) {
            try {
                BufferedImage src = ImageIO.read(new File(args[0]));
                ImageIO.write(src, "jpg", new File(args[1]));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.err.println("Usage: java JPegReadTest src dest");
        }
    }
}

Если вы попробуете это, например, http://www.flickr.com/photos/visualpanic/233508614/sizes/l/, цвета целевого изображения отличаются от исходного файла. Почему это? Как это исправить?

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

Ответ 1

Это может быть несколько причин.

  • Данные цвета JPEG часто хранятся как YCrCb вместо RGB, хотя преобразования должны быть в основном незаметными.
  • JPEG часто имеет встроенный цветовой профиль, но многие приложения не понимают этого и просто игнорируют его (в этом случае ваш выходной файл может отсутствовать в цветовом профиле).
  • Значение Gamma может быть reset или отсутствует после того, как Java манипулирует им.

Я действительно не пробовал ваш пример... не могли бы вы разместить как до, так и после файлов? Не имея возможности проверить файл результатов, трудно определить, имеются ли эти дополнительные данные или нет.

Изменить: Да, ясно, что ваши оригинальные и конвертированные изображения имеют разные цветовые профили. Java разделила исходный цветной профиль и вместо него использовала общий sRGB. Они выглядят одинаково для нас в Windows с Firefox и различными программами, потому что эти программы не используют цветовой профиль при визуализации. Тем не менее, на вашем Mac Mac фактически поддерживает эти цветовые профили (обсуждение вопросов по Mac для графики и т.д.), И поэтому они визуализируются по-разному. У меня нет Mac, но я подозреваю, что если вы откроете файлы в Photoshop на любой платформе, вы увидите разницу.

Ответ 2

Возможно, ваше исходное изображение имеет назначенный цветовой профиль с шириной диапазона, чем sRGB (например, Adobe RGB), и ваш цикл загрузки/сохранения не сохраняет информацию о цветовом пространстве? Без цветового профиля ваш зритель будет считать sRGB, а сжатая гамма сделает все "blah". Если у вас есть exiftool,

exiftool -ProfileDescription filename.jpg

- это быстрый способ проверки цветовых профилей на вашем источнике и вывода изображений.

Ответ 3

jpeg - формат с потерями. Когда читается, java сохраняет его как необработанный формат, похожий на BMP. Затем он снова выписывается, что приводит к потере данных. Кроме того, не так много контроля над качеством, как при использовании чего-то вроде GIMP.

Возможно, посмотрите на использование других API, таких как Image Magick, чтобы дать вам больше контроля над качеством.

Ответ 4

JPEG является lossy.

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

Дополнительно ImageIO.write(), возможно, использует некоторые параметры качества по умолчанию для сохранения файлов JPEG, которые могут быть ниже оригинала, что приведет к дополнительной потере качества.

Попробуйте сохранить файл PNG, и вы увидите, что он будет выглядеть так же, как источник.