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.Point;
018    import java.awt.Rectangle;
019    import java.awt.image.BufferedImage;
020    
021    import railo.runtime.engine.ThreadLocalPageContext;
022    import railo.runtime.exp.FunctionException;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.type.KeyImpl;
025    import railo.runtime.type.Struct;
026    import railo.runtime.type.util.CollectionUtil;
027    
028    /**
029     * A filter which rotates an image. These days this is easier done with Java2D, but this filter remains.
030     */
031    public class RotateFilter extends TransformFilter  implements DynFiltering {
032            
033            private float angle;
034            private float cos, sin;
035            private boolean resize = true;
036    
037            /**
038         * Construct a RotateFilter.
039         */
040        public RotateFilter() {
041                    this(ImageMath.PI);
042            }
043    
044            /**
045         * Construct a RotateFilter.
046         * @param angle the angle to rotate
047         */
048            public RotateFilter(float angle) {
049                    this(angle, true);
050            }
051    
052            /**
053         * Construct a RotateFilter.
054         * @param angle the angle to rotate
055         * @param resize true if the output image should be resized
056         */
057            public RotateFilter(float angle, boolean resize) {
058                    setAngle(angle);
059                    this.resize = resize;
060            }
061    
062            /**
063         * Specifies the angle of rotation.
064         * @param angle the angle of rotation.
065         * @angle
066         * @see #getAngle
067         */
068            public void setAngle(float angle) {
069                    this.angle = angle;
070                    cos = (float)Math.cos(this.angle);
071                    sin = (float)Math.sin(this.angle);
072            }
073    
074            /**
075         * Returns the angle of rotation.
076         * @return the angle of rotation.
077         * @see #setAngle
078         */
079            public float getAngle() {
080                    return angle;
081            }
082    
083            protected void transformSpace(Rectangle rect) {
084                    if (resize) {
085                            Point out = new Point(0, 0);
086                            int minx = Integer.MAX_VALUE;
087                            int miny = Integer.MAX_VALUE;
088                            int maxx = Integer.MIN_VALUE;
089                            int maxy = Integer.MIN_VALUE;
090                            int w = rect.width;
091                            int h = rect.height;
092                            int x = rect.x;
093                            int y = rect.y;
094    
095                            for (int i = 0; i < 4; i++)  {
096                                    switch (i) {
097                                    case 0: transform(x, y, out); break;
098                                    case 1: transform(x + w, y, out); break;
099                                    case 2: transform(x, y + h, out); break;
100                                    case 3: transform(x + w, y + h, out); break;
101                                    }
102                                    minx = Math.min(minx, out.x);
103                                    miny = Math.min(miny, out.y);
104                                    maxx = Math.max(maxx, out.x);
105                                    maxy = Math.max(maxy, out.y);
106                            }
107    
108                            rect.x = minx;
109                            rect.y = miny;
110                            rect.width = maxx - minx;
111                            rect.height = maxy - miny;
112                    }
113            }
114            
115            
116    
117            private void transform(int x, int y, Point out) {
118                    out.x = (int)((x * cos) + (y * sin));
119                    out.y = (int)((y * cos) - (x * sin));
120            }
121    
122            protected void transformInverse(int x, int y, float[] out) {
123                    out[0] = (x * cos) - (y * sin);
124                    out[1] = (y * cos) + (x * sin);
125            }
126    
127            public String toString() {
128                    return "Rotate "+(int)(angle * 180 / Math.PI);
129            }
130    
131            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {
132                    //BufferedImage dst=ImageUtil.createBufferedImage(src,src.getWidth()+400,src.getHeight()+400);
133                    Object o;
134                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
135                    if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
136                    if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation"));
137    
138                    // check for arguments not supported
139                    if(parameters.size()>0) {
140                            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 [Angle, EdgeAction, Interpolation]");
141                    }
142                    
143                    
144    
145                    //Rectangle rect = new Rectangle(0, 0, src.getWidth(), src.getHeight());
146                    //transformSpace(rect);
147                    BufferedImage dst=null;//ImageUtil.createBufferedImage(src,rect.width,rect.height);
148                    
149                    return filter(src, dst);
150            }
151    }