记录一下整个过程
第一次采用的办法
public static String readImage(String filename) throws IOException {
File file = new File(filename);
ImageInputStream input = ImageIO.createImageInputStream(file);
Iterator readers = ImageIO.getImageReaders(input);
if(readers == null || !readers.hasNext()) {
throw new RuntimeException("1 No ImageReaders found");
}
ImageReader reader = (ImageReader) readers.next();
reader.setInput(input);
String format = reader.getFormatName() ;
BufferedImage image;
if ( "JPEG".equalsIgnoreCase(format) ||"JPG".equalsIgnoreCase(format) ) {
try {
// 尝试读取图片 (包括颜色的转换).
image = reader.read(0); //RGB
} catch (IIOException e) {
// 读取Raster (没有颜色的转换).
Raster raster = reader.readRaster(0, null);//CMYK
image = createJPEG4(raster);
}
image.getGraphics().drawImage(image, 0, 0, null);
String dstfilename = filename.substring(0,filename.lastIndexOf("."))+"_rgb"+filename.substring(filename.lastIndexOf("."));
String newfilename = filename;
File newFile = new File(dstfilename);
FileOutputStream out = new FileOutputStream(newFile);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.flush();
out.close();
return dstfilename;
}
return null;
}
private static BufferedImage createJPEG4(Raster raster) {
int w = raster.getWidth();
int h = raster.getHeight();
byte[] rgb = new byte[w * h * 3];
//彩色空间转换
float[] Y = raster.getSamples(0, 0, w, h, 0, (float[]) null);
float[] Cb = raster.getSamples(0, 0, w, h, 1, (float[]) null);
float[] Cr = raster.getSamples(0, 0, w, h, 2, (float[]) null);
float[] K = raster.getSamples(0, 0, w, h, 3, (float[]) null);
for (int i = 0, imax = Y.length, base = 0; i < imax; i++, base += 3) {
float k = 220 - K[i], y = 255 - Y[i], cb = 255 - Cb[i],
cr = 255 - Cr[i];
double val = y + 1.402 * (cr - 128) - k;
val = (val - 128) * .65f + 128;
rgb[base] = val < 0.0 ? (byte) 0 : val > 255.0 ? (byte) 0xff
: (byte) (val + 0.5);
val = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128) - k;
val = (val - 128) * .65f + 128;
rgb[base + 1] = val < 0.0 ? (byte) 0 : val > 255.0 ? (byte) 0xff
: (byte) (val + 0.5);
val = y + 1.772 * (cb - 128) - k;
val = (val - 128) * .65f + 128;
rgb[base + 2] = val < 0.0 ? (byte) 0 : val > 255.0 ? (byte) 0xff
: (byte) (val + 0.5);
}
raster = Raster.createInterleavedRaster(new DataBufferByte(rgb, rgb.length), w, h, w * 3, 3, new int[]{0, 1, 2}, null);
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorModel cm = new ComponentColorModel(cs, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
return new BufferedImage(cm, (WritableRaster) raster, true, null);
}
public static String TestImg(String src) {
File imgsrc = new File(src);
try {
ImageIO.read(imgsrc);
} catch (IOException e) {
// TODO Auto-generated catch block
String msg = e.getMessage();
System.out.println("msg:"+msg);
if (msg.indexOf("Unsupported Image Type") == 0) {
try {
return readImage(src);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else {
e.printStackTrace();
return null;
}
}
return src;
}
格式不太会整
针对大多数图片,运行的相当不错,但是,有一次遇到超大图片,5900*16000的大小
上面的代码直接报java.lang.OutOfMemoryError: Java heap space, 尝试过在程序启动的时候加
些参数 :-Xms256M -Xmx768M -XX:PermSize=128M -XX:MaxPermSize=512M,后面把Xmx数值加大到2G
,仍然报错
网上找了找,还有个方法:
@SuppressWarnings("restriction")
JPEGImageDecoder decoder = null;
try {
decoder = JPEGCodec.createJPEGDecoder(new FileInputStream( new File(file) ) );
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (decoder == null) {
System.out.println("can't get decoder");
return;
}
try {
BufferedImage sourceImg = decoder.decodeAsBufferedImage();
OutputStream os = null;
os = new FileOutputStream("D:\\test28.jpg");
ImageIO.write(sourceImg, "jpg", os);
} catch (ImageFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
部分人说这个代码可用,但是,对我个人,转换后的图片颜色不对了,白色的变成墨绿色,黑色变成了紫红色
直接丢弃。。。
又有一种方法:
public static void cmyk2rgb(String file) {
Iterator readers = ImageIO.getImageReadersByFormatName("jpeg");
ImageReader reader = null;
while (readers.hasNext()) {
reader = (ImageReader) readers.next();
if (reader.canReadRaster()) {
break;
}
}
ImageInputStream input = null;
try {
input = ImageIO.createImageInputStream(new File(file));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (input == null)
return;
reader.setInput(input);
// 创建图片.
BufferedImage image;
try {
// 尝试读取图片 (包括颜色的转换).
image = reader.read(0);
} catch (IOException e) {
// 读取Raster (没有颜色的转换).
Raster raster = null;
try {
raster = reader.readRaster(0, null);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 随意选择一个BufferedImage类型.
int imageType;
switch (raster.getNumBands()) {
case 1:
imageType = BufferedImage.TYPE_BYTE_GRAY;
break;
case 3:
imageType = BufferedImage.TYPE_3BYTE_BGR;
break;
case 4:
imageType = BufferedImage.TYPE_4BYTE_ABGR;
break;
default:
throw new UnsupportedOperationException();
}
System.out.println("type:"+imageType);
// 创建一个BufferedImage.
image = new BufferedImage(raster.getWidth(), raster.getHeight(), imageType);
// 设置图片数据.
image.getRaster().setRect(raster);
OutputStream os = null;
try {
os = new FileOutputStream("D:\\test26.png");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 生成图片
try {
ImageIO.write(image, "png", os);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
好那么一点点,半斤八两,继续:
有人说上面的代码转换后颜色不对,是因为cmyk里面有自己的颜色配置文件iccprofile,没读取这个,所有颜色异常:
public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
byte[] profileData = cmykProfile.getData(); // Need to clone entire profile, due to a JDK 7 bug
if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
cmykProfile = ICC_Profile.getInstance(profileData);
}
}
// 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;
}
public static void Test7(String file) {
ICC_Profile iccProfile = null;
try {
iccProfile = Sanselan.getICCProfile(new File(file));//"D:\\color\\CoatedFOGRA27.icc"));
} catch (ImageReadException e2) {
e2.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
if (iccProfile == null) {
System.out.println("icc pro file is null");
return;
}
Iterator readers = ImageIO.getImageReadersByFormatName("jpeg");
ImageReader reader = null;
while (readers.hasNext()) {
reader = (ImageReader) readers.next();
if (reader.canReadRaster()) {
break;
}
}
ImageInputStream input = null;
try {
input = ImageIO.createImageInputStream(new File(file));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (input == null)
return;
reader.setInput(input);
// 创建图片.
BufferedImage image;
try {
// 尝试读取图片 (包括颜色的转换).
image = reader.read(0);
} catch (IOException e) {
// 读取Raster (没有颜色的转换).
Raster raster = null;
try {
raster = reader.readRaster(0, null);
} catch (IOException e1) {
e1.printStackTrace();
}
try {
BufferedImage img = convertCmykToRgb(raster, iccProfile);
if (img != null) {
OutputStream os = null;
try {
os = new FileOutputStream("D:\\test29.jpg");
} catch (FileNotFoundException e4) {
e.printStackTrace();
}
try {
ImageIO.write((RenderedImage) img, "jpg", os);
} catch (IOException e3) {
e.printStackTrace();
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
白色变成了酱紫色。。。可能是我加载iccprofile的方法不对,网上说的去
https://www.adobe.com/support/downloads/iccprofiles/iccprofiles_win.html下载,然后。。真不知道怎么用
找了半天,找到了一个库,twelvemonkeys,地址如下:
https://github.com/haraldk/TwelveMonkeys
源码很庞大,没看,直接用,在上面那个链接里面找到install部分,下载jar包或者添加maven依赖
代码里面直接用下面的方法去读取:
File cmykJPEGFile = new File(file);
BufferedImage image = ImageIO.read(cmykJPEGFile);
然后进行其他操作就没问题了