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

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

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

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

转换前的PNG图像

转换前的 PNG 图像

转换后的JPEG图像

转换后的 JPEG 图像

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

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

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

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

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

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

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

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

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

完整的代码

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

留言

2011-10-18
次访问