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.geom.Point2D;
018    import java.awt.image.BufferedImage;
019    
020    import railo.runtime.engine.ThreadLocalPageContext;
021    import railo.runtime.exp.ExpressionException;
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     * A filter which wraps an image around a circular arc.
029     */
030    public class CircleFilter extends TransformFilter  implements DynFiltering {
031    
032            private float radius = 10;
033            private float height = 20;
034            private float angle = 0;
035            private float spreadAngle = (float)Math.PI;
036            private float centreX = 0.5f;
037            private float centreY = 0.5f;
038    
039            private float icentreX;
040            private float icentreY;
041            private float iWidth;
042            private float iHeight;
043    
044            /**
045         * Construct a CircleFilter.
046         */
047        public CircleFilter() {
048                    try {
049                            setEdgeAction( "ZERO" );
050                    } catch (ExpressionException e) {}
051            }
052    
053            /**
054         * Set the height of the arc.
055         * @param height the height
056         * @see #getHeight
057         */
058            public void setHeight(float height) {
059                    this.height = height;
060            }
061    
062            /**
063         * Get the height of the arc.
064         * @return the height
065         * @see #setHeight
066         */
067            public float getHeight() {
068                    return height;
069            }
070    
071            /**
072         * Set the angle of the arc.
073         * @param angle the angle of the arc.
074         * @angle
075         * @see #getAngle
076         */
077            public void setAngle(float angle) {
078                    this.angle = angle;
079            }
080    
081            /**
082         * Returns the angle of the arc.
083         * @return the angle of the arc.
084         * @see #setAngle
085         */
086            public float getAngle() {
087                    return angle;
088            }
089    
090            /**
091         * Set the spread angle of the arc.
092         * @param spreadAngle the angle
093         * @angle
094         * @see #getSpreadAngle
095         */
096            public void setSpreadAngle(float spreadAngle) {
097                    this.spreadAngle = spreadAngle;
098            }
099    
100            /**
101         * Get the spread angle of the arc.
102         * @return the angle
103         * @angle
104         * @see #setSpreadAngle
105         */
106            public float getSpreadAngle() {
107                    return spreadAngle;
108            }
109    
110            /**
111             * Set the radius of the effect.
112             * @param radius the radius
113         * @min-value 0
114         * @see #getRadius
115             */
116            public void setRadius(float radius) {
117                    this.radius = radius;
118            }
119    
120            /**
121             * Get the radius of the effect.
122             * @return the radius
123         * @see #setRadius
124             */
125            public float getRadius() {
126                    return radius;
127            }
128    
129            /**
130             * Set the centre of the effect in the Y direction as a proportion of the image size.
131             * @param centreX the center
132         * @see #getCentreX
133             */
134            public void setCentreX( float centreX ) {
135                    this.centreX = centreX;
136            }
137    
138            /**
139             * Get the centre of the effect in the X direction as a proportion of the image size.
140             * @return the center
141         * @see #setCentreX
142             */
143            public float getCentreX() {
144                    return centreX;
145            }
146            
147            /**
148             * Set the centre of the effect in the Y direction as a proportion of the image size.
149             * @param centreY the center
150         * @see #getCentreY
151             */
152            public void setCentreY( float centreY ) {
153                    this.centreY = centreY;
154            }
155    
156            /**
157             * Get the centre of the effect in the Y direction as a proportion of the image size.
158             * @return the center
159         * @see #setCentreY
160             */
161            public float getCentreY() {
162                    return centreY;
163            }
164            
165            /**
166             * Set the centre of the effect as a proportion of the image size.
167             * @param centre the center
168         * @see #getCentre
169             */
170            public void setCentre( Point2D centre ) {
171                    this.centreX = (float)centre.getX();
172                    this.centreY = (float)centre.getY();
173            }
174    
175            /**
176             * Get the centre of the effect as a proportion of the image size.
177             * @return the center
178         * @see #setCentre
179             */
180            public Point2D getCentre() {
181                    return new Point2D.Float( centreX, centreY );
182            }
183            
184        public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
185                    iWidth = src.getWidth();
186                    iHeight = src.getHeight();
187                    icentreX = iWidth * centreX;
188                    icentreY = iHeight * centreY;
189                    iWidth--;
190                    return super.filter( src, dst );
191            }
192            
193            protected void transformInverse(int x, int y, float[] out) {
194                    float dx = x-icentreX;
195                    float dy = y-icentreY;
196                    float theta = (float)Math.atan2( -dy, -dx ) + angle;
197                    float r = (float)Math.sqrt( dx*dx + dy*dy );
198    
199                    theta = ImageMath.mod( theta, 2*(float)Math.PI );
200    
201                    out[0] = iWidth * theta/(spreadAngle+0.00001f);
202                    out[1] = iHeight * (1-(r-radius)/(height+0.00001f));
203            }
204    
205            public String toString() {
206                    return "Distort/Circle...";
207            }
208    
209            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src);
210                    Object o;
211                    if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius"));
212                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
213                    if((o=parameters.removeEL(KeyImpl.init("SpreadAngle")))!=null)setSpreadAngle(ImageFilterUtil.toFloatValue(o,"SpreadAngle"));
214                    if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX"));
215                    if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY"));
216                    //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre"));
217                    if((o=parameters.removeEL(KeyImpl.init("Height")))!=null)setHeight(ImageFilterUtil.toFloatValue(o,"Height"));
218                    if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
219                    if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation"));
220    
221                    // check for arguments not supported
222                    if(parameters.size()>0) {
223                            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 [Radius, Angle, SpreadAngle, CentreX, CentreY, Centre, Height, EdgeAction, Interpolation]");
224                    }
225    
226                    return filter(src, dst);
227            }
228    }