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.Noise;
042import lucee.runtime.type.KeyImpl;
043import lucee.runtime.type.Struct;
044import lucee.runtime.type.util.CollectionUtil;
045
046/**
047 * A filter which produces a simulated wood texture. This is a bit of a hack, but might be usefult to some people.
048 */
049public class WoodFilter extends PointFilter  implements DynFiltering {
050
051        private float scale = 200;
052        private float stretch = 10.0f;
053        private float angle = (float)Math.PI/2;
054        private float rings = 0.5f;
055        private float turbulence = 0.0f;
056        private float fibres = 0.5f;
057        private float gain = 0.8f;
058        private float m00 = 1.0f;
059        private float m01 = 0.0f;
060        private float m10 = 0.0f;
061        private float m11 = 1.0f;
062        private Colormap colormap = new LinearColormap( 0xffe5c494, 0xff987b51 );
063
064        /**
065     * Construct a WoodFilter.
066     */
067    public WoodFilter() {
068        }
069
070        /**
071     * Specifies the rings value.
072     * @param rings the rings value.
073     * @min-value 0
074     * @max-value 1
075     * @see #getRings
076     */
077    public void setRings(float rings) {
078                this.rings = rings;
079        }
080
081    /**
082     * Returns the rings value.
083     * @return the rings value.
084     * @see #setRings
085     */
086        public float getRings() {
087                return rings;
088        }
089
090        /**
091     * Specifies the scale of the texture.
092     * @param scale the scale of the texture.
093     * @min-value 1
094     * @max-value 300+
095     * @see #getScale
096     */
097        public void setScale(float scale) {
098                this.scale = scale;
099        }
100
101        /**
102     * Returns the scale of the texture.
103     * @return the scale of the texture.
104     * @see #setScale
105     */
106        public float getScale() {
107                return scale;
108        }
109
110        /**
111     * Specifies the stretch factor of the texture.
112     * @param stretch the stretch factor of the texture.
113     * @min-value 1
114     * @max-value 50+
115     * @see #getStretch
116     */
117        public void setStretch(float stretch) {
118                this.stretch = stretch;
119        }
120
121        /**
122     * Returns the stretch factor of the texture.
123     * @return the stretch factor of the texture.
124     * @see #setStretch
125     */
126        public float getStretch() {
127                return stretch;
128        }
129
130        /**
131     * Specifies the angle of the texture.
132     * @param angle the angle of the texture.
133     * @angle
134     * @see #getAngle
135     */
136        public void setAngle(float angle) {
137                this.angle = angle;
138                float cos = (float)Math.cos(angle);
139                float sin = (float)Math.sin(angle);
140                m00 = cos;
141                m01 = sin;
142                m10 = -sin;
143                m11 = cos;
144        }
145
146        /**
147     * Returns the angle of the texture.
148     * @return the angle of the texture.
149     * @see #setAngle
150     */
151        public float getAngle() {
152                return angle;
153        }
154
155        /**
156     * Specifies the turbulence of the texture.
157     * @param turbulence the turbulence of the texture.
158     * @min-value 0
159     * @max-value 1
160     * @see #getTurbulence
161     */
162        public void setTurbulence(float turbulence) {
163                this.turbulence = turbulence;
164        }
165
166        /**
167     * Returns the turbulence of the texture.
168     * @return the turbulence of the texture.
169     * @see #setTurbulence
170     */
171        public float getTurbulence() {
172                return turbulence;
173        }
174
175        /**
176     * Specifies the amount of fibres in the texture.
177     * @param fibres the amount of fibres in the texture.
178     * @min-value 0
179     * @max-value 1
180     * @see #getFibres
181     */
182        public void setFibres(float fibres) {
183                this.fibres = fibres;
184        }
185
186        /**
187     * Returns the amount of fibres in  the texture.
188     * @return the amount of fibres in the texture.
189     * @see #setFibres
190     */
191        public float getFibres() {
192                return fibres;
193        }
194
195        /**
196     * Specifies the gain of the texture.
197     * @param gain the gain of the texture.
198     * @min-value 0
199     * @max-value 1
200     * @see #getGain
201     */
202        public void setGain(float gain) {
203                this.gain = gain;
204        }
205
206        /**
207     * Returns the gain of the texture.
208     * @return the gain of the texture.
209     * @see #setGain
210     */
211        public float getGain() {
212                return gain;
213        }
214
215    /**
216     * Set the colormap to be used for the filter.
217     * @param colormap the colormap
218     * @see #getColormap
219     */
220        public void setColormap(Colormap colormap) {
221                this.colormap = colormap;
222        }
223        
224    /**
225     * Get the colormap to be used for the filter.
226     * @return the colormap
227     * @see #setColormap
228     */
229        public Colormap getColormap() {
230                return colormap;
231        }
232        
233        public int filterRGB(int x, int y, int rgb) {
234                float nx = m00*x + m01*y;
235                float ny = m10*x + m11*y;
236                nx /= scale;
237                ny /= scale * stretch;
238                float f = Noise.noise2(nx, ny);
239        f += 0.1f*turbulence * Noise.noise2(nx*0.05f, ny*20);
240                f = (f * 0.5f) + 0.5f;
241
242        f *= rings*50;
243        f = f-(int)f;
244        f *= 1-ImageMath.smoothStep(gain, 1.0f, f);
245
246        f += fibres*Noise.noise2(nx*scale, ny*50);
247
248                int a = rgb & 0xff000000;
249                int v;
250                if (colormap != null)
251                        v = colormap.getColor(f);
252                else {
253                        v = PixelUtils.clamp((int)(f*255));
254                        int r = v << 16;
255                        int g = v << 8;
256                        int b = v;
257                        v = a|r|g|b;
258                }
259
260                return v;
261        }
262
263        public String toString() {
264                return "Texture/Wood...";
265        }
266        
267        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
268                Object o;
269                if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
270                if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence"));
271                if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch"));
272                if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
273                if((o=parameters.removeEL(KeyImpl.init("Gain")))!=null)setGain(ImageFilterUtil.toFloatValue(o,"Gain"));
274                if((o=parameters.removeEL(KeyImpl.init("Rings")))!=null)setRings(ImageFilterUtil.toFloatValue(o,"Rings"));
275                if((o=parameters.removeEL(KeyImpl.init("Fibres")))!=null)setFibres(ImageFilterUtil.toFloatValue(o,"Fibres"));
276                if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale"));
277                if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){
278                        int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions");
279                        setDimensions(dim[0],dim[1]);
280                }
281
282                // check for arguments not supported
283                if(parameters.size()>0) {
284                        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, Turbulence, Stretch, Angle, Gain, Rings, Fibres, Scale, Dimensions]");
285                }
286
287                return filter(src, dst);
288        }
289}