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.List; 025 import railo.runtime.type.Struct; 026 027 /** 028 * A filter which simulates a lens placed over an image. 029 */ 030 public class SphereFilter extends TransformFilter implements DynFiltering { 031 032 private float a = 0; 033 private float b = 0; 034 private float a2 = 0; 035 private float b2 = 0; 036 private float centreX = 0.5f; 037 private float centreY = 0.5f; 038 private float refractionIndex = 1.5f; 039 040 private float icentreX; 041 private float icentreY; 042 043 public SphereFilter() { 044 super(ConvolveFilter.CLAMP_EDGES ); 045 setRadius( 100.0f ); 046 } 047 048 /** 049 * Set the index of refaction. 050 * @param refractionIndex the index of refaction 051 * @see #getRefractionIndex 052 */ 053 public void setRefractionIndex(float refractionIndex) { 054 this.refractionIndex = refractionIndex; 055 } 056 057 /** 058 * Get the index of refaction. 059 * @return the index of refaction 060 * @see #setRefractionIndex 061 */ 062 public float getRefractionIndex() { 063 return refractionIndex; 064 } 065 066 /** 067 * Set the radius of the effect. 068 * @param r the radius 069 * @min-value 0 070 * @see #getRadius 071 */ 072 public void setRadius(float r) { 073 this.a = r; 074 this.b = r; 075 } 076 077 /** 078 * Get the radius of the effect. 079 * @return the radius 080 * @see #setRadius 081 */ 082 public float getRadius() { 083 return a; 084 } 085 086 /** 087 * Set the centre of the effect in the X direction as a proportion of the image size. 088 * @param centreX the center 089 * @see #getCentreX 090 */ 091 public void setCentreX( float centreX ) { 092 this.centreX = centreX; 093 } 094 095 public float getCentreX() { 096 return centreX; 097 } 098 099 /** 100 * Set the centre of the effect in the Y direction as a proportion of the image size. 101 * @param centreY the center 102 * @see #getCentreY 103 */ 104 public void setCentreY( float centreY ) { 105 this.centreY = centreY; 106 } 107 108 /** 109 * Get the centre of the effect in the Y direction as a proportion of the image size. 110 * @return the center 111 * @see #setCentreY 112 */ 113 public float getCentreY() { 114 return centreY; 115 } 116 117 /** 118 * Set the centre of the effect as a proportion of the image size. 119 * @param centre the center 120 * @see #getCentre 121 */ 122 public void setCentre( Point2D centre ) { 123 this.centreX = (float)centre.getX(); 124 this.centreY = (float)centre.getY(); 125 } 126 127 /** 128 * Get the centre of the effect as a proportion of the image size. 129 * @return the center 130 * @see #setCentre 131 */ 132 public Point2D getCentre() { 133 return new Point2D.Float( centreX, centreY ); 134 } 135 136 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 137 int width = src.getWidth(); 138 int height = src.getHeight(); 139 icentreX = width * centreX; 140 icentreY = height * centreY; 141 if (a == 0) 142 a = width/2; 143 if (b == 0) 144 b = height/2; 145 a2 = a*a; 146 b2 = b*b; 147 return super.filter( src, dst ); 148 } 149 150 protected void transformInverse(int x, int y, float[] out) { 151 float dx = x-icentreX; 152 float dy = y-icentreY; 153 float x2 = dx*dx; 154 float y2 = dy*dy; 155 if (y2 >= (b2 - (b2*x2)/a2)) { 156 out[0] = x; 157 out[1] = y; 158 } else { 159 float rRefraction = 1.0f / refractionIndex; 160 161 float z = (float)Math.sqrt((1.0f - x2/a2 - y2/b2) * (a*b)); 162 float z2 = z*z; 163 164 float xAngle = (float)Math.acos(dx / Math.sqrt(x2+z2)); 165 float angle1 = ImageMath.HALF_PI - xAngle; 166 float angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction); 167 angle2 = ImageMath.HALF_PI - xAngle - angle2; 168 out[0] = x - (float)Math.tan(angle2)*z; 169 170 float yAngle = (float)Math.acos(dy / Math.sqrt(y2+z2)); 171 angle1 = ImageMath.HALF_PI - yAngle; 172 angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction); 173 angle2 = ImageMath.HALF_PI - yAngle - angle2; 174 out[1] = y - (float)Math.tan(angle2)*z; 175 } 176 } 177 178 public String toString() { 179 return "Distort/Sphere..."; 180 } 181 182 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 183 Object o; 184 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius")); 185 if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX")); 186 if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY")); 187 //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre")); 188 if((o=parameters.removeEL(KeyImpl.init("RefractionIndex")))!=null)setRefractionIndex(ImageFilterUtil.toFloatValue(o,"RefractionIndex")); 189 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 190 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 191 192 // check for arguments not supported 193 if(parameters.size()>0) { 194 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Radius, CentreX, CentreY, Centre, RefractionIndex, EdgeAction, Interpolation]"); 195 } 196 197 return filter(src, dst); 198 } 199 }