Невозможно прочитать изображение в формате JPEG с помощью ImageIO.read (файл файла) - PullRequest
41 голосов
/ 09 марта 2010

У меня проблемы с чтением этого файла JPEG с использованием ImageIO.read (File file) - возникает исключение с сообщением «Неподдерживаемый тип изображения».

Я пробовал другие изображения JPEG, и они, кажется, работают нормально.

Единственное отличие, которое мне удалось заметить, заключается в том, что этот файл содержит миниатюру. Известно ли, что это вызывает проблемы с ImageIO.read ()?

Troublesome image

EDIT:

Добавлено полученное изображение:

Strange colors

Ответы [ 6 ]

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

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

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

Это простая Java и не требует JAI. Исходный код и двоичные дистрибутивы свободно доступны по адресу github.com / haraldk / TwelveMonkeys и защищены лицензией в стиле BSD.

После того, как он установлен, он позволяет читать файлы CMYK JPEG, используя ImageIO.read(...), например:

File cmykJPEGFile = new File(/*path*/);
BufferedImage image = ImageIO.read(cmykJPEGFile);

I.e .: В большинстве случаев нет необходимости изменять ваш код.

38 голосов
/ 09 марта 2010

Ваше изображение "Цветовая модель" - CMYK, JPEGImageReader (внутренний класс, который читает ваш файл) только для чтения Цветовая модель RGB.

Если вы настаиваете на чтении изображений CMYK, вам нужно будет их конвертировать, попробуйте этот код.

UPDATE

Считывание изображения CMYK в RGB BufferedImage.

    File f = new File("/path/imagefile.jpg");

    //Find a suitable ImageReader
    Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
    ImageReader reader = null;
    while(readers.hasNext()) {
        reader = (ImageReader)readers.next();
        if(reader.canReadRaster()) {
            break;
        }
    }

    //Stream the image file (the original CMYK image)
    ImageInputStream input =   ImageIO.createImageInputStream(f); 
    reader.setInput(input); 

    //Read the image raster
    Raster raster = reader.readRaster(0, null); 

    //Create a new RGB image
    BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(), 
    BufferedImage.TYPE_4BYTE_ABGR); 

    //Fill the new image with the old raster
    bi.getRaster().setRect(raster);

ОБНОВЛЕНИЕ - март 2015 г. - Добавление имитационных изображений

Исходные изображения были удалены из выпадающего списка OP. Поэтому я добавляю новые изображения (не оригиналы), которые имитируют проблему, которая происходила с ними.

Первое изображение - это то, как выглядит нормальное изображение RGB.

Image RGB

Второе изображение - так будет выглядеть то же изображение в цветовой модели CMYK.

На самом деле вы не можете видеть, как он выглядит в Интернете, потому что хост будет конвертировать его в RGB. Чтобы увидеть, как он выглядит, возьмите изображение RGB и запустите его через конвертер RGB в CMYK.

Третье изображение - это то, как будет выглядеть изображение CMYK при чтении и записи с использованием Java ImageIO.

Image CMYK read through Java RGB

Проблема, которая происходила с OP, заключалась в том, что у них было что-то вроде изображения 2, которое выдает исключение при попытке прочитать его.

18 голосов
/ 26 августа 2012

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

Для решения требуется Sanselan (или Apache Commons Imaging, как его сейчас называют), и для него требуется разумный цветовой профиль CMYK (файл .icc). Вы можете получить более позднюю версию из Adobe или eci.org.

Основная проблема заключается в том, что Java - из коробки - может читать файлы JPEG только в RGB. Если у вас есть файл CMYK, вам нужно различать обычный CMYK, Adobe CMYK (с инвертированными значениями, то есть 255 для отсутствия чернил и 0 для максимальных чернил) и Adobe CYYK (также в некоторых вариантах с инвертированными цветами).

public class JpegReader {

    public static final int COLOR_TYPE_RGB = 1;
    public static final int COLOR_TYPE_CMYK = 2;
    public static final int COLOR_TYPE_YCCK = 3;

    private int colorType = COLOR_TYPE_RGB;
    private boolean hasAdobeMarker = false;

    public BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorType = COLOR_TYPE_RGB;
        hasAdobeMarker = false;

        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK)
                    convertYcckToCmyk(raster);
                if (hasAdobeMarker)
                    convertInvertedColors(raster);
                image = convertCmykToRgb(raster, profile);
            }

            return image;
        }

        return null;
    }

    public void checkAdobeMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
            {
                hasAdobeMarker = true;
                int transform = app14Segment.bytes[11] & 0xff;
                if (transform == 2)
                    colorType = COLOR_TYPE_YCCK;
            }
        }
    }

    public static void convertYcckToCmyk(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);

            for (int x = 0; x < stride; x += 4) {
                int y = pixelRow[x];
                int cb = pixelRow[x + 1];
                int cr = pixelRow[x + 2];

                int c = (int) (y + 1.402 * cr - 178.956);
                int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int) (y + 1.772 * cb - 226.316);

                if (c < 0) c = 0; else if (c > 255) c = 255;
                if (m < 0) m = 0; else if (m > 255) m = 255;
                if (y < 0) y = 0; else if (y > 255) y = 255;

                pixelRow[x] = 255 - c;
                pixelRow[x + 1] = 255 - m;
                pixelRow[x + 2] = 255 - y;
            }

            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static void convertInvertedColors(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);
            for (int x = 0; x < stride; x++)
                pixelRow[x] = 255 - pixelRow[x];
            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
        if (cmykProfile == null)
            cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));
        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
        BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykRaster, rgbRaster);
        return rgbImage;
    }
}

Код сначала пытается прочитать файл, используя обычный метод, который работает для файлов RGB. В случае сбоя считываются сведения о цветовой модели (профиль, маркер Adobe, вариант Adobe). Затем он считывает необработанные пиксельные данные (растр) и выполняет все необходимые преобразования (YCCK в CMYK, инвертированные цвета, CMYK в RGB).

Я не совсем доволен своим решением. В то время как цвета в основном хорошие, темные области немного слишком яркие, в частности черный не полностью черный. Если кто-нибудь знает, что я могу улучшить, я буду рад это услышать.

6 голосов
/ 02 августа 2012

ImageIO.read() ->

File filePath = new File("C:\\Users\\chang\\Desktop\\05036877.jpg");
com.sun.image.codec.jpeg.JPEGImageDecoder jpegDecoder =  JPEGCodec.createJPEGDecoder (new FileInputStream(filePath));

BufferedImage image = jpegDecoder.decodeAsBufferedImage();
5 голосов
/ 30 июня 2011

Я также нашел здесь https://stackoverflow.com/questions/22409..., этот отлично конвертирует цвета

И объединены оба, чтобы получить это:

private BufferedImage convertCMYK2RGB(BufferedImage image) throws IOException{
    log.info("Converting a CYMK image to RGB");
    //Create a new RGB image
    BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(),
    BufferedImage.TYPE_3BYTE_BGR);
    // then do a funky color convert
    ColorConvertOp op = new ColorConvertOp(null);
    op.filter(image, rgbImage);
    return rgbImage;
}
0 голосов
/ 30 ноября 2017

Я исправлю это. Нужно только добавить эту зависимость. Я могу прочитать изображение CMYK ImageIO. TwelveMonkeys

ImageIO.read(new URL("http://img3.tianyancha.com/api/9b80a61183787909e719c77fd0f78103.png"))
...