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