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 a water ripple distortion. 029 */ 030 public class WaterFilter extends TransformFilter implements DynFiltering { 031 032 private float wavelength = 16; 033 private float amplitude = 10; 034 private float phase = 0; 035 private float centreX = 0.5f; 036 private float centreY = 0.5f; 037 private float radius = 50; 038 039 private float radius2 = 0; 040 private float icentreX; 041 private float icentreY; 042 043 public WaterFilter() { 044 super(ConvolveFilter.CLAMP_EDGES ); 045 } 046 047 /** 048 * Set the wavelength of the ripples. 049 * @param wavelength the wavelength 050 * @see #getWavelength 051 */ 052 public void setWavelength(float wavelength) { 053 this.wavelength = wavelength; 054 } 055 056 /** 057 * Get the wavelength of the ripples. 058 * @return the wavelength 059 * @see #setWavelength 060 */ 061 public float getWavelength() { 062 return wavelength; 063 } 064 065 /** 066 * Set the amplitude of the ripples. 067 * @param amplitude the amplitude 068 * @see #getAmplitude 069 */ 070 public void setAmplitude(float amplitude) { 071 this.amplitude = amplitude; 072 } 073 074 /** 075 * Get the amplitude of the ripples. 076 * @return the amplitude 077 * @see #setAmplitude 078 */ 079 public float getAmplitude() { 080 return amplitude; 081 } 082 083 /** 084 * Set the phase of the ripples. 085 * @param phase the phase 086 * @see #getPhase 087 */ 088 public void setPhase(float phase) { 089 this.phase = phase; 090 } 091 092 /** 093 * Get the phase of the ripples. 094 * @return the phase 095 * @see #setPhase 096 */ 097 public float getPhase() { 098 return phase; 099 } 100 101 /** 102 * Set the centre of the effect in the X direction as a proportion of the image size. 103 * @param centreX the center 104 * @see #getCentreX 105 */ 106 public void setCentreX( float centreX ) { 107 this.centreX = centreX; 108 } 109 110 /** 111 * Get the centre of the effect in the X direction as a proportion of the image size. 112 * @return the center 113 * @see #setCentreX 114 */ 115 public float getCentreX() { 116 return centreX; 117 } 118 119 /** 120 * Set the centre of the effect in the Y direction as a proportion of the image size. 121 * @param centreY the center 122 * @see #getCentreY 123 */ 124 public void setCentreY( float centreY ) { 125 this.centreY = centreY; 126 } 127 128 /** 129 * Get the centre of the effect in the Y direction as a proportion of the image size. 130 * @return the center 131 * @see #setCentreY 132 */ 133 public float getCentreY() { 134 return centreY; 135 } 136 137 /** 138 * Set the centre of the effect as a proportion of the image size. 139 * @param centre the center 140 * @see #getCentre 141 */ 142 public void setCentre( Point2D centre ) { 143 this.centreX = (float)centre.getX(); 144 this.centreY = (float)centre.getY(); 145 } 146 147 /** 148 * Get the centre of the effect as a proportion of the image size. 149 * @return the center 150 * @see #setCentre 151 */ 152 public Point2D getCentre() { 153 return new Point2D.Float( centreX, centreY ); 154 } 155 156 /** 157 * Set the radius of the effect. 158 * @param radius the radius 159 * @min-value 0 160 * @see #getRadius 161 */ 162 public void setRadius(float radius) { 163 this.radius = radius; 164 } 165 166 /** 167 * Get the radius of the effect. 168 * @return the radius 169 * @see #setRadius 170 */ 171 public float getRadius() { 172 return radius; 173 } 174 175 private boolean inside(int v, int a, int b) { 176 return a <= v && v <= b; 177 } 178 179 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 180 icentreX = src.getWidth() * centreX; 181 icentreY = src.getHeight() * centreY; 182 if ( radius == 0 ) 183 radius = Math.min(icentreX, icentreY); 184 radius2 = radius*radius; 185 return super.filter( src, dst ); 186 } 187 188 protected void transformInverse(int x, int y, float[] out) { 189 float dx = x-icentreX; 190 float dy = y-icentreY; 191 float distance2 = dx*dx + dy*dy; 192 if (distance2 > radius2) { 193 out[0] = x; 194 out[1] = y; 195 } else { 196 float distance = (float)Math.sqrt(distance2); 197 float amount = amplitude * (float)Math.sin(distance / wavelength * ImageMath.TWO_PI - phase); 198 amount *= (radius-distance)/radius; 199 if ( distance != 0 ) 200 amount *= wavelength/distance; 201 out[0] = x + dx*amount; 202 out[1] = y + dy*amount; 203 } 204 } 205 206 public String toString() { 207 return "Distort/Water Ripples..."; 208 } 209 210 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 211 Object o; 212 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius")); 213 if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX")); 214 if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY")); 215 //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre")); 216 if((o=parameters.removeEL(KeyImpl.init("Wavelength")))!=null)setWavelength(ImageFilterUtil.toFloatValue(o,"Wavelength")); 217 if((o=parameters.removeEL(KeyImpl.init("Amplitude")))!=null)setAmplitude(ImageFilterUtil.toFloatValue(o,"Amplitude")); 218 if((o=parameters.removeEL(KeyImpl.init("Phase")))!=null)setPhase(ImageFilterUtil.toFloatValue(o,"Phase")); 219 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 220 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 221 222 // check for arguments not supported 223 if(parameters.size()>0) { 224 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, CentreX, CentreY, Centre, Wavelength, Amplitude, Phase, EdgeAction, Interpolation]"); 225 } 226 227 return filter(src, dst); 228 } 229 }