我在使用 ImageIO.read(File file) 读取这个 JPEG 文件时遇到问题 - 它会引发异常,并显示消息“不支持的图像类型”。
我尝试过其他 JPEG 图像,它们似乎工作正常。
我能够发现的唯一区别是该文件似乎包含一个缩略图 - 是否已知会导致 ImageIO.read() 出现问题?
编辑:
添加了生成的图像:
我在使用 ImageIO.read(File file) 读取这个 JPEG 文件时遇到问题 - 它会引发异常,并显示消息“不支持的图像类型”。
我尝试过其他 JPEG 图像,它们似乎工作正常。
我能够发现的唯一区别是该文件似乎包含一个缩略图 - 是否已知会导致 ImageIO.read() 出现问题?
编辑:
添加了生成的图像:
旧帖子,但供将来参考:
受此问题和此处找到的链接的启发,我为 ImageIO 编写了一个 JPEGImageReader 插件,该插件支持 CMYK 颜色模型(均具有原始颜色模型,或在读取时隐式转换为 RGB)。与此处提到的其他解决方案相比,阅读器还使用嵌入在 JPEG 流中的 ICC 配置文件进行适当的颜色转换。
它是纯 Java,不需要 JAI。源代码和二进制发行版可在github.com/haraldk/TwelveMonkeys免费获得,并由 BSD 风格的许可证覆盖。
安装后,它允许您使用ImageIO.read(...)
以下方式读取 CMYK JPEG:
File cmykJPEGFile = new File(/*path*/);
BufferedImage image = ImageIO.read(cmykJPEGFile);
即:在大多数情况下,没有必要修改您的代码。
您的图像“颜色模型”是 CMYK,JPEGImageReader
(读取文件的内部类)仅读取 RGB 颜色模型。
如果您坚持阅读 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 的保管箱中删除。因此,我正在添加新图像(不是原始图像)来模拟它们所发生的问题。
第一个图像是普通 RGB 图像的样子。
第二张图像是相同图像在 CMYK 颜色模型中的外观。
您实际上无法在 Web 上看到它的外观,因为它会被主机转换为 RGB。要准确查看它的外观,请获取 RGB 图像并通过 RGB 到 CMYK 转换器运行它。
第三个图像是 CMYK 图像在使用 Java ImageIO 读取然后写入时的样子。
OP 发生的问题是它们有类似图像 2 的内容,当您尝试阅读它时会引发异常。
我参加聚会有点晚了。但是我发布我的答案可能仍然值得,因为没有一个答案真正解决了问题。
该解决方案需要 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)。
我对我的解决方案不太满意。虽然颜色大多很好,但暗区有点太亮,特别是黑色不是全黑的。如果有人知道我可以改进什么,我会很高兴听到的。
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();
我在这里也找到了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;
}
我通过这个修复它。只需要添加这个依赖。我可以通过 ImageIO 读取 CMYK 图像。 十二只猴子
ImageIO.read(new URL("http://img3.tianyancha.com/api/9b80a61183787909e719c77fd0f78103.png"))