Java 更改 BufferedImage 的 alpha 值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/660580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Change the alpha value of a BufferedImage?
提问by William
How do I change the global alpha value of a BufferedImage in Java? (I.E. make every pixel in the image that has a alpha value of 100 have a alpha value of 80)
如何在 Java 中更改 BufferedImage 的全局 alpha 值?(IE 使图像中 alpha 值为 100 的每个像素的 alpha 值为 80)
采纳答案by Michael Brewer-Davis
I don't believe there's a single simple command to do this. A few options:
我不相信有一个简单的命令可以做到这一点。几个选项:
- copy into another image with an AlphaCompositespecified (downside: not converted in place)
- directly manipulate the raster(downside: can lead to unmanaged images)
- use a filter or BufferedImageOp
- 复制到另一个指定了AlphaComposite 的图像(缺点:没有就地转换)
- 直接操作光栅(缺点:可能导致非托管图像)
- 使用过滤器或BufferedImageOp
The first is the simplest to implement, IMO.
第一个是最容易实现的,IMO。
回答by Neil Coffey
I'm 99% sure the methods that claim to deal with an "RGB" value packed into an int actually deal with ARGB. So you ought to be able to do something like:
我 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);
}
}
For speed, you could maybe use the methods to retrieve blocks of pixel values.
为了速度,您可以使用这些方法来检索像素值块。
回答by Michael Brewer-Davis
@Neil Coffey: Thanks, I've been looking for this too; however, Your code didn't work very well for me (white background became black).
@Neil Coffey:谢谢,我也在找这个;但是,您的代码对我来说效果不佳(白色背景变为黑色)。
I coded something like this and it works perfectly:
我编码了这样的东西,它完美地工作:
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);
}
}
}
Where obj_img is BufferedImage.TYPE_INT_ARGB.
其中 obj_img 是 BufferedImage.TYPE_INT_ARGB。
I change alpha with setAlpha((byte)125); alpha range is now 0-255.
我用 setAlpha((byte)125) 改变 alpha; alpha 范围现在是 0-255。
Hope someone finds this useful.
希望有人觉得这很有用。
回答by LarsH
This is an old question, so I'm not answering for the sake of the OP, but for those like me who find this question later.
这是一个老问题,所以我不是为了 OP 而回答,而是为了像我这样后来发现这个问题的人。
AlphaComposite
阿尔法复合材料
As @Michael's excellent outline mentioned, an AlphaComposite operation can modify the alpha channel. But only in certain ways, which to me are somewhat difficult to understand:
正如@Michael 的优秀大纲所提到的,AlphaComposite 操作可以修改 alpha 通道。但只是在某些方面,这对我来说有点难以理解:
is the formulafor how the "over" operation affects the alpha channel. Moreover, this affects the RGB channels too, so if you have color data that needs to be unchanged, AlphaComposite is not the answer.
是“过度”操作如何影响 alpha 通道的公式。此外,这也会影响 RGB 通道,因此如果您有需要保持不变的颜色数据,AlphaComposite 不是答案。
BufferedImageOps
缓冲图像操作
LookupOp
查找操作
There are several varieties of BufferedImageOp (see 4.10.6 here). In the more general case, the OP's task could be met by a LookupOp, which requires building lookup arrays. To modify only the alpha channel, supply an identity array (an array where table[i] = i) for the RGB channels, and a separate array for the alpha channel. Populate the latter array with table[i] = f(i)
, where f()
is the function by which you want to map from old alpha value to new. E.g. if you want to "make every pixel in the image that has a alpha value of 100 have a alpha value of 80", set table[100] = 80
. (The full range is 0 to 255.) See how to increase opacity in gaussian blurfor a code sample.
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。)查看如何为代码示例增加高斯模糊的不透明度。
RescaleOp
重新缩放操作
But for a subset of these cases, there is a simpler way to do it, that doesn't require setting up a lookup table. If f()
is a simple, linear function, use a RescaleOp. For example, if you want to set newAlpha = oldAlpha - 20
, use a RescaleOp with a scaleFactor of 1 and an offset of -20. If you want to set newAlpha = oldAlpha * 0.8
, use a scaleFactor of 0.8 and an offset of 0. In either case, you again have to provide dummy scaleFactors and offsets for the RGB channels:
但是对于这些情况的一个子集,有一种更简单的方法来做到这一点,不需要设置查找表。如果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)
Again see 4.10.6 herefor some examples that illustrate the principles well, but are not specific to the alpha channel.
再次参见4.10.6 此处的一些示例,这些示例很好地说明了原理,但并非特定于 alpha 通道。
Both RescaleOpand LookupOpallow modifying a BufferedImage in-place.
无论RescaleOp中和LookupOp允许修改就地一个BufferedImage。
回答by Thumbz
for a nicer looking alpha change effect, you can use relative alpha change per pixel (rather than static set, or clipping linear)
为了获得更好看的 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);
}
}
}
回答by Don Smith
You may need to first copy your BufferedImage to an image of type BufferedImage.TYPE_INT_ARGB
. If your image is of type, say, BufferedImage.TYPE_INT_RGB
, then the alpha component won't be set correctly. If your BufferedImage is of type BufferedImage.TYPE_INT_ARGB
, then the code below works.
/**
* 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;
}
您可能需要先将 BufferedImage 复制到类型为 的图像BufferedImage.TYPE_INT_ARGB
。如果您的图像类型为 ,BufferedImage.TYPE_INT_RGB
则 alpha 组件将无法正确设置。如果您的 BufferedImage 类型为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;
}