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