如何在 Java 中更改 BufferedImage 的全局 alpha 值?(IE 使图像中 alpha 值为 100 的每个像素的 alpha 值为 80)
6 回答
@Neil Coffey:谢谢,我也在找这个;但是,您的代码对我来说效果不佳(白色背景变为黑色)。
我编写了这样的代码,并且效果很好:
public void setAlpha(byte alpha) {
alpha %= 0xff;
for (int cx=0;cx<obj_img.getWidth();cx++) {
for (int cy=0;cy<obj_img.getHeight();cy++) {
int color = obj_img.getRGB(cx, cy);
int mc = (alpha << 24) | 0x00ffffff;
int newcolor = color & mc;
obj_img.setRGB(cx, cy, newcolor);
}
}
}
其中 obj_img 是 BufferedImage.TYPE_INT_ARGB。
我用 setAlpha((byte)125); alpha 范围现在是 0-255。
希望有人觉得这很有用。
我不相信有一个简单的命令可以做到这一点。几个选项:
- 复制到另一个指定了AlphaComposite的图像中(缺点:未就地转换)
- 直接操作光栅(缺点:可能导致不受管理的图像)
- 使用过滤器或BufferedImageOp
第一个是最容易实现的,IMO。
这是一个老问题,所以我不是为了OP而回答,而是为了像我这样后来发现这个问题的人。
阿尔法复合材料
正如@Michael 出色的大纲所述,AlphaComposite 操作可以修改 Alpha 通道。但仅在某些方面,对我来说有些难以理解:
是“over”操作如何影响 Alpha 通道的公式。此外,这也会影响 RGB 通道,因此如果您有需要更改的颜色数据,AlphaComposite 不是答案。
缓冲图像操作
查找操作
BufferedImageOp 有多种变体(请参见此处的 4.10.6)。在更一般的情况下,OP 的任务可以通过LookupOp来满足,这需要构建查找数组。要仅修改 Alpha 通道,请为 RGB 通道提供一个标识数组(其中 table[i] = i 的数组),并为 Alpha 通道提供一个单独的数组。用 填充后一个数组table[i] = f(i)
,其中f()
是您想要从旧 alpha 值映射到新值的函数。例如,如果您想“使图像中 alpha 值为 100 的每个像素的 alpha 值为 80”,请设置table[100] = 80
. (完整范围为 0 到 255。)请参阅如何增加代码示例的高斯模糊不透明度。
重新缩放操作
但是对于这些情况的一个子集,有一种更简单的方法可以做到这一点,它不需要设置查找表。如果f()
是一个简单的线性函数,请使用RescaleOp。例如,如果要设置newAlpha = oldAlpha - 20
,请使用比例因子为 1 且偏移量为 -20 的 RescaleOp。如果要设置newAlpha = oldAlpha * 0.8
,请使用 0.8 的 scaleFactor 和 0 的偏移量。在任何一种情况下,您都必须再次为 RGB 通道提供虚拟的 scaleFactors 和偏移量:
new RescaleOp({1.0f, 1.0f, 1.0f, /* alpha scaleFactor */ 0.8f},
{0f, 0f, 0f, /* alpha offset */ -20f}, null)
再次参见此处的 4.10.6中的一些示例,这些示例很好地说明了原理,但并不特定于 Alpha 通道。
为了获得更好看的 alpha 变化效果,您可以使用每个像素的相对 alpha 变化(而不是静态设置或线性裁剪)
public static void modAlpha(BufferedImage modMe, double modAmount) {
//
for (int x = 0; x < modMe.getWidth(); x++) {
for (int y = 0; y < modMe.getHeight(); y++) {
//
int argb = modMe.getRGB(x, y); //always returns TYPE_INT_ARGB
int alpha = (argb >> 24) & 0xff; //isolate alpha
alpha *= modAmount; //similar distortion to tape saturation (has scrunching effect, eliminates clipping)
alpha &= 0xff; //keeps alpha in 0-255 range
argb &= 0x00ffffff; //remove old alpha info
argb |= (alpha << 24); //add new alpha info
modMe.setRGB(x, y, argb);
}
}
}
我 99% 确信声称处理打包到 int 中的“RGB”值的方法实际上处理的是 ARGB。因此,您应该能够执行以下操作:
for (all x,y values of image) {
int argb = img.getRGB(x, y);
int oldAlpha = (argb >>> 24);
if (oldAlpha == 100) {
argb = (80 << 24) | (argb & 0xffffff);
img.setRGB(x, y, argb);
}
}
为了速度,您可以使用这些方法来检索像素值块。
您可能需要先将 BufferedImage 复制到类型为 的图像BufferedImage.TYPE_INT_ARGB
。如果您的图像类型为BufferedImage.TYPE_INT_RGB
,则 alpha 组件将无法正确设置。如果您的 BufferedImage 是 type BufferedImage.TYPE_INT_ARGB
,则下面的代码有效。
/**
* Modifies each pixel of the BufferedImage so that the selected component (R, G, B, or A)
* is adjusted by delta. Note: the BufferedImage must be of type BufferedImage.TYPE_INT_ARGB.
* @param src BufferedImage of type BufferedImage.TYPE_INT_ARGB.
* @param colorIndex 0=red, 1=green, 2=blue, 3= alpha
* @param delta amount to change component
* @return
*/
public static BufferedImage adjustAColor(BufferedImage src,int colorIndex, int delta) {
int w = src.getWidth();
int h = src.getHeight();
assert(src.getType()==BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
int rgb = src.getRGB(x,y);
java.awt.Color color= new java.awt.Color(rgb,true);
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int alpha=color.getAlpha();
switch (colorIndex) {
case 0: red=adjustColor(red,delta); break;
case 1: green=adjustColor(green,delta); break;
case 2: blue=adjustColor(blue,delta); break;
case 3: alpha=adjustColor(alpha,delta); break;
default: throw new IllegalStateException();
}
java.awt.Color adjustedColor=new java.awt.Color(red,green,blue,alpha);
src.setRGB(x,y,adjustedColor.getRGB());
int gottenColorInt=src.getRGB(x,y);
java.awt.Color gottenColor=new java.awt.Color(gottenColorInt,true);
assert(gottenColor.getRed()== red);
assert(gottenColor.getGreen()== green);
assert(gottenColor.getBlue()== blue);
assert(gottenColor.getAlpha()== alpha);
}
return src;
}
private static int adjustColor(int value255, int delta) {
value255+= delta;
if (value255<0) {
value255=0;
} else if (value255>255) {
value255=255;
}
return value255;
}