001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.lib.image;
011
012
013/*
014 * This class implements different schemes for accessing pixel values from
015 * a 2D image that is contained in a 1D array.
016 * 
017 */
018public abstract class PixelIndexer {
019        
020        public static PixelIndexer create(int width, int height, OutOfBoundsStrategy mode) {
021                switch (mode) {
022                case DefaultValue       : return new PixelIndexer.DefaultValueIndexer(width, height);
023                case NearestBorder      : return new PixelIndexer.NearestBorderIndexer(width, height);
024                case MirrorImage        : return new PixelIndexer.MirrorImageIndexer(width, height);
025                case Exception          : return new PixelIndexer.ExceptionIndexer(width, height);
026                }
027                return null;
028        }
029        
030        protected final int width;
031        protected final int height;
032
033        private PixelIndexer(int width, int height) {
034                this.width = width;
035                this.height = height;
036        }
037        
038        public abstract int getIndex(int u, int v);
039
040        /* 
041         * This indexer returns out of bounds pixel values that
042         * are taken from the closest border pixel. This is the
043         * most common method.
044         */
045        public static class NearestBorderIndexer extends PixelIndexer {
046                NearestBorderIndexer(int width, int height) {
047                        super(width, height);
048                }
049
050                public int getIndex(int u, int v) {
051                        if (u < 0)
052                                u = 0;
053                        else if (u >= width)
054                                u = width - 1;
055                        if (v < 0)
056                                v = 0;
057                        else if (v >= height)
058                                v = height - 1;
059                        return width * v + u;
060                }
061        }
062        
063        /* 
064         * This index returns out of bound pixels taken from
065         * the mirrored image.
066         */
067        public static class MirrorImageIndexer extends PixelIndexer {
068                MirrorImageIndexer(int width, int height) {
069                        super(width, height);
070                }
071
072                public int getIndex(int u, int v) {
073                        // this is a fast modulo operation for positive divisors only
074                        u = u % width;
075                        if (u < 0) u = u + width; 
076                        v = v % height;
077                        if (v < 0) v = v + height; 
078                        return width * v + u;
079                }
080        }
081        
082        /* 
083         * This indexer returns -1 for out of bounds pixels to
084         * indicate that a (predefined) default value should be used.
085         */
086        public static class DefaultValueIndexer extends PixelIndexer {
087                DefaultValueIndexer(int width, int height) {
088                        super(width, height);
089                }
090
091                public int getIndex(int u, int v) {
092                        if (u < 0 || u >= width || v < 0 || v >= height)
093                                return -1;
094                        else 
095                                return width * v + u;
096                }
097        }
098        
099        /*
100         * This indexer throws an exception if out of bounds pixels
101         * are accessed.
102         */
103        public static class ExceptionIndexer extends PixelIndexer {
104                ExceptionIndexer(int width, int height) {
105                        super(width, height);
106                }
107
108                public int getIndex(int u, int v) {
109                        if (u < 0 || u >= width || v < 0 || v >= height) {
110                                throw new ArrayIndexOutOfBoundsException();
111                        }
112                        else 
113                                return width * v + u;
114                }
115        }
116
117}
118
119