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    import java.util.Random;
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 adds random noise into an image.
030     */
031    public class NoiseFilter extends PointFilter  implements DynFiltering {
032            
033        /**
034         * Gaussian distribution for the noise.
035         */
036            public final static int GAUSSIAN = 0;
037    
038        /**
039         * Uniform distribution for the noise.
040         */
041            public final static int UNIFORM = 1;
042            
043            private int amount = 25;
044            private int distribution = UNIFORM;
045            private boolean monochrome = false;
046            private float density = 1;
047            private Random randomNumbers = new Random();
048            
049            public NoiseFilter() {
050            }
051    
052            /**
053             * Set the amount of effect.
054             * @param amount the amount
055         * @min-value 0
056         * @max-value 1
057         * @see #getAmount
058             */
059            public void setAmount(int amount) {
060                    this.amount = amount;
061            }
062            
063            /**
064             * Get the amount of noise.
065             * @return the amount
066         * @see #setAmount
067             */
068            public int getAmount() {
069                    return amount;
070            }
071            
072            /**
073             * Set the distribution of the noise.
074             * @param distribution the distribution
075         * @see #getDistribution
076             */
077            public void setDistribution( int distribution ) {
078                    this.distribution = distribution;
079            }
080            
081            /**
082             * Get the distribution of the noise.
083             * @return the distribution
084         * @see #setDistribution
085             */
086            public int getDistribution() {
087                    return distribution;
088            }
089            
090            /**
091             * Set whether to use monochrome noise.
092             * @param monochrome true for monochrome noise
093         * @see #getMonochrome
094             */
095            public void setMonochrome(boolean monochrome) {
096                    this.monochrome = monochrome;
097            }
098            
099            /**
100             * Get whether to use monochrome noise.
101             * @return true for monochrome noise
102         * @see #setMonochrome
103             */
104            public boolean getMonochrome() {
105                    return monochrome;
106            }
107            
108            /**
109             * Set the density of the noise.
110             * @param density the density
111         * @see #getDensity
112             */
113            public void setDensity( float density ) {
114                    this.density = density;
115            }
116            
117            /**
118             * Get the density of the noise.
119             * @return the density
120         * @see #setDensity
121             */
122            public float getDensity() {
123                    return density;
124            }
125            
126            private int random(int x) {
127                    x += (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount);
128                    if (x < 0)
129                            x = 0;
130                    else if (x > 0xff)
131                            x = 0xff;
132                    return x;
133            }
134            
135            public int filterRGB(int x, int y, int rgb) {
136                    if ( randomNumbers.nextFloat() <= density ) {
137                            int a = rgb & 0xff000000;
138                            int r = (rgb >> 16) & 0xff;
139                            int g = (rgb >> 8) & 0xff;
140                            int b = rgb & 0xff;
141                            if (monochrome) {
142                                    int n = (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount);
143                                    r = PixelUtils.clamp(r+n);
144                                    g = PixelUtils.clamp(g+n);
145                                    b = PixelUtils.clamp(b+n);
146                            } else {
147                                    r = random(r);
148                                    g = random(g);
149                                    b = random(b);
150                            }
151                            return a | (r << 16) | (g << 8) | b;
152                    }
153                    return rgb;
154            }
155    
156            public String toString() {
157                    return "Stylize/Add Noise...";
158            }
159            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
160                    Object o;
161                    if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toIntValue(o,"Amount"));
162                    if((o=parameters.removeEL(KeyImpl.init("Monochrome")))!=null)setMonochrome(ImageFilterUtil.toBooleanValue(o,"Monochrome"));
163                    if((o=parameters.removeEL(KeyImpl.init("Density")))!=null)setDensity(ImageFilterUtil.toFloatValue(o,"Density"));
164                    if((o=parameters.removeEL(KeyImpl.init("Distribution")))!=null)setDistribution(ImageFilterUtil.toIntValue(o,"Distribution"));
165                    if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){
166                            int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions");
167                            setDimensions(dim[0],dim[1]);
168                    }
169    
170                    // check for arguments not supported
171                    if(parameters.size()>0) {
172                            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 [Amount, Monochrome, Density, Distribution, Dimensions]");
173                    }
174    
175                    return filter(src, dst);
176            }
177    }