RescaleOp根据文档不起作用

时间:2013-08-14 03:51:12

标签: java swing graphics awt bufferedimage

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

来自RescaleOp的文档清楚地说明BufferedImage的实例,alpha通道在单因素构造函数中 - 我将其解释为floatfloat[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转换但没有成功:(假设RescaleOpfloat 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
  1. 我是否误解了官方的JDK文档?
  2. 或者,这是一个可以/应该在将来的JDK中修复的错误吗?
  3. 有没有办法找到(在运行时)alpha通道索引?
    • 可能有用的方法:
      1. new RescaleOp(new float[] { scaleFactor, scaleFactor, scaleFactor, alphaScaleFactor }, new float[] { offset, offset, offset, offset }, (RenderingHints) null)
      2. ColorModel BufferedImage.getColorModel()
      3. int ColorModel.getNumColorComponents()
      4. boolean ColorModel.hasAlpha()(可能包含可选的Alpha频道)
      5. int ColorModel.getNumComponents()
  4. 请告知。

2 个答案:

答案 0 :(得分:1)

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

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

  2. RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints),如引用的第二个example所示,要求“缩放常量集的数量必须等于源颜色组件的数量加上alpha零件。” BufferedImage类型TYPE_INT_ARGB有三个颜色组件加一个alpha组件,因此scaleFactors数组必须有四个组件。

  3. 不同之处在于便利性。内部循环相应地逐步遍历数组。

    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位)
  • 适用于ComponentSampleModelComponentSampleModel.getBandOffsets()