在JAVA中将透明的图像转换成JPEG格式

在JAVA中将透明的图像转换成JPEG格式

在JAVA中将图像文件转换成JPEG,通常使用下面的代码:

 1File __pngFile = new File("exportUnit.png");
 2File __jpgFile = new File("exportUnit.jpg");
 3writeJPEG(__pngFile, __jpgFile, 80);
 4
 5public static void writeJPEG(File $source, File $dest, int $quality) throws IOException
 6{
 7	String __formatName = "jpeg";
 8	BufferedImage __image = ImageIO.read($source);
 9	ImageWriter __writer = ImageIO.getImageWritersByFormatName(__formatName).next();
10	ImageWriteParam __writeParam = __writer.getDefaultWriteParam();
11	FileOutputStream __out = new FileOutputStream($dest);
12	__writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
13	__writeParam.setCompressionQuality((float)$quality/100f);
14	__writer.setOutput(ImageIO.createImageOutputStream(__out));
15	__writer.write(null, new IIOImage(__image, null, null), __writeParam);
16	__out.flush();
17	__out.close();
18	__writer.dispose();
19}

但是,当被转换的文件是32位带Alpha通道的图像文件转换为JPEG的时候,会出现颜色错误。就像下面这样:

转换前的PNG图像

转换前的 PNG 图像

转换后的JPEG图像

转换后的 JPEG 图像

出现这种错误的原因,是强行将32位的ARGB图像转换成了24位的RGB图像,转换过程中没有指定正确的色彩转换方式。下面的2种方法都可以解决这个问题。

要使用这2种方法,可以在writeJPEG方法中加入下面的判断:

1//如果图像是透明的,就丢弃Alpha通道
2if(__image.getTransparency() == Transparency.TRANSLUCENT)
3	__image = get24BitImage(__image);
4	//__image = get24BitImage(__image, Color.BLACK);

第一种方法,删除32位ARGB颜色中的Alpha通道

根据ARGB的颜色表示法,32位颜色的前8位代表Alpha值。因此只需要将前8位去掉,就得到了不带Alpha通道的24位颜色值。详见下面的代码:

 1/**
 2 * 使用删除alpha值的方式去掉图像的alpha通道
 3 * @param $image
 4 * @return
 5 */
 6protected static BufferedImage get24BitImage(BufferedImage $image)
 7{
 8	int __w = $image.getWidth();
 9	int __h = $image.getHeight();
10	int[] __imgARGB = getRGBs($image.getRGB(0, 0, __w, __h, null, 0, __w));
11	BufferedImage __newImg = new BufferedImage(__w, __h, BufferedImage.TYPE_INT_RGB);
12	__newImg.setRGB(0, 0, __w, __h, __imgARGB, 0, __w);
13	return __newImg;
14}
15
16/**
17 * 将32位色彩转换成24位色彩(丢弃Alpha通道)
18 * @param $argb
19 * @return
20 */
21public static int[] getRGBs(int[] $argb)
22{
23	int[] __rgbs = new int[$argb.length];
24	for(int i=0;i<$argb.length;i++)
25	{
26		__rgbs[i] = $argb[i] & 0xFFFFFF;
27	}
28	return __rgbs;
29}

第二种方法,使用绘制的方式去掉图像的alpha值

使用这种方法的优势在于,可以很方便的控制生成的JPEG图像的背景色。

 1/**
 2 * 使用绘制的方式去掉图像的alpha值
 3 * @param $image
 4 * @param $bgColor
 5 * @return
 6 */
 7protected static BufferedImage get24BitImage(BufferedImage $image, Color $bgColor)
 8{
 9	int $w = $image.getWidth();
10	int $h = $image.getHeight();
11	BufferedImage __image = new BufferedImage($w, $h, BufferedImage.TYPE_INT_RGB);
12	Graphics2D __graphic = __image.createGraphics();
13	__graphic.setColor($bgColor);
14	__graphic.fillRect(0,0,$w,$h);
15	__graphic.drawRenderedImage($image, null);
16	__graphic.dispose();
17	return __image; 
18}

完整的代码

 1import java.awt.Color;
 2import java.awt.Graphics2D;
 3import java.awt.Transparency;
 4import java.awt.image.BufferedImage;
 5import java.io.File;
 6import java.io.FileOutputStream;
 7import java.io.IOException;
 8
 9import javax.imageio.IIOImage;
10import javax.imageio.ImageIO;
11import javax.imageio.ImageWriteParam;
12import javax.imageio.ImageWriter;
13
14public class ConvertJPEG
15{
16
17	/**
18	 * @param args
19	 * @throws IOException 
20	 */
21	public static void main(String[] args) throws IOException
22	{
23		File __pngFile = new File("exportUnit.png");
24		File __jpgFile = new File("exportUnit.jpg");
25		writeJPEG(__pngFile, __jpgFile, 80);
26	}
27	
28	public static void writeJPEG(File $source, File $dest, int $quality) throws IOException
29	{
30		String __formatName = "jpeg";
31		BufferedImage __image = ImageIO.read($source);
32		//如果图像是透明的,就丢弃Alpha通道
33		if(__image.getTransparency() == Transparency.TRANSLUCENT)
34			__image = get24BitImage(__image);
35			//__image = get24BitImage(__image, Color.BLACK);
36		ImageWriter __writer = ImageIO.getImageWritersByFormatName(__formatName).next();
37		ImageWriteParam __writeParam = __writer.getDefaultWriteParam();
38		FileOutputStream __out = new FileOutputStream($dest);
39		__writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
40		__writeParam.setCompressionQuality((float)$quality/100f);
41		__writer.setOutput(ImageIO.createImageOutputStream(__out));
42		__writer.write(null, new IIOImage(__image, null, null), __writeParam);
43		__out.flush();
44		__out.close();
45		__writer.dispose();
46	}
47	
48	/**
49	 * 使用删除alpha值的方式去掉图像的alpha通道
50	 * @param $image
51	 * @return
52	 */
53	protected static BufferedImage get24BitImage(BufferedImage $image)
54	{
55		int __w = $image.getWidth();
56		int __h = $image.getHeight();
57		int[] __imgARGB = getRGBs($image.getRGB(0, 0, __w, __h, null, 0, __w));
58		BufferedImage __newImg = new BufferedImage(__w, __h, BufferedImage.TYPE_INT_RGB);
59		__newImg.setRGB(0, 0, __w, __h, __imgARGB, 0, __w);
60		return __newImg;
61	}
62	
63	/**
64	 * 使用绘制的方式去掉图像的alpha值
65	 * @param $image
66	 * @param $bgColor
67	 * @return
68	 */
69	protected static BufferedImage get24BitImage(BufferedImage $image, Color $bgColor)
70	{
71		int $w = $image.getWidth();
72		int $h = $image.getHeight();
73		BufferedImage __image = new BufferedImage($w, $h, BufferedImage.TYPE_INT_RGB);
74		Graphics2D __graphic = __image.createGraphics();
75		__graphic.setColor($bgColor);
76		__graphic.fillRect(0,0,$w,$h);
77		__graphic.drawRenderedImage($image, null);
78		__graphic.dispose();
79		return __image; 
80	}
81	
82	/**
83	 * 将32位色彩转换成24位色彩(丢弃Alpha通道)
84	 * @param $argb
85	 * @return
86	 */
87	public static int[] getRGBs(int[] $argb)
88	{
89		int[] __rgbs = new int[$argb.length];
90		for(int i=0;i<$argb.length;i++)
91		{
92			__rgbs[i] = $argb[i] & 0xFFFFFF;
93		}
94		return __rgbs;
95	}
96}