001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019/*
020*
021
022Licensed under the Apache License, Version 2.0 (the "License");
023you may not use this file except in compliance with the License.
024You may obtain a copy of the License at
025
026   http://www.apache.org/licenses/LICENSE-2.0
027
028Unless required by applicable law or agreed to in writing, software
029distributed under the License is distributed on an "AS IS" BASIS,
030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
031See the License for the specific language governing permissions and
032limitations under the License.
033*/
034
035package lucee.runtime.img.filter;import java.awt.image.BufferedImage;
036
037import lucee.runtime.engine.ThreadLocalPageContext;
038import lucee.runtime.exp.FunctionException;
039import lucee.runtime.exp.PageException;
040import lucee.runtime.img.math.Noise;
041import lucee.runtime.type.KeyImpl;
042import lucee.runtime.type.Struct;
043import lucee.runtime.type.util.CollectionUtil;
044
045/**
046 * A filter which distorts an image as if it were underwater.
047 */
048public class SwimFilter extends TransformFilter  implements DynFiltering {
049
050        private float scale = 32;
051        private float stretch = 1.0f;
052        private float angle = 0.0f;
053        private float amount = 1.0f;
054        private float turbulence = 1.0f;
055        private float time = 0.0f;
056        private float m00 = 1.0f;
057        private float m01 = 0.0f;
058        private float m10 = 0.0f;
059        private float m11 = 1.0f;
060
061        public SwimFilter() {
062        }
063        
064        /**
065         * Set the amount of swim.
066         * @param amount the amount of swim
067     * @min-value 0
068     * @max-value 100+
069     * @see #getAmount
070         */
071        public void setAmount(float amount) {
072                this.amount = amount;
073        }
074        
075        /**
076         * Get the amount of swim.
077         * @return the amount swim
078     * @see #setAmount
079         */
080        public float getAmount() {
081                return amount;
082        }
083        
084        /**
085     * Specifies the scale of the distortion.
086     * @param scale the scale of the distortion.
087     * @min-value 1
088     * @max-value 300+
089     * @see #getScale
090     */
091        public void setScale(float scale) {
092                this.scale = scale;
093        }
094
095        /**
096     * Returns the scale of the distortion.
097     * @return the scale of the distortion.
098     * @see #setScale
099     */
100        public float getScale() {
101                return scale;
102        }
103
104        /**
105     * Specifies the stretch factor of the distortion.
106     * @param stretch the stretch factor of the distortion.
107     * @min-value 1
108     * @max-value 50+
109     * @see #getStretch
110     */
111        public void setStretch(float stretch) {
112                this.stretch = stretch;
113        }
114
115        /**
116     * Returns the stretch factor of the distortion.
117     * @return the stretch factor of the distortion.
118     * @see #setStretch
119     */
120        public float getStretch() {
121                return stretch;
122        }
123
124        /**
125     * Specifies the angle of the effect.
126     * @param angle the angle of the effect.
127     * @angle
128     * @see #getAngle
129     */
130        public void setAngle(float angle) {
131                this.angle = angle;
132                float cos = (float)Math.cos(angle);
133                float sin = (float)Math.sin(angle);
134                m00 = cos;
135                m01 = sin;
136                m10 = -sin;
137                m11 = cos;
138        }
139
140        /**
141     * Returns the angle of the effect.
142     * @return the angle of the effect.
143     * @see #setAngle
144     */
145        public float getAngle() {
146                return angle;
147        }
148
149        /**
150     * Specifies the turbulence of the texture.
151     * @param turbulence the turbulence of the texture.
152     * @min-value 0
153     * @max-value 1
154     * @see #getTurbulence
155     */
156        public void setTurbulence(float turbulence) {
157                this.turbulence = turbulence;
158        }
159
160        /**
161     * Returns the turbulence of the effect.
162     * @return the turbulence of the effect.
163     * @see #setTurbulence
164     */
165        public float getTurbulence() {
166                return turbulence;
167        }
168
169        /**
170     * Specifies the time. Use this to animate the effect.
171     * @param time the time.
172     * @angle
173     * @see #getTime
174     */
175        public void setTime(float time) {
176                this.time = time;
177        }
178
179        /**
180     * Returns the time.
181     * @return the time.
182     * @see #setTime
183     */
184        public float getTime() {
185                return time;
186        }
187
188        protected void transformInverse(int x, int y, float[] out) {
189                float nx = m00*x + m01*y;
190                float ny = m10*x + m11*y;
191                nx /= scale;
192                ny /= scale * stretch;
193
194                if ( turbulence == 1.0f ) {
195                        out[0] = x + amount * Noise.noise3(nx+0.5f, ny, time);
196                        out[1] = y + amount * Noise.noise3(nx, ny+0.5f, time);
197                } else {
198                        out[0] = x + amount * Noise.turbulence3(nx+0.5f, ny, turbulence, time);
199                        out[1] = y + amount * Noise.turbulence3(nx, ny+0.5f, turbulence, time);
200                }
201        }
202
203        public String toString() {
204                return "Distort/Swim...";
205        }
206        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src);
207                Object o;
208                if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount"));
209                if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence"));
210                if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch"));
211                if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
212                if((o=parameters.removeEL(KeyImpl.init("Time")))!=null)setTime(ImageFilterUtil.toFloatValue(o,"Time"));
213                if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale"));
214                if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
215                if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation"));
216
217                // check for arguments not supported
218                if(parameters.size()>0) {
219                        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, Turbulence, Stretch, Angle, Time, Scale, EdgeAction, Interpolation]");
220                }
221
222                return filter(src, dst);
223        }
224}