Image读取CMYK和Tif 报错的解决办法

上一篇说到,Image.read()返回空是null,引入一个包就行。后来要讲读取到的图片缩小,还是会报错。没办法只得先把它先转换成其他格式的图片才能进行缩小,处理办法,为先判断图片的真实格式,用下面类里的getRealFormatName(),如果为Tif格式,先将它转成其他可被ImageIO读取的格式covertTif就可以了。
后来又碰到一种情况,就是读取的图片有些不是RGB颜色,而是CMYK设置的颜色,此时会报不支持此格式的错误。内容如下:
javax.imageio.IIOException: Unsupported Image Type
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(Unknown Source)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(Unknown Source)
....
同样需要将图片的颜色转为RGB再作读取,这里的处理方法是,不用系统自带的ImageIO读取图片,而用下面这个类的readImage(file)方法,这个方法里会对CMYK颜色的图片做特殊处理。

import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;

public class ImageTool {

private static boolean hasAdobeMarker = false;
private static Log log = LogFactory.getLog(ImageTool.class);

/*
*返回图片的真实格式,此方法如果读取的图片为svg格式会返回空值
*/
public static String getRealFormatName(Object object) throws Exception {
ImageInputStream iis = ImageIO.createImageInputStream(object);
Iterator<ImageReader> iterator = ImageIO.getImageReaders(iis);
while (iterator.hasNext()) {
ImageReader reader = (ImageReader) iterator.next();
return reader.getFormatName();
}
return null;
}

/*
*传图片的路径,和要将图片转成的格式
*/
public static void convertTif(String fileName, String extension) {
try {
File file = new File(fileName);
if (file.exists() == false) {
System.out.println("File not exist!!!");
return;
}
BufferedImage image = ImageIO.read(file);
BufferedImage convertedImage = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_INT_RGB);
convertedImage.createGraphics().drawRenderedImage(image, null);
ImageIO.write(convertedImage, extension, new File(fileName));
} catch (IOException ex) {
ex.printStackTrace();
}
}

/*
*传进需要读取的图片,fileName是用来记录CMYK图片的名字
*/
public static BufferedImage readImage(File file, String fileName) throws IOException, ImageReadException {
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) {
checkAdobeMarker(file);
profile = Sanselan.getICCProfile(file);
WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
if (hasAdobeMarker) {
convertInvertedColors(raster);`
}
image = convertCmykToRgb(raster, profile);
log.info("The CMYK FileName ========" + fileName);
}
return image;
}
return null;
}

private static 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;
}
}
}

private 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);
}
}

private static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
if (cmykProfile == null) //读取CMYK的色彩配置文件
{
cmykProfile = ICC_Profile.getInstance(ImageTool.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;
}
}


此类需要引入一个包和ISOcoated_v2_300_eci.icc(CMYK的位图);

注:CMYK转RGB参考自stackoverflow :
http://stackoverflow.com/questions/3123574/how-to-convert-from-cmyk-to-rgb-in-java-correctly?lq=1 codo君的答案;
发布了26 篇原创文章 · 获赞 52 · 访问量 14万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章