java - 尝试设置颜色的 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);
boolean transparent = (rgb & 0xFF000000) == 0x0;
boolean opaque = (rgb & 0xFF000000) == 0xFF000000;
if (!transparent && !opaque)
{
rgb = rgb | 0xFF000000;
image2.setRGB(width, height, rgb);
} else
{
image2.setRGB(width, height, image.getRGB(width, height));
}
}
}
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;
}
}
解决方案
输入图像的主要问题是它在完全透明的像素周围有一个几乎透明的“光环”,有点像“抖动”的透明度。当您将这些像素完全不透明时,它们 a)在您不想要它们的地方创建不透明像素,并且 b)使这些像素过于饱和,因为像素没有与 alpha 预乘(如果你是,你可以谷歌“预乘 alpha”对 alpha 合成/混合感兴趣)。请注意,像素并没有真正“改变颜色”,只是它们通常对最终结果贡献不大,因为它们几乎是完全透明的。
无论背景颜色如何,简单的解决方法都可以正常工作,只是使用阈值来决定像素是否应该是透明的。
如果您知道背景颜色(纯色或某种“平均”),则可以使用 alpha 值将像素颜色与背景颜色混合。这将创建更平滑的边缘,但仅针对此背景。在这种情况下,您可以使用较低的阈值。
这是您的代码的修改版本,可为您的输入产生更好的结果:
public static void main(String args[]) throws IOException {
File file = new File(args[0]);
BufferedImage image = convertToType(ImageIO.read(file), BufferedImage.TYPE_INT_ARGB);
Color bg = Color.ORANGE; // Change to the color of your background, if you want to blend
int bgR = bg.getRed();
int bgG = bg.getGreen();
int bgB = bg.getBlue();
for (int width = 0; width < image.getWidth(); width++) {
for (int height = 0; height < image.getHeight(); height++) {
int rgb = image.getRGB(width, height);
int opaqueness = (rgb >>> 24) & 0xFF;
if (opaqueness > 100) { // The threshold 100 works fine for your current input, tune to suit other needs
// Fully opaque
image.setRGB(width, height, rgb | 0xFF000000);
// Or if you prefer blending the background:
/*
// Multiply alpha
int r = ((rgb >> 16 & 0xFF) * opaqueness) + (bgR * (0xFF - opaqueness)) >> 8;
int g = ((rgb >> 8 & 0xFF) * opaqueness) + (bgG * (0xFF - opaqueness)) >> 8;
int b = ((rgb & 0xFF) * opaqueness) + (bgB * (0xFF - opaqueness)) >> 8;
image.setRGB(width, height, r << 16 | g << 8 | b | 0xFF000000);
*/
} else {
// Fully transparent
image.setRGB(width, height, rgb & 0xFFFFFF);
}
}
}
ImageIO.write(image, "png", new File(file.getParentFile(), file.getName() + "_copy_bg_mult.png"));
}
public static BufferedImage convertToType(BufferedImage image, int type) {
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
Graphics2D graphics = newImage.createGraphics();
graphics.setComposite(AlphaComposite.Src);
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
return newImage;
}
代码原样将创建一个像这样的图像,它会有轻微的锯齿状边缘,但“光环”被删除:
或者,如果您注释掉“完全不透明”版本,并在“乘 alpha”部分进行注释,您可以获得这样的图像(显然只有在黄色背景下才会好看):
推荐阅读
- python - PyQt5 event.button() - 鼠标中键关闭选项卡可防止在 OS X 上选择选项卡
- jhipster - 杰普斯特错误!在 ~(Table Names) 寻找 otherEntity Authority 时出错
- r - 如何使这些样条线的颜色变暗?
- java - Mockito Spy:想要但没有被调用,但它是
- asp.net-mvc - ASP.NET MVC:无法发布值数组
- javascript - 如何修剪 IG Popup LOV 上的空格?
- excel - 关于从 Excel 工作表读取数据并通过 Replace 和 FileSystemObject 写入预定义文件的宏的建议
- node.js - nodejs 背靠背运行函数
- excel - 当数字为文本形式时如何将单元格相加?
- c - 为什么 gmtime_r 和 localtime_r 返回同一时间?