Java修改图像alpha值为完全不透明时出现色彩异常问题
问题说明
你编写代码的目标是移除图像中的半透明属性,将所有半透明像素调整为完全不透明,但运行后图像色彩出现大幅偏移,以下是效果对比:
- 修改前:

- 修改后:

问题原因
色彩失真是由预乘Alpha(Premultiplied Alpha) 存储规则导致的:绝大多数带透明通道的PNG图像会对像素值做预乘处理,半透明像素的R/G/B通道值已经预先和归一化后的Alpha值(0-1)做了乘法运算。比如某像素完全不透明时的颜色为(255,255,255),如果Alpha值为0.5,实际存储的R/G/B值就是(127,127,127)。你直接强制把Alpha通道改为完全不透明,但R/G/B值还是预乘后的低值,显示出来自然会偏暗、饱和度降低。
修复方案
处理半透明像素时,先将预乘后的R/G/B值按当前Alpha值还原为未做乘法的原始颜色,再将Alpha通道设为完全不透明即可,修复后代码如下:
public class Main { public static void main(String args[]) throws IOException { File file = new File("karambitlore.png"); FileInputStream fis = new FileInputStream(file); BufferedImage image = ImageIO.read(fis); image = convertToType(image, BufferedImage.TYPE_INT_ARGB); BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); for (int width = 0; width < image.getWidth(); width++) { for (int height = 0; height < image.getHeight(); height++) { int rgb = image.getRGB(width, height); int alpha = (rgb >> 24) & 0xff; if (alpha != 0 && alpha != 0xff) { // 拆分RGB三个通道 int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; // 还原预乘前的原始颜色,做边界限制防止数值溢出 float factor = 255f / alpha; r = Math.min((int)(r * factor), 255); g = Math.min((int)(g * factor), 255); b = Math.min((int)(b * factor), 255); // 重新组合ARGB值,Alpha设为完全不透明 rgb = (0xff << 24) | (r << 16) | (g << 8) | b; } image2.setRGB(width, height, rgb); } } fis.close(); ImageIO.write(image2, "png", file); System.out.println(image.getType()); } public static BufferedImage convertToType(BufferedImage image, int type) { BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type); Graphics2D graphics = newImage.createGraphics(); graphics.drawImage(image, 0, 0, null); graphics.dispose(); return newImage; } }
内容的提问来源于stack exchange,提问作者Symphonic
相关产品推荐
相关产品推荐

