001    /*
002     * Invert
003     * 
004     * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.color;
009    
010    import net.sourceforge.jiu.data.PixelImage;
011    import net.sourceforge.jiu.data.Palette;
012    import net.sourceforge.jiu.data.Paletted8Image;
013    import net.sourceforge.jiu.data.IntegerImage;
014    import net.sourceforge.jiu.ops.ImageToImageOperation;
015    import net.sourceforge.jiu.ops.MissingParameterException;
016    import net.sourceforge.jiu.ops.WrongParameterException;
017    
018    /**
019     * Creates an inverted (negated) version of an image.
020     * This is done by subtracting each sample value of a channel 
021     * from the maximum sample for that channel.
022     * The maximum sample for a channel is given by 
023     * {@link net.sourceforge.jiu.data.IntegerImage#getMaxSample}. 
024     * For paletted images, just the palette is treated that way.
025     * Supported image types: {@link net.sourceforge.jiu.data.IntegerImage}.
026     * Input and output image can be the same object.
027     * @author Marco Schmidt
028     */
029    public class Invert extends ImageToImageOperation
030    {
031            private void prepare(PixelImage in) throws
032                    MissingParameterException,
033                    WrongParameterException
034            {
035                    if (in == null)
036                    {
037                            throw new MissingParameterException("Missing input image.");
038                    }
039                    PixelImage out = getOutputImage();
040                    if (out == null)
041                    {
042                            setOutputImage(in.createCompatibleImage(in.getWidth(), in.getHeight()));
043                    }
044                    else
045                    {
046                            if (in.getClass() != out.getClass())
047                            {
048                                    throw new WrongParameterException("Specified output image type must be the same as input image type.");
049                            }
050                            if (in.getWidth() != out.getWidth())
051                            {
052                                    throw new WrongParameterException("Specified output image must have same width as input image.");
053                            }
054                            if (in.getHeight() != out.getHeight())
055                            {
056                                    throw new WrongParameterException("Specified output image must have same height as input image.");
057                            }
058                    }
059            }
060    
061            private void process(Paletted8Image in)
062            {
063                    // prepare(PixelImage) has made sure that we have a compatible output image
064                    Paletted8Image out = (Paletted8Image)getOutputImage();
065    
066                    // invert palette of output image
067                    Palette pal = out.getPalette();
068                    final int MAX = pal.getMaxValue();
069                    for (int entryIndex = 0; entryIndex < pal.getNumEntries(); entryIndex++)
070                    {
071                            for (int channelIndex = 0; channelIndex < 3; channelIndex++)
072                            {
073                                    pal.putSample(channelIndex, entryIndex, MAX - pal.getSample(channelIndex, entryIndex));
074                            }
075                    }
076    
077                    // copy image content
078                    final int WIDTH = in.getWidth();
079                    final int HEIGHT = in.getHeight();
080                    for (int y = 0; y < HEIGHT; y++)
081                    {
082                            for (int x = 0; x < WIDTH; x++)
083                            {
084                                    out.putSample(0, x, y, in.getSample(0, x, y));
085                            }
086                            setProgress(y, HEIGHT);
087                    }
088            }
089    
090            private void process(IntegerImage in)
091            {
092                    IntegerImage out = (IntegerImage)getOutputImage();
093                    final int WIDTH = in.getWidth();
094                    final int HEIGHT = in.getHeight();
095                    final int CHANNELS = in.getNumChannels();
096                    final int TOTAL_ITEMS = CHANNELS * HEIGHT;
097                    int processedItems = 0;
098                    for (int channel = 0; channel < CHANNELS; channel++)
099                    {
100                            final int MAX = in.getMaxSample(channel);
101                            for (int y = 0; y < HEIGHT; y++)
102                            {
103                                    for (int x = 0; x < WIDTH; x++)
104                                    {
105                                            out.putSample(channel, x, y, MAX - in.getSample(channel, x, y));
106                                    }
107                                    setProgress(processedItems++, TOTAL_ITEMS);
108                            }
109                    }
110            }
111    
112            /**
113             * Inverts the input image, reusing an output image if one has been specified.
114             * For paletted images, inverts the palette.
115             * For all other types, subtracts each sample of each channel from the maximum
116             * value of that channel.
117             * @throws MissingParameterException if the input image is missing
118             * @throws WrongParameterException if any of the specified image parameters are unsupported or of the wrong width or height
119             */
120            public void process() throws
121                    MissingParameterException,
122                    WrongParameterException
123            {
124                    PixelImage in = getInputImage();
125                    prepare(in);
126                    if (in instanceof Paletted8Image)
127                    {
128                            process((Paletted8Image)in);
129                    }
130                    else
131                    if (in instanceof IntegerImage)
132                    {
133                            process((IntegerImage)in);
134                    }
135                    else
136                    {
137                            throw new WrongParameterException("Input image type unsupported: " + in.toString());
138                    }
139            }
140    }