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

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

该解决方案需要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 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)。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值