001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019/*
020*
021
022Licensed under the Apache License, Version 2.0 (the "License");
023you may not use this file except in compliance with the License.
024You may obtain a copy of the License at
025
026   http://www.apache.org/licenses/LICENSE-2.0
027
028Unless required by applicable law or agreed to in writing, software
029distributed under the License is distributed on an "AS IS" BASIS,
030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
031See the License for the specific language governing permissions and
032limitations under the License.
033*/
034
035package lucee.runtime.img.filter;import java.awt.Rectangle;
036import java.awt.image.BufferedImage;
037
038import lucee.runtime.engine.ThreadLocalPageContext;
039import lucee.runtime.exp.FunctionException;
040import lucee.runtime.exp.PageException;
041import lucee.runtime.img.ImageUtil;
042import lucee.runtime.type.KeyImpl;
043import lucee.runtime.type.Struct;
044import lucee.runtime.type.util.CollectionUtil;
045
046/**
047 * An edge-detection filter.
048 */
049public class EdgeFilter extends WholeImageFilter  implements DynFiltering {
050        
051        public final static float R2 = (float)Math.sqrt(2);
052
053        public final static float[] ROBERTS_V = {
054                0,  0, -1,
055                0,  1,  0,
056                0,  0,  0,
057        };
058        public final static float[] ROBERTS_H = {
059                -1,  0,  0,
060                0,  1,  0,
061                0,  0,  0,
062        };
063        public final static float[] PREWITT_V = {
064                -1,  0,  1,
065                -1,  0,  1,
066                -1,  0,  1,
067        };
068        public final static float[] PREWITT_H = {
069                -1, -1, -1,
070                0,  0,  0,
071                1,  1,  1,
072        };
073        public final static float[] SOBEL_V = {
074                -1,  0,  1,
075                -2,  0,  2,
076                -1,  0,  1,
077        };
078        public static float[] SOBEL_H = {
079                -1, -2, -1,
080                0,  0,  0,
081                1,  2,  1,
082        };
083        public final static float[] FREI_CHEN_V = {
084                -1,  0,  1,
085                -R2,  0,  R2,
086                -1,  0,  1,
087        };
088        public static float[] FREI_CHEN_H = {
089                -1, -R2, -1,
090                0,  0,  0,
091                1,  R2,  1,
092        };
093
094        protected float[] vEdgeMatrix = SOBEL_V;
095        protected float[] hEdgeMatrix = SOBEL_H;
096
097        public EdgeFilter() {
098        }
099
100        public void setVEdgeMatrix(float[] vEdgeMatrix) {
101                this.vEdgeMatrix = vEdgeMatrix;
102        }
103
104        public float[] getVEdgeMatrix() {
105                return vEdgeMatrix;
106        }
107
108        public void setHEdgeMatrix(float[] hEdgeMatrix) {
109                this.hEdgeMatrix = hEdgeMatrix;
110        }
111
112        public float[] getHEdgeMatrix() {
113                return hEdgeMatrix;
114        }
115
116        protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
117                int index = 0;
118                int[] outPixels = new int[width * height];
119
120                for (int y = 0; y < height; y++) {
121                        for (int x = 0; x < width; x++) {
122                                int r = 0, g = 0, b = 0;
123                                int rh = 0, gh = 0, bh = 0;
124                                int rv = 0, gv = 0, bv = 0;
125                                int a = inPixels[y*width+x] & 0xff000000;
126
127                                for (int row = -1; row <= 1; row++) {
128                                        int iy = y+row;
129                                        int ioffset;
130                                        if (0 <= iy && iy < height)
131                                                ioffset = iy*width;
132                                        else
133                                                ioffset = y*width;
134                                        int moffset = 3*(row+1)+1;
135                                        for (int col = -1; col <= 1; col++) {
136                                                int ix = x+col;
137                                                if (!(0 <= ix && ix < width))
138                                                        ix = x;
139                                                int rgb = inPixels[ioffset+ix];
140                                                float h = hEdgeMatrix[moffset+col];
141                                                float v = vEdgeMatrix[moffset+col];
142
143                                                r = (rgb & 0xff0000) >> 16;
144                                                g = (rgb & 0x00ff00) >> 8;
145                                                b = rgb & 0x0000ff;
146                                                rh += (int)(h * r);
147                                                gh += (int)(h * g);
148                                                bh += (int)(h * b);
149                                                rv += (int)(v * r);
150                                                gv += (int)(v * g);
151                                                bv += (int)(v * b);
152                                        }
153                                }
154                                r = (int)(Math.sqrt(rh*rh + rv*rv) / 1.8);
155                                g = (int)(Math.sqrt(gh*gh + gv*gv) / 1.8);
156                                b = (int)(Math.sqrt(bh*bh + bv*bv) / 1.8);
157                                r = PixelUtils.clamp(r);
158                                g = PixelUtils.clamp(g);
159                                b = PixelUtils.clamp(b);
160                                outPixels[index++] = a | (r << 16) | (g << 8) | b;
161                        }
162
163                }
164                return outPixels;
165        }
166
167        public String toString() {
168                return "Blur/Detect Edges";
169        }
170        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
171                Object o;
172                if((o=parameters.removeEL(KeyImpl.init("VEdgeMatrix")))!=null)setVEdgeMatrix(ImageFilterUtil.toAFloat(o,"VEdgeMatrix"));
173                if((o=parameters.removeEL(KeyImpl.init("HEdgeMatrix")))!=null)setHEdgeMatrix(ImageFilterUtil.toAFloat(o,"HEdgeMatrix"));
174
175                // check for arguments not supported
176                if(parameters.size()>0) {
177                        throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+CollectionUtil.getKeyList(parameters,", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [VEdgeMatrix, HEdgeMatrix]");
178                }
179
180                return filter(src, dst);
181        }
182}