001    /*
002     * BorderSampleGenerator
003     * 
004     * Copyright (c) 2002, 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.filters;
009    
010    import net.sourceforge.jiu.data.IntegerImage;
011    
012    /**
013     * Abstract base class for classes that fill an <code>int</code> array with samples
014     * from a rectangular region of an image's channel by
015     * (1) copying <code>int</code> samples from an {@link net.sourceforge.jiu.data.IntegerImage} object 
016     * and by (2) generating samples that lie outside of the image.
017     * To be used by {@link ConvolutionKernelFilter} and other operations 
018     * that require rectangular parts of an image that may not lie fully
019     * inside of the image.
020     * @author Marco Schmidt
021     * @since 0.10.0
022     */
023    public abstract class BorderSampleGenerator
024    {
025            private int areaWidth;
026            private int areaHeight;
027            private int channelIndex;
028            private IntegerImage image;
029    
030            /**
031             * Initialize width and height of the area to be covered in every call to
032             * {@link #fill}, also provides the image to be used for data copying.
033             * The current channel is set to 0.
034             * @param integerImage the image from which samples will be copied
035             * @param areaWidth number of columns of the area to be covered in {@link #fill}
036             * @param areaHeight number of rows of the area to be covered in {@link #fill}
037             */
038            public BorderSampleGenerator(IntegerImage integerImage, int areaWidth, int areaHeight)
039            {
040                    image = integerImage;
041                    if (image == null)
042                    {
043                            throw new IllegalArgumentException("The image argument must be non-null.");
044                    }
045                    this.areaWidth = areaWidth;
046                    if (areaWidth < 1 || (areaWidth % 2) == 0)
047                    {
048                            throw new IllegalArgumentException("Area width must be a positive odd number.");
049                    }
050                    this.areaHeight = areaHeight;
051                    if (areaHeight < 1 || (areaHeight % 2) == 0)
052                    {
053                            throw new IllegalArgumentException("Area height must be a positive odd number.");
054                    }
055            }
056    
057            /**
058             * Fills the argument array with samples from the current channel of the image
059             * given to the constructor, generating samples that lie outside of the image.
060             * The samples are copied (or generated) from the row y to row y + areaHeight - 1,
061             * and within each row from column x to x + areaWidth - 1.
062             * <p>
063             * The implementation of this method is left to the child classes.
064             * There are different ways to generate new samples, and each child class
065             * is supposed to implement another way.
066             * Obviously, the child classes also must copy samples from the image.
067             * @param x leftmost column to be copied or generated
068             * @param y top row to be copied or generated
069             * @param samples array to which samples will be written; must have at least
070             *  {@link #getAreaWidth} times {@link #getAreaHeight} elements
071             */
072            public abstract void fill(int x, int y, int[] samples);
073    
074            /**
075             * Returns the number of rows from which data is copied or generated 
076             * with every call to {@link #fill}.
077             * @return number or rows of a fill area
078             */
079            public int getAreaHeight()
080            {
081                    return areaHeight;
082            }
083    
084            /**
085             * Returns the number of columns from which data is copied or generated 
086             * with every call to {@link #fill}.
087             * @return number or columns of a fill area
088             */
089            public int getAreaWidth()
090            {
091                    return areaWidth;
092            }
093    
094            /**
095             * Returns the index of the channel of the image from which data is copied.
096             * @see #setChannelIndex
097             * @return number or rows
098             */
099            public int getChannelIndex()
100            {
101                    return channelIndex;
102            }
103    
104            /**
105             * Returns the image from which data is copied.
106             * @return image object
107             */
108            public IntegerImage getImage()
109            {
110                    return image;
111            }
112    
113            /**
114             * Sets the channel from which data is copied in {@link #fill}.
115             * @return channel index
116             * @see #getChannelIndex
117             */
118            public void setChannelIndex(int newChannelIndex)
119            {
120                    if (newChannelIndex < 0 || newChannelIndex >= image.getNumChannels())
121                    {
122                            throw new IllegalArgumentException("Illegal channel index: " + 
123                                    newChannelIndex + " (must be from 0 to " +
124                                    (image.getNumChannels() - 1) + ").");
125                    }
126                    else
127                    {
128                            channelIndex = newChannelIndex;
129                    }
130            }
131    }