001    /*
002    *
003    
004    Licensed under the Apache License, Version 2.0 (the "License");
005    you may not use this file except in compliance with the License.
006    You may obtain a copy of the License at
007    
008       http://www.apache.org/licenses/LICENSE-2.0
009    
010    Unless required by applicable law or agreed to in writing, software
011    distributed under the License is distributed on an "AS IS" BASIS,
012    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013    See the License for the specific language governing permissions and
014    limitations under the License.
015    */
016    
017    package railo.runtime.img.filter;import java.awt.Rectangle;
018    import java.awt.image.BufferedImage;
019    
020    import railo.runtime.engine.ThreadLocalPageContext;
021    import railo.runtime.exp.FunctionException;
022    import railo.runtime.exp.PageException;
023    import railo.runtime.img.ImageUtil;
024    import railo.runtime.type.List;
025    import railo.runtime.type.Struct;
026    
027    /**
028     * A filter which performs a 3x3 median operation. Useful for removing dust and noise.
029     */
030    public class MedianFilter extends WholeImageFilter  implements DynFiltering {
031    
032            public MedianFilter() {
033            }
034    
035            private int median(int[] array) {
036                    int max, maxIndex;
037                    
038                    for (int i = 0; i < 4; i++) {
039                            max = 0;
040                            maxIndex = 0;
041                            for (int j = 0; j < 9; j++) {
042                                    if (array[j] > max) {
043                                            max = array[j];
044                                            maxIndex = j;
045                                    }
046                            }
047                            array[maxIndex] = 0;
048                    }
049                    max = 0;
050                    for (int i = 0; i < 9; i++) {
051                            if (array[i] > max)
052                                    max = array[i];
053                    }
054                    return max;
055            }
056    
057            private int rgbMedian(int[] r, int[] g, int[] b) {
058                    int sum, index = 0, min = Integer.MAX_VALUE;
059                    
060                    for (int i = 0; i < 9; i++) {
061                            sum = 0;
062                            for (int j = 0; j < 9; j++) {
063                                    sum += Math.abs(r[i]-r[j]);
064                                    sum += Math.abs(g[i]-g[j]);
065                                    sum += Math.abs(b[i]-b[j]);
066                            }
067                            if (sum < min) {
068                                    min = sum;
069                                    index = i;
070                            }
071                    }
072                    return index;
073            }
074    
075            protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
076                    int index = 0;
077                    int[] argb = new int[9];
078                    int[] r = new int[9];
079                    int[] g = new int[9];
080                    int[] b = new int[9];
081                    int[] outPixels = new int[width * height];
082    
083                    for (int y = 0; y < height; y++) {
084                            for (int x = 0; x < width; x++) {
085                                    int k = 0;
086                                    for (int dy = -1; dy <= 1; dy++) {
087                                            int iy = y+dy;
088                                            if (0 <= iy && iy < height) {
089                                                    int ioffset = iy*width;
090                                                    for (int dx = -1; dx <= 1; dx++) {
091                                                            int ix = x+dx;
092                                                            if (0 <= ix && ix < width) {
093                                                                    int rgb = inPixels[ioffset+ix];
094                                                                    argb[k] = rgb;
095                                                                    r[k] = (rgb >> 16) & 0xff;
096                                                                    g[k] = (rgb >> 8) & 0xff;
097                                                                    b[k] = rgb & 0xff;
098                                                                    k++;
099                                                            }
100                                                    }
101                                            }
102                                    }
103                                    while (k < 9) {
104                                            argb[k] = 0xff000000;
105                                            r[k] = g[k] = b[k] = 0;
106                                            k++;
107                                    }
108                                    outPixels[index++] = argb[rgbMedian(r, g, b)];
109                            }
110                    }
111                    return outPixels;
112            }
113    
114            public String toString() {
115                    return "Blur/Median";
116            }
117    
118            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
119                    Object o;
120    
121                    // check for arguments not supported
122                    if(parameters.size()>0) {
123                            throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported []");
124                    }
125    
126                    return filter(src, dst);
127            }
128    }
129