| ColorBlitter |

    package ij.process;
    import java.awt.*;
    import java.awt.image.*;

    /** This class does bit blitting of RGB images. */
    public class ColorBlitter implements Blitter {

        private ColorProcessor ip;
        private int width, height;
        private int[] pixels;
        private int transparent = 0xffffff;

        /** Constructs a ColorBlitter from a ColorProcessor. */
        public ColorBlitter(ColorProcessor ip) {
            this.ip = ip;
            width = ip.getWidth();
            height = ip.getHeight();
            pixels = (int[])ip.getPixels();
        }

        public void setTransparentColor(Color c) {
            transparent = c.getRGB()&0xffffff;
        }

        /** Copies the RGB image in 'ip' to (x,y) using the specified mode. */
        public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
            int srcIndex, dstIndex;
            int xSrcBase, ySrcBase;
            int[] srcPixels;

            int srcWidth = ip.getWidth();
            int srcHeight = ip.getHeight();
            Rectangle rect1 = new Rectangle(srcWidth, srcHeight);
            rect1.setLocation(xloc, yloc);
            Rectangle rect2 = new Rectangle(width, height);
            if (!rect1.intersects(rect2))
                return;
            if (ip instanceof ByteProcessor) {
                byte[] pixels8 = (byte[])ip.getPixels();
                ColorModel cm = ip.getColorModel();
                if (ip.isInvertedLut())
                    cm = ip.getDefaultColorModel();
                int size = ip.getWidth()*ip.getHeight();
                srcPixels = new int[size];
                int v;
                for (int i=0; i<size; i++)
                    srcPixels[i] = cm.getRGB(pixels8[i]&255);
            } else
                srcPixels = (int[])ip.getPixels();
            rect1 = rect1.intersection(rect2);
            xSrcBase = (xloc<0)?-xloc:0;
            ySrcBase = (yloc<0)?-yloc:0;
            int c1, c2, r1, g1, b1, r2, g2, b2;
            int src, dst;

            if (mode==COPY || mode==COPY_TRANSPARENT) {
                for (int y=rect1.y; y<(rect1.y+rect1.height); y++) {
                    srcIndex = (y-yloc)*srcWidth + (rect1.x-xloc);
                    dstIndex = y * width + rect1.x;
                    if (mode==COPY)
                        for (int i=rect1.width; --i>=0;)
                            pixels[dstIndex++] = srcPixels[srcIndex++];
                    else
                        for (int i=rect1.width; --i>=0;) {
                            src = srcPixels[srcIndex++];
                            dst = pixels[dstIndex];
                            pixels[dstIndex++] = (src&0xffffff)==transparent?dst:src;
                        }
                }
                return;
            }

            for (int y=rect1.y; y<(rect1.y+rect1.height); y++) {
                srcIndex = (y-yloc)*srcWidth + (rect1.x-xloc);
                dstIndex = y * width + rect1.x;
                for (int i=rect1.width; --i>=0;) {
                    c1 = srcPixels[srcIndex++];
                    r1 = (c1&0xff0000)>>16;
                    g1 = (c1&0xff00)>>8;
                    b1 = c1&0xff;
                    c2 = pixels[dstIndex];
                    r2 = (c2&0xff0000)>>16;
                    g2 = (c2&0xff00)>>8;
                    b2 = c2&0xff;
                    switch (mode) {
                        case COPY_INVERTED:
                            break;
                        case ADD:
                                r2=r1+r2; g2=g1+g2; b2=b1+b2;
                                if (r2>255) r2=255; if (g2>255) g2=255; if (b2>255) b2=255;
                            break;
                        case AVERAGE:
                                r2=(r1+r2)/2; g2=(g1+g2)/2; b2=(b1+b2)/2;
                            break;
                        case SUBTRACT:
                                r2=r2-r1; g2=g2-g1; b2=b2-b1;
                                if (r2<0) r2=0; if (g2<0) g2=0; if (b2<0) b2=0;
                            break;
                        case DIFFERENCE:
                                r2=r2-r1; if (r2<0) r2=-r2;
                                g2=g2-g1; if (g2<0) g2=-g2;
                                b2=b2-b1; if (b2<0) b2=-b2;
                            break;
                        case MULTIPLY:
                                r2=r1*r2; g2=g1*g2; b2=b1*b2;
                                if (r2>255) r2=255; if (g2>255) g2=255; if (b2>255) b2=255;
                            break;
                        case DIVIDE:
                                if (r1==0) r2=255; else r2=r2/r1;
                                if (g1==0) g2=255; else g2=g2/g1;
                                if (b1==0) b2=255; else b2=b2/b1;
                            break;
                        case AND:
                            r2=r1&r2; g2=g1&g2; b2=b1&b2;
                            break;
                        case OR:
                            r2=r1|r2; g2=g1|g2; b2=b1|b2;
                            break;
                        case XOR:
                            r2=r1^r2; g2=g1^g2; b2=b1^b2;
                            break;
                        case MIN:
                            if (r1<r2) r2 = r1;
                            if (g1<g2) g2 = g1;
                            if (b1<b2) b2 = b1;
                            break;
                        case MAX:
                            if (r1>r2) r2 = r1;
                            if (g1>g2) g2 = g1;
                            if (b1>b2) b2 = b1;
                            break;
                    }
                    pixels[dstIndex++] = 0xff000000 + (r2<<16) + (g2<<8) + b2;
                }
                if (y%20==0)
                    ip.showProgress((double)(y-rect1.y)/rect1.height);
            }
            ip.showProgress(1.0);
        }
    }

| ColorBlitter |