Существует ли 100% -ная Java-альтернатива ImageIO для чтения файлов JPEG? - PullRequest
20 голосов
/ 08 июня 2010

Мы используем Java2D для изменения размера фотографий, загруженных на наш веб-сайт, но мы сталкиваемся с проблемой (казалось бы, старая, ср .: http://forums.sun.com/thread.jspa?threadID=5425569) - некоторые конкретные JPEG-файлы поднимают CMMException, когда мы пытаемся ImageIO.read() InputStream, содержащий их двоичные данные:

java.awt.color.CMMException: Invalid image format
 at sun.awt.color.CMM.checkStatus(CMM.java:131)
 at sun.awt.color.ICC_Transform.<init>(ICC_Transform.java:89)
 at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:516)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.acceptPixels(JPEGImageReader.java:1114)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1082)
 at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
 at javax.imageio.ImageIO.read(ImageIO.java:1422)
 at javax.imageio.ImageIO.read(ImageIO.java:1326)
    ...

(вырезал остаток от трассировки стека, который является нашим ImageIO.read() вызовом, кодом сервлета и т. Д.)

Мы сузили его до фотографий, сделанных на определенных камерах, и я выбрал фотографию, которая вызывает эту ошибку: http://img214.imageshack.us/img214/5121/estacaosp.jpg. Мы заметили, что это происходит только с JVM от Sun (на Linux и Mac, только что протестировал его на 1.6.0_20) - тестовая машина с OpenJDK считывает те же фотографии без помех, возможно, из-за другой реализации читателя JPEG.

К сожалению, мы не можем ни включить JVM в производство, ни использовать собственные решения, такие как ImageMagick (http://www.imagemagick.org/).

Учитывая это, мой вопрос: существует ли замена для JPEG-ридера ImageIO, который может обрабатывать фотографии, такие как связанные? Если нет, то можем ли мы использовать другое решение для изменения размера фотографий Java на 100%?

Спасибо!

Ответы [ 3 ]

12 голосов
/ 09 июня 2010

Одной из полезных библиотек для вас может быть Java Advanced Imaging Library ( JAI )

Использование этой библиотеки может быть немного сложнее, чем использование ImageIO, но в быстром тесте я только что запустил ее, и она открылась и отобразил файл изображения проблемы, с которым вы связались.

public static void main(String[] args) {
        RenderedImage image = JAI.create("fileload", "estacaosp.jpg");

        float scale=(float) 0.5;

        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image);

        pb.add(scale);
        pb.add(scale);
        pb.add(1.0F);
        pb.add(1.0F);

        pb.add(new InterpolationNearest() );// ;InterpolationBilinear());
        image = JAI.create("scale", pb);

        // Create an instance of DisplayJAI.
        DisplayJAI srcdj = new DisplayJAI(image);

        JScrollPane srcScrollPaneImage = new JScrollPane(srcdj);

// Use a label to display the image
        JFrame frame = new JFrame();

        frame.getContentPane().add(srcScrollPaneImage, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }

После запуска этого кода изображение загружается нормально. Затем он изменяется на 50% с помощью ParamaterBlock

И, наконец, если вы хотите сохранить файл, вы можете просто позвонить:

String filename2 = new String ("tofile.jpg");
  String format = new String ("JPEG");
  RenderedOp op = JAI.create ("filestore", image, filename2, format);

Надеюсь, это поможет вам. Желаем удачи.

10 голосов
/ 22 апреля 2013

Старый пост, но для дальнейшего использования:

Вдохновленный этим вопросом и ссылками, найденными здесь, я написал плагин JPEGImageReader для ImageIO, который поддерживает изображения JPEG с такими "плохими" цветовыми профилями ICC (проблема заключается в том, что цель рендеринга в профиле ICC несовместима с Java ColorConvertOp). Это простая Java и не требует JAI.

Исходный код и связанные двоичные сборки свободно доступны из проекта TwelveMonkeys на GitHub.

7 голосов
/ 11 октября 2012

Я столкнулся с той же проблемой. Я не хотел использовать JAI, поскольку он устарел, но, похоже, это самое короткое решение.

Этот код преобразует InputStream в BufferedImage, используя Sun ImageIO (быстрый) или в некоторых случаях, когда возникает эта проблема, используя JAI:

public static BufferedImage read(InputStream is) throws IOException {
    try {
        // We try it with ImageIO
        return ImageIO.read(ImageIO.createImageInputStream(is));
    } catch (CMMException ex) {
        // If we failed...
        // We reset the inputStream (start from the beginning)
        is.reset();
        // And use JAI
        return JAI.create("stream", SeekableStream.wrapInputStream(is, true)).getAsBufferedImage();
    }
}
...