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.image.BufferedImage;
018    
019    import railo.runtime.engine.ThreadLocalPageContext;
020    import railo.runtime.exp.FunctionException;
021    import railo.runtime.exp.PageException;
022    import railo.runtime.img.ImageUtil;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.List;
025    import railo.runtime.type.Struct;
026    
027    /**
028     * A filter which subtracts Gaussian blur from an image, sharpening it.
029     *
030     */
031    public class UnsharpFilter extends GaussianFilter  implements DynFiltering {
032    
033            private float amount = 0.5f;
034            private int threshold = 1;
035            
036            public UnsharpFilter() {
037                    radius = 2;
038            }
039            
040            /**
041         * Set the threshold value.
042         * @param threshold the threshold value
043         * @see #getThreshold
044         */
045            public void setThreshold( int threshold ) {
046                    this.threshold = threshold;
047            }
048            
049            /**
050         * Get the threshold value.
051         * @return the threshold value
052         * @see #setThreshold
053         */
054            public int getThreshold() {
055                    return threshold;
056            }
057            
058            /**
059             * Set the amount of sharpening.
060             * @param amount the amount
061         * @min-value 0
062         * @max-value 1
063         * @see #getAmount
064             */
065            public void setAmount( float amount ) {
066                    this.amount = amount;
067            }
068            
069            /**
070             * Get the amount of sharpening.
071             * @return the amount
072         * @see #setAmount
073             */
074            public float getAmount() {
075                    return amount;
076            }
077            
078        public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
079            int width = src.getWidth();
080            int height = src.getHeight();
081    
082            if ( dst == null )
083                dst = createCompatibleDestImage( src, null );
084    
085            int[] inPixels = new int[width*height];
086            int[] outPixels = new int[width*height];
087            src.getRGB( 0, 0, width, height, inPixels, 0, width );
088    
089                    if ( radius > 0 ) {
090                            convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, alpha && premultiplyAlpha, false, CLAMP_EDGES);
091                            convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, false, alpha && premultiplyAlpha, CLAMP_EDGES);
092                    }
093    
094            src.getRGB( 0, 0, width, height, outPixels, 0, width );
095    
096                    float a = 4*amount;
097    
098                    int index = 0;
099                    for ( int y = 0; y < height; y++ ) {
100                            for ( int x = 0; x < width; x++ ) {
101                                    int rgb1 = outPixels[index];
102                                    int r1 = (rgb1 >> 16) & 0xff;
103                                    int g1 = (rgb1 >> 8) & 0xff;
104                                    int b1 = rgb1 & 0xff;
105    
106                                    int rgb2 = inPixels[index];
107                                    int r2 = (rgb2 >> 16) & 0xff;
108                                    int g2 = (rgb2 >> 8) & 0xff;
109                                    int b2 = rgb2 & 0xff;
110    
111                                    if ( Math.abs( r1 -  r2 ) >= threshold )
112                                            r1 = PixelUtils.clamp( (int)((a+1) * (r1-r2) + r2) );
113                                    if ( Math.abs( g1 -  g2 ) >= threshold )
114                                            g1 = PixelUtils.clamp( (int)((a+1) * (g1-g2) + g2) );
115                                    if ( Math.abs( b1 -  b2 ) >= threshold )
116                                            b1 = PixelUtils.clamp( (int)((a+1) * (b1-b2) + b2) );
117    
118                                    inPixels[index] = (rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1;
119                                    index++;
120                            }
121                    }
122    
123            dst.setRGB( 0, 0, width, height, inPixels, 0, width );
124            return dst;
125        }
126    
127            public String toString() {
128                    return "Blur/Unsharp Mask...";
129            }
130            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
131                    Object o;
132                    if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount"));
133                    if((o=parameters.removeEL(KeyImpl.init("Threshold")))!=null)setThreshold(ImageFilterUtil.toIntValue(o,"Threshold"));
134                    if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius"));
135                    if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
136                    if((o=parameters.removeEL(KeyImpl.init("UseAlpha")))!=null)setUseAlpha(ImageFilterUtil.toBooleanValue(o,"UseAlpha"));
137                    if((o=parameters.removeEL(KeyImpl.init("PremultiplyAlpha")))!=null)setPremultiplyAlpha(ImageFilterUtil.toBooleanValue(o,"PremultiplyAlpha"));
138    
139                    // check for arguments not supported
140                    if(parameters.size()>0) {
141                            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 [Amount, Threshold, Radius, Kernel, EdgeAction, UseAlpha, PremultiplyAlpha]");
142                    }
143    
144                    return filter(src, dst);
145            }
146    }