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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章