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.KeyImpl;
025    import railo.runtime.type.Struct;
026    import railo.runtime.type.util.CollectionUtil;
027    
028    /**
029     * A filter which reduces a binary image to a skeleton.
030     *
031     * Based on an algorithm by Zhang and Suen (CACM, March 1984, 236-239).
032     */
033    public class SkeletonFilter extends BinaryFilter  implements DynFiltering {
034    
035            private final static byte[] skeletonTable = {
036                    0, 0, 0, 1, 0, 0, 1, 3, 0, 0, 3, 1, 1, 0, 1, 3, 
037                    0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 3, 0, 3, 3,
038                    0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 
039                    2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 2, 2,
040                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
041                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
042                    2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 
043                    3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 2, 0,
044                    0, 1, 3, 1, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 
045                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
046                    3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
047                    2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
048                    2, 3, 1, 3, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 
049                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
050                    2, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 
051                    3, 3, 0, 1, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 0
052            };
053            
054            public SkeletonFilter() {
055                    newColor = 0xffffffff;
056            }
057    
058            protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
059                    int[] outPixels = new int[width * height];
060    
061                    int count = 0;
062                    int black = 0xff000000;
063                    //int white = 0xffffffff;
064                    for (int i = 0; i < iterations; i++) {
065                            count = 0;
066                            for (int pass = 0; pass < 2; pass++) {
067                                    for (int y = 1; y < height-1; y++) {
068                                            int offset = y*width+1;
069                                            for (int x = 1; x < width-1; x++) {
070                                                    int pixel = inPixels[offset];
071                                                    if (pixel == black) {
072                                                            int tableIndex = 0;
073    
074                                                            if (inPixels[offset-width-1] == black)
075                                                                    tableIndex |= 1;
076                                                            if (inPixels[offset-width] == black)
077                                                                    tableIndex |= 2;
078                                                            if (inPixels[offset-width+1] == black)
079                                                                    tableIndex |= 4;
080                                                            if (inPixels[offset+1] == black)
081                                                                    tableIndex |= 8;
082                                                            if (inPixels[offset+width+1] == black)
083                                                                    tableIndex |= 16;
084                                                            if (inPixels[offset+width] == black)
085                                                                    tableIndex |= 32;
086                                                            if (inPixels[offset+width-1] == black)
087                                                                    tableIndex |= 64;
088                                                            if (inPixels[offset-1] == black)
089                                                                    tableIndex |= 128;
090                                                            int code = skeletonTable[tableIndex];
091                                                            if (pass == 1) {
092                                                                    if (code == 2 || code == 3) {
093                                                                            if (colormap != null)
094                                                                                    pixel = colormap.getColor((float)i/iterations);
095                                                                            else
096                                                                                    pixel = newColor;
097                                                                            count++;
098                                                                    }
099                                                            } else {
100                                                                    if (code == 1 || code == 3) {
101                                                                            if (colormap != null)
102                                                                                    pixel = colormap.getColor((float)i/iterations);
103                                                                            else
104                                                                                    pixel = newColor;
105                                                                            count++;
106                                                                    }
107                                                            }
108                                                    }
109                                                    outPixels[offset++] = pixel;
110                                            }
111                                    }
112                                    if (pass == 0) {
113                                            inPixels = outPixels;
114                                            outPixels = new int[width * height];
115                                    }
116                            }
117                            if (count == 0)
118                                    break;
119                    }
120                    return outPixels;
121            }
122    
123            public String toString() {
124                    return "Binary/Skeletonize...";
125            }
126    
127            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
128                    Object o;
129                    if((o=parameters.removeEL(KeyImpl.init("Iterations")))!=null)setIterations(ImageFilterUtil.toIntValue(o,"Iterations"));
130                    if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
131                    if((o=parameters.removeEL(KeyImpl.init("NewColor")))!=null)setNewColor(ImageFilterUtil.toColorRGB(o,"NewColor"));
132                    //if((o=parameters.removeEL(KeyImpl.init("BlackFunction")))!=null)setBlackFunction(ImageFilterUtil.toBinaryFunction(o,"BlackFunction"));
133    
134                    // check for arguments not supported
135                    if(parameters.size()>0) {
136                            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 [Iterations, Colormap, NewColor, BlackFunction]");
137                    }
138    
139                    return filter(src, dst);
140            }
141    }
142