我正在使用Java类RescaleOp
来更改BufferedImage
个实例的亮度。 alpha通道始终导致问题。请参阅下面的参考资料 - 感谢@trashgod对他令人印象深刻的Java2D见解。
来自RescaleOp
的文档清楚地说明BufferedImage
的实例,alpha通道在单因素构造函数中不 - 我将其解释为float
或float[1]
。
Quote from JDK6 :(强调补充)
对于BufferedImages,重新缩放对颜色和alpha分量进行操作。 缩放常数组的数量可以是1,在这种情况下 相同的常量应用于所有颜色(但不是alpha )组件。 否则,缩放常数组的数量可能等于 源颜色组件的数量,在这种情况下没有重新缩放 执行alpha分量(如果存在)。如果这两种情况都没有 apply,缩放常量集的数量必须等于数量 源颜色组件加上alpha组件,在这种情况下全部 颜色和alpha组件重新调整。
对于类型为BufferedImage
的{{1}},有四个频道(R-G-B-A),其中alpha是最后一个频道。 (他们为什么不称它为BufferedImage.TYPE_INT_ARGB
?)我尝试了这些BufferedImage.TYPE_INT_RGBA
转换但没有成功:(假设RescaleOp
和float scaleFactor = 1.25f
)
float offset = 0.0f
只有这样才有效:(假设为new RescaleOp(scaleFactor, offset, (RenderingHints) null)
new RescaleOp(new float[] { scaleFactor },
new float[] { offset },
(RenderingHints) null)
new RescaleOp(new float[] { scaleFactor, scaleFactor, scaleFactor },
new float[] { offset, offset, offset },
(RenderingHints) null)
)
float alphaScaleFactor = 1.0f
new RescaleOp(new float[] { scaleFactor, scaleFactor, scaleFactor, alphaScaleFactor },
new float[] { offset, offset, offset, offset },
(RenderingHints) null)
ColorModel BufferedImage.getColorModel()
int ColorModel.getNumColorComponents()
boolean ColorModel.hasAlpha()
(可能包含可选的Alpha频道)int ColorModel.getNumComponents()
请告知。
答案 0 :(得分:1)
RescaleOp
在具有直接颜色模型的栅格上提供两种操作模式。这两种模式对应于两个构造函数。
RescaleOp(float scaleFactor, float offset, RenderingHints hints)
,图示here,按相同因子缩放所有颜色分量,并保持Alpha通道不变。
RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints)
,如引用的第二个example所示,要求“缩放常量集的数量必须等于源颜色组件的数量加上alpha零件。” BufferedImage
类型TYPE_INT_ARGB
有三个颜色组件加一个alpha组件,因此scaleFactors
数组必须有四个组件。
不同之处在于便利性。内部循环相应地逐步遍历数组。
int step = 0;
…
if (length > 1) {
step = 1;
}
总之,你的第一个例子应该有效;你的第二个和第三个例子应该抛出IllegalArgumentException
;而你的第四部作品就像宣传的一样。
答案 1 :(得分:1)
来自API文档的引言:
缩放常数组的数量可以是1,在这种情况下,相同的常数应用于所有颜色(但不是alpha)组件。
按照记录的方式工作。
否则,缩放常数组的数量可以等于源颜色分量的数量,在这种情况下,不执行α分量(如果存在)的重新缩放。
仅在源中不存在alpha分量时才有效。没有记录。
如果这两种情况都不适用,则缩放常数集的数量必须等于源颜色分量加上alpha分量的数量,在这种情况下,所有颜色和alpha分量都会重新调整
按照记录的方式工作。
考虑这个测试用例:
public class RescaleOpTest {
public static void main(String[] args) {
BufferedImage rgb = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
// All ok
new RescaleOp(new float[] {1}, new float[] {1}, null).filter(rgb, rgb);
new RescaleOp(new float[] {1, 1, 1}, new float[] {1, 1, 1}, null).filter(rgb, rgb);
BufferedImage argb = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
new RescaleOp(new float[] {1}, new float[] {1}, null).filter(argb, argb); // Ok
new RescaleOp(new float[] {1, 1, 1, 1}, new float[] {1, 1, 1, 1}, null).filter(argb, argb); // Ok
WritableRaster argbRaster = argb.getRaster();
new RescaleOp(new float[] {1}, new float[] {1}, null).filter(argbRaster, argbRaster); // Ok
new RescaleOp(new float[] {1, 1, 1, 1}, new float[] {1, 1, 1, 1}, null).filter(argbRaster, argbRaster); // Ok
WritableRaster rgbRaster = argbRaster.createWritableChild(0, 0, argb.getWidth(), argb.getHeight(), 0, 0, new int[] {0, 1, 2});
new RescaleOp(new float[] {1}, new float[] {1}, null).filter(rgbRaster, rgbRaster); // Ok
new RescaleOp(new float[] {1, 1, 1}, new float[] {1, 1, 1}, null).filter(rgbRaster, rgbRaster); // Ok
new RescaleOp(new float[] {1, 1, 1}, new float[] {1, 1, 1}, null).filter(argb, argb); // Boom, even though it's the same image, so rasters can't possibly be wrong...
}
}
我说这是一个错误,你的代码应该可行。不记得我是否提交了它,或者当我遇到它时是否已经有匹配的错误报告。但是不要屏住呼吸等待Oracle修复它...解决方法是始终拥有与栅格中的组件/波段一样多的比例因子/偏移(或使用子栅格来掩盖alpha,如图所示在上面的代码中。)
要查找alpha样本的索引,请查看SampleModel
。我不认为你需要它RescaleOp
,因为顺序总是先是颜色,然后是alpha(即R,G,B,A总是,不论ARGB,ABGR,RGBA等)。无论如何,取决于你拥有的SampleModel
的类型(是的,不幸的是,你必须施放):
SinglePixelPackedSampleModel
:
SinglePixelPackedSampleModel.getBitMasks()
(您可以从中计算位偏移/位大小)SinglePixelPackedSampleModel.getBitOffsets()
(但你需要以某种方式获得位大小,或假设它是8位)适用于ComponentSampleModel
:ComponentSampleModel.getBandOffsets()
。