/* 
 * Example of using the Java Advanced Imaging library to composite two 
 * images that are the same size.
 * 
 * Written by Sean R. Owens, sean at guild dot net, released to the
 * public domain.  Share and enjoy.  Since some people argue that it is
 * impossible to release software to the public domain, you are also free
 * to use this code under any version of the GPL, LPGL, or BSD licenses,
 * or contact me for use of another license.
 * http://darksleep.com/player
 */

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.CompositeDescriptor;

/**
 *
 * @author Sean Owens
 */
public class CompositeExample {

    final static private int IMG_WIDTH = 1024;
    final static private int IMG_HEIGHT = 1024;
    final static private int BLOCK_WIDTH = 400;
    final static private int BLOCK_HEIGHT = 200;

    public BufferedImage createImage(String filename, int x, int y, Color foreColor, Color backColor) {
        BufferedImage image = null;
        image = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = image.createGraphics();
        g2.setColor(backColor);
        g2.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
        g2.setColor(foreColor);
        g2.fillRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT);
        g2.dispose();
        return image;
    }

    // Note that when you run this with the images generated by this code, there is an alpha 
    // channel on each image and the 'background' color of the foreground image has a 0 alpha
    // channel, otherwise the 'background' on the foreground image will entirely overwrite the 
    // background image.
    public RenderedOp composite(String backFilename, String foreFilename) {
        // First let's load both the foreground and background images from file
        RenderedOp backImage = JAI.create("fileload", backFilename);
        RenderedOp foreImage = JAI.create("fileload", foreFilename);

        // Now for each image we need to get the RGB layers, and the Alpha layer.
        // 
        // Note that there is some redundancy in the code below, we could easily
        // refactor these into methods but in the interest of clarity we'll 
        // leave it in.
        int[] bands;
        ParameterBlock params;

        bands = new int[]{0, 1, 2};
        params = new ParameterBlock();
        params.addSource(backImage);
        params.add(bands);
        RenderedOp backRGB = JAI.create("bandSelect", params);

        bands = new int[]{3};
        params = new ParameterBlock();
        params.addSource(backImage);
        params.add(bands);
        RenderedOp backAlpha = JAI.create("bandSelect", params);

        bands = new int[]{0, 1, 2};
        params = new ParameterBlock();
        params.addSource(foreImage);
        params.add(bands);
        RenderedOp foreRGB = JAI.create("bandSelect", params);

        bands = new int[]{3};
        params = new ParameterBlock();
        params.addSource(foreImage);
        params.add(bands);
        RenderedOp foreAlpha = JAI.create("bandSelect", params);

        // Now we perform the composite operation!
        params = new ParameterBlock();

        params.addSource(foreRGB);
        params.addSource(backRGB);
        params.add(foreAlpha);
        params.add(backAlpha);
        params.add(Boolean.FALSE);
        params.add(CompositeDescriptor.DESTINATION_ALPHA_LAST);
//        params.add(CompositeDescriptor.NO_DESTINATION_ALPHA);

        RenderedOp result = JAI.create("composite", params, null);

        return result;
    }

    // NOTE THAT ALL FILES will be written to the "current directory" when you compile and run this file.
    // If you can't figure out where that is after you run this, try changing the file names below 
    // to include the full path to a location, i.e. "C:/background1.png" rather than just "bacground1.png".
    // 
    // Also note that it is not necessary to write files out and read them back in in order to perform
    // the composite, but think it might make things a little easier to follow and anyway it's hard enough
    // finding examples of how to read and write image files using JAI that why not include it.
    public CompositeExample() {
        // background image colors - we generate a red rectangle on a white background
        Color white = new Color(1.0f, 1.0f, 1.0f, 1.0f);
        Color red = new Color(1.0f, 0f, 0f, 1.0f);

        // Note that we set the 'background' color of the foreground image to transparent.  
        Color transparent = new Color(1.0f, 1.0f, 1.0f, 0.0f);
        // and the 'foreground' of the foreground image is half blue - i.e. 50% alpha.
        Color halfBlue = new Color(0f, 0f, 1.0f, .5f);

        // Create and save to file background image
        BufferedImage backgroundImage = createImage("background1.png", 200, 400, red, white);
        RenderedOp op1 = JAI.create("filestore", backgroundImage, "background1.png", "png");

        // Create and save to file foreground image
        BufferedImage foregroundImage = createImage("foreground1.png", 400, 350, halfBlue, transparent);
        RenderedOp op2 = JAI.create("filestore", foregroundImage, "foreground1.png", "png");

        // Composite foreground onto background and save to file
        RenderedOp compositeImage = composite("background1.png", "foreground1.png");
        RenderedOp op3 = JAI.create("filestore", compositeImage, "composite.png", "png");
    }

    public static void main(String[] argv) {
        CompositeExample test = new CompositeExample();
    }
}