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.Rectangle;
018    import java.awt.image.BufferedImage;
019    import java.util.Date;
020    import java.util.Random;
021    
022    import railo.runtime.engine.ThreadLocalPageContext;
023    import railo.runtime.exp.FunctionException;
024    import railo.runtime.exp.PageException;
025    import railo.runtime.img.ImageUtil;
026    import railo.runtime.type.KeyImpl;
027    import railo.runtime.type.Struct;
028    import railo.runtime.type.util.CollectionUtil;
029    
030    public class QuiltFilter extends WholeImageFilter  implements DynFiltering {
031    
032            private Random randomGenerator;
033            private long seed = 567;
034            private int iterations = 25000;
035            private float a = -0.59f;
036            private float b = 0.2f;
037            private float c = 0.1f;
038            private float d = 0;
039            private int k = 0;
040            private Colormap colormap = new LinearColormap();
041    
042            public QuiltFilter() {
043                    randomGenerator = new Random();
044            }
045    
046            public void randomize() {
047                    seed = new Date().getTime();
048                    randomGenerator.setSeed(seed);
049                    a = randomGenerator.nextFloat();
050                    b = randomGenerator.nextFloat();
051                    c = randomGenerator.nextFloat();
052                    d = randomGenerator.nextFloat();
053                    k = randomGenerator.nextInt() % 20 - 10;
054            }
055            
056            /**
057             * Set the number of iterations the effect is performed.
058             * @param iterations the number of iterations
059         * @min-value 0
060         * @see #getIterations
061             */
062            public void setIterations(int iterations) {
063                    this.iterations = iterations;
064            }
065    
066            /**
067             * Get the number of iterations the effect is performed.
068             * @return the number of iterations
069         * @see #setIterations
070             */
071            public int getIterations() {
072                    return iterations;
073            }
074    
075            public void setA(float a) {
076                    this.a = a;
077            }
078    
079            public float getA() {
080                    return a;
081            }
082    
083            public void setB(float b) {
084                    this.b = b;
085            }
086    
087            public float getB() {
088                    return b;
089            }
090    
091            public void setC(float c) {
092                    this.c = c;
093            }
094    
095            public float getC() {
096                    return c;
097            }
098    
099            public void setD(float d) {
100                    this.d = d;
101            }
102    
103            public float getD() {
104                    return d;
105            }
106    
107            public void setK(int k) {
108                    this.k = k;
109            }
110    
111            public int getK() {
112                    return k;
113            }
114    
115        /**
116         * Set the colormap to be used for the filter.
117         * @param colormap the colormap
118         * @see #getColormap
119         */
120            public void setColormap(Colormap colormap) {
121                    this.colormap = colormap;
122            }
123            
124        /**
125         * Get the colormap to be used for the filter.
126         * @return the colormap
127         * @see #setColormap
128         */
129            public Colormap getColormap() {
130                    return colormap;
131            }
132            
133            protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
134                    int[] outPixels = new int[width * height];
135    
136                    //int i = 0;
137                    int max = 0;
138    
139                    float x = 0.1f;
140                    float y = 0.3f;
141                    
142                    for (int n = 0; n < 20; n++) {
143                            float mx = ImageMath.PI*x;
144                            float my = ImageMath.PI*y;
145                            float smx2 = (float)Math.sin(2*mx);
146                            float smy2 = (float)Math.sin(2*my);
147                            float x1 = (float)(a*smx2 + b*smx2*Math.cos(2*my) +
148                                    c*Math.sin(4*mx) + d*Math.sin(6*mx)*Math.cos(4*my) + k*x);
149                            x1 = x1 >= 0 ? x1 - (int)x1 : x1 - (int)x1 + 1;
150    
151                            float y1 = (float)(a*smy2 + b*smy2*Math.cos(2*mx) +
152                                    c*Math.sin(4*my) + d*Math.sin(6*my)*Math.cos(4*mx) + k*y);
153                            y1 = y1 >= 0 ? y1 - (int)y1 : y1 - (int)y1 + 1;
154                            x = x1;
155                            y = y1;
156                    }
157    
158                    for (int n = 0; n < iterations; n++) {
159                            float mx = ImageMath.PI*x;
160                            float my = ImageMath.PI*y;
161                            float x1 = (float)(a*Math.sin(2*mx) + b*Math.sin(2*mx)*Math.cos(2*my) +
162                                    c*Math.sin(4*mx) + d*Math.sin(6*mx)*Math.cos(4*my) + k*x);
163                            x1 = x1 >= 0 ? x1 - (int)x1 : x1 - (int)x1 + 1;
164    
165                            float y1 = (float)(a*Math.sin(2*my) + b*Math.sin(2*my)*Math.cos(2*mx) +
166                                    c*Math.sin(4*my) + d*Math.sin(6*my)*Math.cos(4*mx) + k*y);
167                            y1 = y1 >= 0 ? y1 - (int)y1 : y1 - (int)y1 + 1;
168                            x = x1;
169                            y = y1;
170                            int ix = (int)(width*x);
171                            int iy = (int)(height*y);
172                            if (ix >= 0 && ix < width && iy >= 0 && iy < height) {
173                                    int t = outPixels[width*iy+ix]++;
174                                    if (t > max)
175                                            max = t;
176                            }
177                    }
178    
179                    if (colormap != null) {
180                            int index = 0;
181                            for (y = 0; y < height; y++) {
182                                    for (x = 0; x < width; x++) {
183                                            outPixels[index] = colormap.getColor(outPixels[index] / (float)max);
184                                            index++;
185                                    }
186                            }
187                    }
188                    return outPixels;
189            }
190    
191            public String toString() {
192                    return "Texture/Chaotic Quilt...";
193            }
194            
195            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
196                    Object o;
197                    if((o=parameters.removeEL(KeyImpl.init("Iterations")))!=null)setIterations(ImageFilterUtil.toIntValue(o,"Iterations"));
198                    if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
199                    if((o=parameters.removeEL(KeyImpl.init("A")))!=null)setA(ImageFilterUtil.toFloatValue(o,"A"));
200                    if((o=parameters.removeEL(KeyImpl.init("B")))!=null)setB(ImageFilterUtil.toFloatValue(o,"B"));
201                    if((o=parameters.removeEL(KeyImpl.init("C")))!=null)setC(ImageFilterUtil.toFloatValue(o,"C"));
202                    if((o=parameters.removeEL(KeyImpl.init("D")))!=null)setD(ImageFilterUtil.toFloatValue(o,"D"));
203                    if((o=parameters.removeEL(KeyImpl.init("K")))!=null)setK(ImageFilterUtil.toIntValue(o,"K"));
204    
205                    // check for arguments not supported
206                    if(parameters.size()>0) {
207                            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 [Iterations, Colormap, A, B, C, D, K]");
208                    }
209    
210                    return filter(src, dst);
211            }
212    }