3

我正在使用 Java 类RescaleOp来更改BufferedImage实例的亮度。Alpha 通道始终会导致问题。请参阅下面的参考资料——感谢@trashgod令人印象深刻的 Java2D 见解。

来自alpha 通道实例的文档RescaleOp明确说明在单因素构造函数中没有缩放——我将其解释为or 。BufferedImagefloatfloat[1]

来自 JDK6 的引用:(添加了重点)

对于 BufferedImages,重新缩放对颜色和 alpha 分量进行操作。缩放常数组的数量可以是一组,在这种情况下,相同的常数将应用于所有颜色(但不是 alpha)分量。否则,缩放常数集的数量可能等于源颜色分量的数量,在这种情况下,不会执行 alpha 分量(如果存在)的重新缩放。如果这两种情况都不适用,则缩放常数集的数量必须等于源颜色分量加上 alpha 分量的数量,在这种情况下,所有颜色和 alpha 分量都会重新缩放。

对于BufferedImagewith type BufferedImage.TYPE_INT_ARGB,有四个通道 (RGBA),其中 alpha 是最后一个通道。(他们为什么不叫它BufferedImage.TYPE_INT_RGBA?)我尝试了这些RescaleOp转换但没有成功:(假设float scaleFactor = 1.25ffloat 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)
  1. 我是否误解了官方的 JDK 文档?
  2. 或者,这是一个可以/应该在未来的 JDK 中修复的错误?
  3. 有没有办法找到(在运行时)alpha 通道索引?
    • 可能有帮助的方法:
      1. ColorModel BufferedImage.getColorModel()
      2. int ColorModel.getNumColorComponents()
      3. boolean ColorModel.hasAlpha()
      4. int ColorModel.getNumComponents()(可能包括可选的 Alpha 通道)
      5. ColorSpace ColorModel.getColorSpace()

请指教。

4

2 回答 2

1

RescaleOp在具有直接颜色模型的栅格上提供两种操作模式。这两种模式对应于两个构造函数。

  1. RescaleOp(float scaleFactor, float offset, RenderingHints hints),如图所示按相同的因子缩放所有颜色分量,并使 Alpha 通道保持不变。

  2. RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints),在引用的第二个示例中说明,要求“缩放常数集的数量必须等于源颜色分量加上 alpha 分量的数量”。ABufferedImage类型TYPE_INT_ARGB有三个颜色分量加上一个 alpha 分量,所以scaleFactors数组必须有四个分量。

不同的是方便。内部循环相应地遍历数组。

int step = 0;
…
if (length > 1) {
    step = 1;
}

总之,您的第一个示例应该有效;你的第二个和第三个例子应该抛出一个IllegalArgumentException;你的第四个作品如广告所示。

于 2013-08-14T08:45:13.123 回答
1

API 文档中的引用:

缩放常数组的数量可以是一组,在这种情况下,相同的常数将应用于所有颜色(但不是 alpha)分量。

按记录工作。

否则,缩放常数集的数量可能等于源颜色分量的数量,在这种情况下,不会执行 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 位)
  • 对于ComponentSampleModelComponentSampleModel.getBandOffsets()

于 2013-08-15T17:40:17.460 回答