001/*
002Copyright 2006 Jerry Huxtable
003
004Licensed under the Apache License, Version 2.0 (the "License");
005you may not use this file except in compliance with the License.
006You may obtain a copy of the License at
007
008   http://www.apache.org/licenses/LICENSE-2.0
009
010Unless required by applicable law or agreed to in writing, software
011distributed under the License is distributed on an "AS IS" BASIS,
012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013See the License for the specific language governing permissions and
014limitations under the License.
015*/
016
017package com.jhlabs.math;
018
019import java.awt.*;
020import java.awt.image.*;
021import com.jhlabs.image.*;
022
023public class ImageFunction2D implements Function2D {
024
025        public final static int ZERO = 0;
026        public final static int CLAMP = 1;
027        public final static int WRAP = 2;
028        
029        protected int[] pixels;
030        protected int width;
031        protected int height;
032        protected int edgeAction = ZERO;
033        protected boolean alpha = false;
034        
035        public ImageFunction2D(BufferedImage image) {
036                this(image, false);
037        }
038        
039        public ImageFunction2D(BufferedImage image, boolean alpha) {
040                this(image, ZERO, alpha);
041        }
042        
043        public ImageFunction2D(BufferedImage image, int edgeAction, boolean alpha) {
044                init( getRGB( image, 0, 0, image.getWidth(), image.getHeight(), null), image.getWidth(), image.getHeight(), edgeAction, alpha);
045        }
046        
047        public ImageFunction2D(int[] pixels, int width, int height, int edgeAction, boolean alpha) {
048                init(pixels, width, height, edgeAction, alpha);
049        }
050        
051        public ImageFunction2D(Image image) {
052                this( image, ZERO, false );
053        }
054        
055        public ImageFunction2D(Image image, int edgeAction, boolean alpha) {
056                PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, null, 0, -1);
057                try {
058                        pg.grabPixels();
059                } catch (InterruptedException e) {
060                        throw new RuntimeException("interrupted waiting for pixels!");
061                }
062                if ((pg.status() & ImageObserver.ABORT) != 0) {
063                        throw new RuntimeException("image fetch aborted");
064                }
065                init((int[])pg.getPixels(), pg.getWidth(), pg.getHeight(), edgeAction, alpha);
066        }
067
068        /**
069         * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
070         * penalty of BufferedImage.getRGB unmanaging the image.
071         */
072        public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
073                int type = image.getType();
074                if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
075                        return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
076                return image.getRGB( x, y, width, height, pixels, 0, width );
077    }
078
079        public void init(int[] pixels, int width, int height, int edgeAction, boolean alpha) {
080                this.pixels = pixels;
081                this.width = width;
082                this.height = height;
083                this.edgeAction = edgeAction;
084                this.alpha = alpha;
085        }
086        
087        public float evaluate(float x, float y) {
088                int ix = (int)x;
089                int iy = (int)y;
090                if (edgeAction == WRAP) {
091                        ix = ImageMath.mod(ix, width);
092                        iy = ImageMath.mod(iy, height);
093                } else if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
094                        if (edgeAction == ZERO)
095                                return 0;
096                        if (ix < 0)
097                                ix = 0;
098                        else if (ix >= width)
099                                ix = width-1;
100                        if (iy < 0)
101                                iy = 0;
102                        else if (iy >= height)
103                                iy = height-1;
104                }
105                return alpha ? ((pixels[iy*width+ix] >> 24) & 0xff) / 255.0f : PixelUtils.brightness(pixels[iy*width+ix]) / 255.0f;
106        }
107        
108        public void setEdgeAction(int edgeAction) {
109                this.edgeAction = edgeAction;
110        }
111
112        public int getEdgeAction() {
113                return edgeAction;
114        }
115
116        public int getWidth() {
117                return width;
118        }
119        
120        public int getHeight() {
121                return height;
122        }
123        
124        public int[] getPixels() {
125                return pixels;
126        }
127}
128