如何使用Graphics2D执行MULTIPLY复合效果

时间:2009-03-12 18:50:42

标签: java swing graphics

我有两个不同的javax.swing.Icon对象,我想创建一个新的Icon,它是这两个的组合。我想复合材料是一个MULTIPLY效果,类似于你在选择该选项时在任何类似Photoshop的图像编辑应用程序中获得的效果。具体来说,每个像素,如果您分别从图像1和图像中获得颜色Ca和Cb

Ca =(Ra,Ga,Ba) Cb =(Rb,Gb,Bb)

我希望输出

Cc =(Ra Rb,Ga Gb,Ba * Bb)

我想在运行中实时(实时),所以我必须只使用Graphics2D操作。我看过AlphaComposite并没有看到这可以做到。有人有什么想法吗?

2 个答案:

答案 0 :(得分:3)

你需要的是一个“乘法”alpha复合词。 Conveniently, I asked the same question a while ago about a "screen" effect.我被指向 http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/,它具有您需要的多重复合。

答案 1 :(得分:1)

由于这个问题的大部分答案都指向了很多场外资源,我认为我会在这里提供一个完整的实现。它与您可能已经看到的大型混合模式库基本相同,但为了仅实现特定的混合模式,我已经删除了抽象。

关于以下代码的一些注释:

  • 仅使用g.setComposite(MultiplyComposite.Multiply)

  • MultiplyComposite类同时实现CompositeCompositeContext,因为根据我的需要,两者之间没有任何区别。如果你有一个混合模式,可以调整参数或混合应用不同,你需要分别实现这两个类。

  • 此代码仅适用于32位"整数"缓冲区。你需要修改它以使用16位颜色(移位和屏蔽5/6位而不是8位)

  • 此代码使用最后一个字节作为Alpha通道。您需要修改代码以使用没有Alpha通道(24位)的数据。

  • mixPixel方法中右移8是一种快速除以256的方法。 (a * b) >> 8代替(a * b) / 256

  • 像素从左到右一次处理一行。如果你有更多的内存,你可以修改它以立即处理整个缓冲区。

public class MultiplyComposite implements Composite, CompositeContext {
    protected void checkRaster(Raster r) {
        if (r.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
            throw new IllegalStateException("Expected integer sample type");
        }
    }

    @Override
    public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
        checkRaster(src);
        checkRaster(dstIn);
        checkRaster(dstOut);

        int width = Math.min(src.getWidth(), dstIn.getWidth());
        int height = Math.min(src.getHeight(), dstIn.getHeight());
        int x, y;
        int[] srcPixels = new int[width];
        int[] dstPixels = new int[width];

        for (y=0; y < height; y++) {
            src.getDataElements(0, y, width, 1, srcPixels);
            dstIn.getDataElements(0, y, width, 1, dstPixels);

            for (x=0; x < width; x++) {
                dstPixels[x] = mixPixel(srcPixels[x], dstPixels[x]);
            }

            dstOut.setDataElements(0, y, width, 1, dstPixels);
        }
    }

    private static int mixPixel(int x, int y) {
        int xb = (x) & 0xFF;
        int yb = (y) & 0xFF;
        int b = (xb * yb) / 255;

        int xg = (x >> 8) & 0xFF;
        int yg = (y >> 8) & 0xFF;
        int g = (xg * yg) / 255;

        int xr = (x >> 16) & 0xFF;
        int yr = (y >> 16) & 0xFF;
        int r = (xr * yr) / 255;

        int xa = (x >> 24) & 0xFF;
        int ya = (y >> 24) & 0xFF;
        int a = Math.min(255, xa + ya);

        return (b) | (g << 8) | (r << 16) | (a << 24);
    }


    @Override
    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
        return this;
    }

    @Override
    public void dispose() {

    }

    public static final MultiplyComposite Multiply = new MultiplyComposite();

}