| CompositeImage |

    package ij;
    import ij.process.*;
    import ij.gui.*;
    import java.awt.*;
    import java.awt.image.*;
    import ij.plugin.*;
    import ij.plugin.frame.ContrastAdjuster;

    public class CompositeImage extends ImagePlus {

        int[] awtImagePixels;
        boolean newPixels;
        MemoryImageSource imageSource;
        ColorModel imageColorModel;
        Image awtImage;
        int[][] pixels;
        ImageProcessor[] cip;
        Color[] colors = {Color.red, Color.green, Color.blue, Color.white, Color.cyan, Color.magenta, Color.yellow};
        int currentChannel = 0;
        static int count;
        boolean singleChannel;

        public CompositeImage(ImagePlus imp, int channels) {
            //count++; if (count==1) throw new IllegalArgumentException("");
            ImageStack stack2;
            boolean isRGB = imp.getBitDepth()==24;
            if (isRGB)
                stack2 = getRGBStack(imp);
            else
                stack2 = imp.getStack();
            int stackSize = stack2.getSize();
            if (channels<2 || (stackSize%channels)!=0)
                throw new IllegalArgumentException("channels<2 or stacksize not multiple of channels");
            compositeImage = true;
            setDimensions(channels, stackSize/channels, 1);
            setup(channels, stack2);
            setStack(imp.getTitle(), stack2);
            setCalibration(imp.getCalibration());
            Object info = imp.getProperty("Info");
            if (info!=null)
                setProperty("Info", imp.getProperty("Info"));
        }

        public Image getImage() {
            if (img==null)
                updateImage();
            return img;
        }

        public void updateChannelAndDraw() {
            singleChannel = true;
            updateAndDraw();
        }

        public ImageProcessor getChannelProcessor() {
            return cip[currentChannel];
        }

        void setup(int channels, ImageStack stack2) {
            cip = new ImageProcessor[channels];
            for (int i=0; i<channels; ++i) {
                cip[i] = stack2.getProcessor(i+1);
                cip[i].resetMinAndMax();
                cip[i].setColorModel(createModelFromColor(colors[i]));
            }
        }

        public void updateImage() {
            int imageSize = width*height;
            int nChannels = getNChannels();
            int redValue, greenValue, blueValue;
            int slice = getCurrentSlice();

            if (nChannels==1) {
                pixels = null;
                awtImagePixels = null;
                if (ip!=null)
                    img = ip.createImage();
                return;

            }

            if (cip!=null && cip[0].getWidth()!=width||cip[0].getHeight()!=height||(pixels!=null&&pixels.length!=nChannels)) {
                setup(nChannels, getStack());
                pixels = null;
                awtImagePixels = null;
                if (slice>nChannels) {
                    setSlice(1);
                    slice = 1;
                }
            }
            if (slice>nChannels) slice = nChannels;

            if (slice-1!=currentChannel) {
                currentChannel = slice-1;
                getProcessor().setMinAndMax(cip[currentChannel].getMin(), cip[currentChannel].getMax());
                ContrastAdjuster.update();
            }
            //IJ.log(nChannels+" "+slice+" "+currentChannel);

            if (awtImagePixels == null) {
                awtImagePixels = new int[imageSize];
                newPixels = true;
                imageSource = null;
            }
            if (pixels==null || pixels.length!=nChannels || pixels[0].length!=imageSize) {
                pixels = new int[nChannels][];
                for (int i=0; i<nChannels; ++i)
                    pixels[i] = new int[imageSize];
            }

            ImageProcessor ip = getProcessor();
            cip[currentChannel].setMinAndMax(ip.getMin(),ip.getMax());
            if (singleChannel) {
                PixelGrabber pg = new PixelGrabber(cip[currentChannel].createImage(), 0, 0, width, height, pixels[currentChannel], 0, width);
                try { pg.grabPixels();}
                catch (InterruptedException e){};
            } else {
                for (int i=0; i<nChannels; ++i) {
                    PixelGrabber pg = new PixelGrabber(cip[i].createImage(), 0, 0, width, height, pixels[i], 0, width);
                    try { pg.grabPixels();}
                    catch (InterruptedException e){};
                }
            }
            if (singleChannel && nChannels<=3) {
                switch (currentChannel) {
                    case 0:
                        for (int i=0; i<imageSize; ++i) {
                            redValue = (pixels[0][i]>>16)&0xff;
                            awtImagePixels[i] = (awtImagePixels[i]&0xff00ffff) | (redValue<<16);
                        }
                        break;
                    case 1:
                        for (int i=0; i<imageSize; ++i) {
                            greenValue = (pixels[1][i]>>8)&0xff;
                            awtImagePixels[i] = (awtImagePixels[i]&0xffff00ff) | (greenValue<<8);
                        }
                        break;
                    case 2:
                        for (int i=0; i<imageSize; ++i) {
                            blueValue = pixels[2][i]&0xff;
                            awtImagePixels[i] = (awtImagePixels[i]&0xffffff00) | blueValue;
                        }
                        break;
                }
            } else {
                for (int i=0; i<imageSize; ++i) {
                    redValue=0; greenValue=0; blueValue=0;
                    for (int j=0; j<nChannels; ++j) {
                        redValue += (pixels[j][i]>>16)&0xff;
                        greenValue += (pixels[j][i]>>8)&0xff;
                        blueValue += (pixels[j][i])&0xff;
                        if (redValue>255) redValue = 255;
                        if (greenValue>255) greenValue = 255;
                        if (blueValue>255) blueValue = 255;
                    }
                    awtImagePixels[i] = (redValue<<16) | (greenValue<<8) | (blueValue);
                }
            }
            if (imageSource==null) {
                imageColorModel = new DirectColorModel(32, 0xff0000, 0xff00, 0xff);
                imageSource = new MemoryImageSource(width, height, imageColorModel, awtImagePixels, 0, width);
                imageSource.setAnimated(true);
                imageSource.setFullBufferUpdates(true);
                awtImage = Toolkit.getDefaultToolkit().createImage(imageSource);
                newPixels = false;
            } else if (newPixels){
                imageSource.newPixels(awtImagePixels, imageColorModel, 0, width);
                newPixels = false;
            } else
                imageSource.newPixels();
            if (img == null && awtImage!=null)
                img = awtImage;
            singleChannel = false;
        }

        ImageStack getRGBStack(ImagePlus imp) {
            ImageProcessor ip = imp.getProcessor();
            int w = ip.getWidth();
            int h = ip.getHeight();
            int size = w*h;
            byte[] r = new byte[size];
            byte[] g = new byte[size];
            byte[] b = new byte[size];
            ((ColorProcessor)ip).getRGB(r, g, b);
            ImageStack stack = new ImageStack(w, h);
            stack.addSlice("Red", r);
            stack.addSlice("Green", g);
            stack.addSlice("Blue", b);
            stack.setColorModel(ip.getDefaultColorModel());
            return stack;
        }

        public static IndexColorModel createModelFromColor(Color color) {
            byte[] rLut = new byte[256];
            byte[] gLut = new byte[256];
            byte[] bLut = new byte[256];
            int red = color.getRed();
            int green = color.getGreen();
            int blue = color.getBlue();
            double rIncr = ((double)red)/255d;
            double gIncr = ((double)green)/255d;
            double bIncr = ((double)blue)/255d;
            for (int i=0; i<256; ++i) {
                rLut[i] = (byte)(i*rIncr);
                gLut[i] = (byte)(i*gIncr);
                bLut[i] = (byte)(i*bIncr);
            }
            return new IndexColorModel(8, 256, rLut, gLut, bLut);
        }

        public Color getChannelColor() {
            int index = getCurrentSlice()-1;
            if (index<colors.length && colors[index]!=Color.white)
                return colors[index];
            else;
                return Color.black;
        }

        public ImageProcessor getProcessor(int channel) {
            if (cip==null || channel>cip.length)
                return null;
            else
                return cip[channel-1];
        }

        public double getMin(int channel) {
            if (cip==null || channel>cip.length)
                return 0.0;
            else
                return cip[channel-1].getMin();
        }

        public double getMax(int channel) {
            if (cip==null || channel>cip.length)
                return 0.0;
            else
                return cip[channel-1].getMax();
        }

    }

| CompositeImage |