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