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

tzcvj98z  于 2023-11-15  发布在  Java
关注(0)|答案(6)|浏览(172)

我有问题阅读这一个JPEG文件使用ImageIO.read(文件文件)-它抛出一个异常的消息“不支持的图像类型”。
我试过其他JPEG图像,它们似乎工作得很好。
我能发现的唯一区别是,这个文件似乎包括一个缩略图-这是已知的导致ImageIO.read()的问题?
x1c 0d1x的数据
编辑:
添加了生成的图像:


gjmwrych

gjmwrych1#

我通过这个修复了它。只需要添加这个依赖。我可以通过ImageIO读取CMYK图像。

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

字符串

w8rqjzmb

w8rqjzmb2#

旧帖,但备查:
受这个问题和这里的链接启发,我为ImageIO编写了一个JPEGImageReader插件,它支持CMYK颜色模型(使用原始颜色模型,或在读取时隐式转换为RGB)。与这里提到的其他解决方案不同,该阅读器还使用JPEG流中嵌入的ICC配置文件进行适当的颜色转换。
源代码和二进制版本可以在github.com/haraldk/TwelveMonkeys上免费获得,并且受BSD风格的许可证的保护。
安装后,您可以使用ImageIO.read(...)读取CMYK JPEG,如下所示:

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

字符串
也就是说:在大多数情况下,没有必要修改代码。

6l7fqoea

6l7fqoea3#

您的图像“Color Model”是CMYK,JPEGImageReader(读取文件的内部类)只读取RGB Color Model。
如果你需要读取CMYK图像,那么你将需要转换它们,试试这个代码。

更新

将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的dropbox中删除了。所以我添加了新的图片(不是原来的)来模拟它们发生的问题。

第一个图像是正常RGB图像的样子。

x1c 0d1x的数据

第二张图像是CMYK颜色模式下相同图像的外观。

你实际上无法看到它在网络上的样子,因为它将被主机转换为RGB。要确切地看到它的样子,请将RGB图像通过RGB到CMYK转换器运行。

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



OP发生的问题是,他们有像图像2这样的东西,当你试图读取它时,它会抛出一个异常。

gywdnpxw

gywdnpxw4#

我有点迟到了,但我还是值得把我的答案贴出来,因为没有一个答案能真正解决问题。
该解决方案需要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)。
我对我的解决方案不是很满意。虽然颜色大部分都很好,但深色区域有点太亮了,特别是黑色不是全黑。如果有人知道我可以改进的地方,我很高兴听到它。

ktecyv1j

ktecyv1j5#

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();

字符串

qzwqbdag

qzwqbdag6#

我在这里也找到了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;
}

字符串

相关问题