java下cmyk图片读取和转换rgb

记录一下整个过程

第一次采用的办法

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);
然后进行其他操作就没问题了
 

猜你喜欢

转载自blog.csdn.net/ybn187/article/details/52185269