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.img.math.Function2D;
024    import railo.runtime.img.math.Noise;
025    import railo.runtime.type.KeyImpl;
026    import railo.runtime.type.List;
027    import railo.runtime.type.Struct;
028    
029    public class TextureFilter extends PointFilter  implements DynFiltering {
030    
031            private float scale = 32;
032            private float stretch = 1.0f;
033            private float angle = 0.0f;
034            public float amount = 1.0f;
035            public float turbulence = 1.0f;
036            public float gain = 0.5f;
037            public float bias = 0.5f;
038            public int operation;
039            private float m00 = 1.0f;
040            private float m01 = 0.0f;
041            private float m10 = 0.0f;
042            private float m11 = 1.0f;
043            private Colormap colormap = new Gradient();
044            private Function2D function = new Noise();
045    
046            public TextureFilter() {
047            }
048    
049            /**
050             * Set the amount of texture.
051             * @param amount the amount
052         * @min-value 0
053         * @max-value 1
054         * @see #getAmount
055             */
056            public void setAmount(float amount) {
057                    this.amount = amount;
058            }
059    
060            /**
061             * Get the amount of texture.
062             * @return the amount
063         * @see #setAmount
064             */
065            public float getAmount() {
066                    return amount;
067            }
068    
069            public void setFunction(Function2D function) {
070                    this.function = function;
071            }
072    
073            public Function2D getFunction() {
074                    return function;
075            }
076    
077            public void setOperation(int operation) {
078                    this.operation = operation;
079            }
080            
081            public int getOperation() {
082                    return operation;
083            }
084            
085            /**
086         * Specifies the scale of the texture.
087         * @param scale the scale of the texture.
088         * @min-value 1
089         * @max-value 300+
090         * @see #getScale
091         */
092            public void setScale(float scale) {
093                    this.scale = scale;
094            }
095    
096            /**
097         * Returns the scale of the texture.
098         * @return the scale of the texture.
099         * @see #setScale
100         */
101            public float getScale() {
102                    return scale;
103            }
104    
105            /**
106         * Specifies the stretch factor of the texture.
107         * @param stretch the stretch factor of the texture.
108         * @min-value 1
109         * @max-value 50+
110         * @see #getStretch
111         */
112            public void setStretch(float stretch) {
113                    this.stretch = stretch;
114            }
115    
116            /**
117         * Returns the stretch factor of the texture.
118         * @return the stretch factor of the texture.
119         * @see #setStretch
120         */
121            public float getStretch() {
122                    return stretch;
123            }
124    
125            /**
126         * Specifies the angle of the texture.
127         * @param angle the angle of the texture.
128         * @angle
129         * @see #getAngle
130         */
131            public void setAngle(float angle) {
132                    this.angle = angle;
133                    float cos = (float)Math.cos(angle);
134                    float sin = (float)Math.sin(angle);
135                    m00 = cos;
136                    m01 = sin;
137                    m10 = -sin;
138                    m11 = cos;
139            }
140    
141            /**
142         * Returns the angle of the texture.
143         * @return the angle of the texture.
144         * @see #setAngle
145         */
146            public float getAngle() {
147                    return angle;
148            }
149    
150            /**
151         * Specifies the turbulence of the texture.
152         * @param turbulence the turbulence of the texture.
153         * @min-value 0
154         * @max-value 1
155         * @see #getTurbulence
156         */
157            public void setTurbulence(float turbulence) {
158                    this.turbulence = turbulence;
159            }
160    
161            /**
162         * Returns the turbulence of the texture.
163         * @return the turbulence of the texture.
164         * @see #setTurbulence
165         */
166            public float getTurbulence() {
167                    return turbulence;
168            }
169    
170        /**
171         * Set the colormap to be used for the filter.
172         * @param colormap the colormap
173         * @see #getColormap
174         */
175            public void setColormap(Colormap colormap) {
176                    this.colormap = colormap;
177            }
178            
179        /**
180         * Get the colormap to be used for the filter.
181         * @return the colormap
182         * @see #setColormap
183         */
184            public Colormap getColormap() {
185                    return colormap;
186            }
187            
188            public int filterRGB(int x, int y, int rgb) {
189                    float nx = m00*x + m01*y;
190                    float ny = m10*x + m11*y;
191                    nx /= scale;
192                    ny /= scale * stretch;
193                    float f = turbulence == 1.0 ? Noise.noise2(nx, ny) : Noise.turbulence2(nx, ny, turbulence);
194                    f = (f * 0.5f) + 0.5f;
195                    f = ImageMath.gain(f, gain);
196                    f = ImageMath.bias(f, bias);
197                    f *= amount;
198                    int a = rgb & 0xff000000;
199                    int v;
200                    if (colormap != null)
201                            v = colormap.getColor(f);
202                    else {
203                            v = PixelUtils.clamp((int)(f*255));
204                            int r = v << 16;
205                            int g = v << 8;
206                            int b = v;
207                            v = a|r|g|b;
208                    }
209                    if (operation != PixelUtils.REPLACE)
210                            v = PixelUtils.combinePixels(rgb, v, operation);
211                    return v;
212            }
213    
214            public String toString() {
215                    return "Texture/Noise...";
216            }
217            
218            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
219                    Object o;
220                    if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
221                    if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount"));
222                    if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence"));
223                    if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch"));
224                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
225                    if((o=parameters.removeEL(KeyImpl.init("Operation")))!=null)setOperation(ImageFilterUtil.toIntValue(o,"Operation"));
226                    if((o=parameters.removeEL(KeyImpl.init("Function")))!=null)setFunction(ImageFilterUtil.toFunction2D(o,"Function"));
227                    if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale"));
228                    if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){
229                            int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions");
230                            setDimensions(dim[0],dim[1]);
231                    }
232    
233                    // check for arguments not supported
234                    if(parameters.size()>0) {
235                            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 [Colormap, Amount, Turbulence, Stretch, Angle, Operation, Function, Scale, Dimensions]");
236                    }
237    
238                    return filter(src, dst);
239            }
240    }