为了账号安全,请及时绑定邮箱和手机立即绑定

无法使用ImageIO.read(文件文件)读取JPEG图像

/ 猿问

无法使用ImageIO.read(文件文件)读取JPEG图像

饮歌长啸 2019-09-21 15:00:59

我在使用ImageIO.read(File file)读取此JPEG文件时遇到问题-它引发异常,并显示消息“不支持的图像类型”。

我尝试了其他JPEG图像,但它们似乎工作正常。

我能够发现的唯一区别是此文件似乎包含缩略图-已知会导致ImageIO.read()问题吗?


查看完整描述

3 回答

?
潇湘沐


您的图像“颜色模型”为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年3月-添加仿真图像


原始图像已从OP的保管箱中删除。因此,我要添加新的图像(而不是原始图像)来模拟它们所发生的问题。


第一幅图像是普通RGB图像的外观。


图像RGB


第二张图像是同一图像在CMYK颜色模型中的外观。


您实际上看不到它在网络上的外观,因为它将由主机转换为RGB。要确切查看其外观,请拍摄RGB图像,然后通过RGB到CMYK转换器运行它。


第三个图像是使用Java ImageIO读取然后写入时CMYK图像的外观。


通过Java RGB读取的图像CMYK


OP发生的问题是,它们有类似图像2的内容,当您尝试读取它时会抛出异常。


查看完整回答
反对 回复 2019-09-21
?
弑天下

旧帖子,但供将来参考:


受此问题和此处链接的启发,我为ImageIO编写了一个JPEGImageReader插件,该插件支持CMYK颜色模型(都具有原始颜色模型,或者在读取时隐式转换为RGB)。与此处提到的其他解决方案相比,阅读器还使用嵌入在JPEG流中的ICC配置文件进行正确的颜色转换。


它是纯Java,不需要JAI。源代码和二进制发行版可在github.com/haraldk/TwelveMonkeys上免费获得,并包含BSD样式的许可证。


安装完成后,您可以使用以下方式读取CMYK JPEG ImageIO.read(...):


File cmykJPEGFile = new File(/*path*/);

BufferedImage image = ImageIO.read(cmykJPEGFile);

即:在大多数情况下,无需修改代码。


查看完整回答
反对 回复 2019-09-21
?
扬帆大鱼

我参加聚会有点晚了。但是我仍然可以发布我的答案,因为所有答案都不能真正解决问题。


该解决方案需要Sanselan(或现在称为Apache Commons Imaging),并且需要合理的CMYK颜色配置文件(.icc文件)。您可以从Adobe或eci.org获得后者。


基本问题是,Java开箱即用只能读取RGB中的JPEG文件。如果您有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)。


我对我的解决方案不太满意。虽然颜色大多不错,但深色区域却有点太亮,尤其是黑色不是完全黑色。如果有人知道我可以改进的地方,我会很高兴听到它。


查看完整回答
反对 回复 2019-09-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信