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.math.Noise;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.List;
025    import railo.runtime.type.Struct;
026    
027    /**
028     * A filter which distorts an image as if it were underwater.
029     */
030    public class SwimFilter extends TransformFilter  implements DynFiltering {
031    
032            private float scale = 32;
033            private float stretch = 1.0f;
034            private float angle = 0.0f;
035            private float amount = 1.0f;
036            private float turbulence = 1.0f;
037            private float time = 0.0f;
038            private float m00 = 1.0f;
039            private float m01 = 0.0f;
040            private float m10 = 0.0f;
041            private float m11 = 1.0f;
042    
043            public SwimFilter() {
044            }
045            
046            /**
047             * Set the amount of swim.
048             * @param amount the amount of swim
049         * @min-value 0
050         * @max-value 100+
051         * @see #getAmount
052             */
053            public void setAmount(float amount) {
054                    this.amount = amount;
055            }
056            
057            /**
058             * Get the amount of swim.
059             * @return the amount swim
060         * @see #setAmount
061             */
062            public float getAmount() {
063                    return amount;
064            }
065            
066            /**
067         * Specifies the scale of the distortion.
068         * @param scale the scale of the distortion.
069         * @min-value 1
070         * @max-value 300+
071         * @see #getScale
072         */
073            public void setScale(float scale) {
074                    this.scale = scale;
075            }
076    
077            /**
078         * Returns the scale of the distortion.
079         * @return the scale of the distortion.
080         * @see #setScale
081         */
082            public float getScale() {
083                    return scale;
084            }
085    
086            /**
087         * Specifies the stretch factor of the distortion.
088         * @param stretch the stretch factor of the distortion.
089         * @min-value 1
090         * @max-value 50+
091         * @see #getStretch
092         */
093            public void setStretch(float stretch) {
094                    this.stretch = stretch;
095            }
096    
097            /**
098         * Returns the stretch factor of the distortion.
099         * @return the stretch factor of the distortion.
100         * @see #setStretch
101         */
102            public float getStretch() {
103                    return stretch;
104            }
105    
106            /**
107         * Specifies the angle of the effect.
108         * @param angle the angle of the effect.
109         * @angle
110         * @see #getAngle
111         */
112            public void setAngle(float angle) {
113                    this.angle = angle;
114                    float cos = (float)Math.cos(angle);
115                    float sin = (float)Math.sin(angle);
116                    m00 = cos;
117                    m01 = sin;
118                    m10 = -sin;
119                    m11 = cos;
120            }
121    
122            /**
123         * Returns the angle of the effect.
124         * @return the angle of the effect.
125         * @see #setAngle
126         */
127            public float getAngle() {
128                    return angle;
129            }
130    
131            /**
132         * Specifies the turbulence of the texture.
133         * @param turbulence the turbulence of the texture.
134         * @min-value 0
135         * @max-value 1
136         * @see #getTurbulence
137         */
138            public void setTurbulence(float turbulence) {
139                    this.turbulence = turbulence;
140            }
141    
142            /**
143         * Returns the turbulence of the effect.
144         * @return the turbulence of the effect.
145         * @see #setTurbulence
146         */
147            public float getTurbulence() {
148                    return turbulence;
149            }
150    
151            /**
152         * Specifies the time. Use this to animate the effect.
153         * @param time the time.
154         * @angle
155         * @see #getTime
156         */
157            public void setTime(float time) {
158                    this.time = time;
159            }
160    
161            /**
162         * Returns the time.
163         * @return the time.
164         * @see #setTime
165         */
166            public float getTime() {
167                    return time;
168            }
169    
170            protected void transformInverse(int x, int y, float[] out) {
171                    float nx = m00*x + m01*y;
172                    float ny = m10*x + m11*y;
173                    nx /= scale;
174                    ny /= scale * stretch;
175    
176                    if ( turbulence == 1.0f ) {
177                            out[0] = x + amount * Noise.noise3(nx+0.5f, ny, time);
178                            out[1] = y + amount * Noise.noise3(nx, ny+0.5f, time);
179                    } else {
180                            out[0] = x + amount * Noise.turbulence3(nx+0.5f, ny, turbulence, time);
181                            out[1] = y + amount * Noise.turbulence3(nx, ny+0.5f, turbulence, time);
182                    }
183            }
184    
185            public String toString() {
186                    return "Distort/Swim...";
187            }
188            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src);
189                    Object o;
190                    if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount"));
191                    if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence"));
192                    if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch"));
193                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
194                    if((o=parameters.removeEL(KeyImpl.init("Time")))!=null)setTime(ImageFilterUtil.toFloatValue(o,"Time"));
195                    if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale"));
196                    if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
197                    if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation"));
198    
199                    // check for arguments not supported
200                    if(parameters.size()>0) {
201                            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, Turbulence, Stretch, Angle, Time, Scale, EdgeAction, Interpolation]");
202                    }
203    
204                    return filter(src, dst);
205            }
206    }