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.type.KeyImpl;
024    import railo.runtime.type.Struct;
025    import railo.runtime.type.util.CollectionUtil;
026    
027    
028    
029    public class CurvesFilter extends TransferFilter  implements DynFiltering {
030    
031            private Curve[] curves = new Curve[1];
032            
033        public static class Curve {
034            public float[] x;
035            public float[] y;
036            
037            public Curve() {
038                x = new float[] { 0, 1 };
039                y = new float[] { 0, 1 };
040            }
041            
042            public Curve( Curve curve ) {
043                x = curve.x.clone();
044                y = curve.y.clone();
045            }
046            
047            public int addKnot( float kx, float ky ) {
048                int pos = -1;
049                int numKnots = x.length;
050                float[] nx = new float[numKnots+1];
051                float[] ny = new float[numKnots+1];
052                int j = 0;
053                for ( int i = 0; i < numKnots; i++ ) {
054                    if ( pos == -1 && x[i] > kx ) {
055                        pos = j;
056                        nx[j] = kx;
057                        ny[j] = ky;
058                        j++;
059                    }
060                    nx[j] = x[i];
061                    ny[j] = y[i];
062                    j++;
063                }
064                if ( pos == -1 ) {
065                    pos = j;
066                    nx[j] = kx;
067                    ny[j] = ky;
068                }
069                x = nx;
070                y = ny;
071                return pos;
072            }
073            
074            public void removeKnot( int n ) {
075                int numKnots = x.length;
076                if ( numKnots <= 2 )
077                    return;
078                float[] nx = new float[numKnots-1];
079                float[] ny = new float[numKnots-1];
080                int j = 0;
081                for ( int i = 0; i < numKnots-1; i++ ) {
082                    if ( i == n )
083                        j++;
084                    nx[i] = x[j];
085                    ny[i] = y[j];
086                    j++;
087                }
088                x = nx;
089                y = ny;
090                for ( int i = 0; i < x.length; i++ )
091                    System.out.println( i+": "+x[i]+" "+y[i]);
092            }
093    
094            private void sortKnots() {
095                int numKnots = x.length;
096                for (int i = 1; i < numKnots-1; i++) {
097                    for (int j = 1; j < i; j++) {
098                        if (x[i] < x[j]) {
099                            float t = x[i];
100                            x[i] = x[j];
101                            x[j] = t;
102                            t = y[i];
103                            y[i] = y[j];
104                            y[j] = t;
105                        }
106                    }
107                }
108            }
109    
110            protected int[] makeTable() {
111                int numKnots = x.length;
112                float[] nx = new float[numKnots+2];
113                float[] ny = new float[numKnots+2];
114                System.arraycopy( x, 0, nx, 1, numKnots);
115                System.arraycopy( y, 0, ny, 1, numKnots);
116                nx[0] = nx[1];
117                ny[0] = ny[1];
118                nx[numKnots+1] = nx[numKnots];
119                ny[numKnots+1] = ny[numKnots];
120    
121                int[] table = new int[256];
122                for (int i = 0; i < 1024; i++) {
123                    float f = i/1024.0f;
124                    int x = (int)(255 * ImageMath.spline( f, nx.length, nx ) + 0.5f);
125                    int y = (int)(255 * ImageMath.spline( f, nx.length, ny ) + 0.5f);
126                    x = ImageMath.clamp( x, 0, 255 );
127                    y = ImageMath.clamp( y, 0, 255 );
128                    table[x] = y;
129                }
130    //          System.out.println();
131    //          for ( int i = 0; i < 256; i++ )
132    //              System.out.println( i+": "+table[i]);
133                return table;
134            }
135        }
136        
137        public CurvesFilter() {
138            curves = new Curve[3];
139            curves[0] = new Curve();
140            curves[1] = new Curve();
141            curves[2] = new Curve();
142        }
143        
144            protected void initialize() {
145                    initialized = true;
146                    if ( curves.length == 1 )
147                rTable = gTable = bTable = curves[0].makeTable();
148            else {
149                rTable = curves[0].makeTable();
150                gTable = curves[1].makeTable();
151                bTable = curves[2].makeTable();
152            }
153            }
154    
155            public void setCurve( Curve curve ) {
156            curves = new Curve[] { curve };
157                    initialized = false;
158            }
159            
160            public void setCurves( Curve[] curves ) {
161                    if ( curves == null || (curves.length != 1 && curves.length != 3) )
162                throw new IllegalArgumentException( "Curves must be length 1 or 3" );
163            this.curves = curves;
164                    initialized = false;
165            }
166            
167            public Curve[] getCurves() {
168                    return curves;
169            }
170    
171            public String toString() {
172                    return "Colors/Curves...";
173            }
174    
175            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
176                    Object o;
177                    if((o=parameters.removeEL(KeyImpl.init("Curves")))!=null)setCurves(ImageFilterUtil.toACurvesFilter$Curve(o,"Curves"));
178                    if((o=parameters.removeEL(KeyImpl.init("Curve")))!=null)setCurve(ImageFilterUtil.toCurvesFilter$Curve(o,"Curve"));
179                    if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){
180                            int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions");
181                            setDimensions(dim[0],dim[1]);
182                    }
183    
184                    // check for arguments not supported
185                    if(parameters.size()>0) {
186                            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 [Curves, Curve, Dimensions]");
187                    }
188    
189                    return filter(src, dst);
190            }
191    }
192