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.Struct;
043import lucee.runtime.type.util.CollectionUtil;
044
045/**
046 * A filter which removes noise from an image using a "pepper and salt" algorithm.
047 */
048public class DespeckleFilter extends WholeImageFilter  implements DynFiltering {
049
050        public DespeckleFilter() {
051        }
052
053        private short pepperAndSalt( short c, short v1, short v2 ) {
054                if ( c < v1 )
055                        c++;
056                if ( c < v2 )
057                        c++;
058                if ( c > v1 )
059                        c--;
060                if ( c > v2 )
061                        c--;
062                return c;
063        }
064        
065        protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
066                int index = 0;
067                short[][] r = new short[3][width];
068                short[][] g = new short[3][width];
069                short[][] b = new short[3][width];
070                int[] outPixels = new int[width * height];
071
072                for (int x = 0; x < width; x++) {
073                        int rgb = inPixels[x];
074                        r[1][x] = (short)((rgb >> 16) & 0xff);
075                        g[1][x] = (short)((rgb >> 8) & 0xff);
076                        b[1][x] = (short)(rgb & 0xff);
077                }
078                for (int y = 0; y < height; y++) {
079                        boolean yIn = y > 0 && y < height-1;
080                        int nextRowIndex = index+width;
081                        if ( y < height-1) {
082                                for (int x = 0; x < width; x++) {
083                                        int rgb = inPixels[nextRowIndex++];
084                                        r[2][x] = (short)((rgb >> 16) & 0xff);
085                                        g[2][x] = (short)((rgb >> 8) & 0xff);
086                                        b[2][x] = (short)(rgb & 0xff);
087                                }
088                        }
089                        for (int x = 0; x < width; x++) {
090                                boolean xIn = x > 0 && x < width-1;
091                                short or = r[1][x];
092                                short og = g[1][x];
093                                short ob = b[1][x];
094                                int w = x-1;
095                                int e = x+1;
096                                
097                                if ( yIn ) {
098                                        or = pepperAndSalt( or, r[0][x], r[2][x] );
099                                        og = pepperAndSalt( og, g[0][x], g[2][x] );
100                                        ob = pepperAndSalt( ob, b[0][x], b[2][x] );
101                                }
102
103                                if ( xIn ) {
104                                        or = pepperAndSalt( or, r[1][w], r[1][e] );
105                                        og = pepperAndSalt( og, g[1][w], g[1][e] );
106                                        ob = pepperAndSalt( ob, b[1][w], b[1][e] );
107                                }
108
109                                if ( yIn && xIn ) {
110                                        or = pepperAndSalt( or, r[0][w], r[2][e] );
111                                        og = pepperAndSalt( og, g[0][w], g[2][e] );
112                                        ob = pepperAndSalt( ob, b[0][w], b[2][e] );
113
114                                        or = pepperAndSalt( or, r[2][w], r[0][e] );
115                                        og = pepperAndSalt( og, g[2][w], g[0][e] );
116                                        ob = pepperAndSalt( ob, b[2][w], b[0][e] );
117                                }
118
119                                outPixels[index] = (inPixels[index] & 0xff000000) | (or << 16) | (og << 8) | ob;
120                                index++;
121                        }
122                        short[] t;
123                        t = r[0];
124                        r[0] = r[1];
125                        r[1] = r[2];
126                        r[2] = t;
127                        t = g[0];
128                        g[0] = g[1];
129                        g[1] = g[2];
130                        g[2] = t;
131                        t = b[0];
132                        b[0] = b[1];
133                        b[1] = b[2];
134                        b[2] = t;
135                }
136        
137                return outPixels;
138        }
139
140        public String toString() {
141                return "Blur/Despeckle...";
142        }
143
144        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
145                //Object o;
146
147                // check for arguments not supported
148                if(parameters.size()>0) {
149                        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 []");
150                }
151
152                return filter(src, dst);
153        }
154}
155