001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019/* 020* 021 022Licensed under the Apache License, Version 2.0 (the "License"); 023you may not use this file except in compliance with the License. 024You may obtain a copy of the License at 025 026 http://www.apache.org/licenses/LICENSE-2.0 027 028Unless required by applicable law or agreed to in writing, software 029distributed under the License is distributed on an "AS IS" BASIS, 030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 031See the License for the specific language governing permissions and 032limitations under the License. 033*/ 034 035package lucee.runtime.img.filter;import java.awt.geom.Point2D; 036import java.awt.image.BufferedImage; 037 038import lucee.runtime.engine.ThreadLocalPageContext; 039import lucee.runtime.exp.FunctionException; 040import lucee.runtime.exp.PageException; 041import lucee.runtime.type.KeyImpl; 042import lucee.runtime.type.Struct; 043import lucee.runtime.type.util.CollectionUtil; 044 045/** 046 * A Filter which produces the effect of looking into a kaleidoscope. 047 */ 048public class KaleidoscopeFilter extends TransformFilter implements DynFiltering { 049 050 private float angle = 0; 051 private float angle2 = 0; 052 private float centreX = 0.5f; 053 private float centreY = 0.5f; 054 private int sides = 3; 055 private float radius = 0; 056 057 private float icentreX; 058 private float icentreY; 059 060 /** 061 * Construct a KaleidoscopeFilter with no distortion. 062 */ 063 public KaleidoscopeFilter() { 064 super(ConvolveFilter.CLAMP_EDGES ); 065 } 066 067 /** 068 * Set the number of sides of the kaleidoscope. 069 * @param sides the number of sides 070 * @min-value 2 071 * @see #getSides 072 */ 073 public void setSides(int sides) { 074 this.sides = sides; 075 } 076 077 /** 078 * Get the number of sides of the kaleidoscope. 079 * @return the number of sides 080 * @see #setSides 081 */ 082 public int getSides() { 083 return sides; 084 } 085 086 /** 087 * Set the angle of the kaleidoscope. 088 * @param angle the angle of the kaleidoscope. 089 * @angle 090 * @see #getAngle 091 */ 092 public void setAngle(float angle) { 093 this.angle = angle; 094 } 095 096 /** 097 * Get the angle of the kaleidoscope. 098 * @return the angle of the kaleidoscope. 099 * @see #setAngle 100 */ 101 public float getAngle() { 102 return angle; 103 } 104 105 /** 106 * Set the secondary angle of the kaleidoscope. 107 * @param angle2 the angle 108 * @angle 109 * @see #getAngle2 110 */ 111 public void setAngle2(float angle2) { 112 this.angle2 = angle2; 113 } 114 115 /** 116 * Get the secondary angle of the kaleidoscope. 117 * @return the angle 118 * @see #setAngle2 119 */ 120 public float getAngle2() { 121 return angle2; 122 } 123 124 /** 125 * Set the centre of the effect in the X direction as a proportion of the image size. 126 * @param centreX the center 127 * @see #getCentreX 128 */ 129 public void setCentreX( float centreX ) { 130 this.centreX = centreX; 131 } 132 133 /** 134 * Get the centre of the effect in the X direction as a proportion of the image size. 135 * @return the center 136 * @see #setCentreX 137 */ 138 public float getCentreX() { 139 return centreX; 140 } 141 142 /** 143 * Set the centre of the effect in the Y direction as a proportion of the image size. 144 * @param centreY the center 145 * @see #getCentreY 146 */ 147 public void setCentreY( float centreY ) { 148 this.centreY = centreY; 149 } 150 151 /** 152 * Get the centre of the effect in the Y direction as a proportion of the image size. 153 * @return the center 154 * @see #setCentreY 155 */ 156 public float getCentreY() { 157 return centreY; 158 } 159 160 /** 161 * Set the centre of the effect as a proportion of the image size. 162 * @param centre the center 163 * @see #getCentre 164 */ 165 public void setCentre( Point2D centre ) { 166 this.centreX = (float)centre.getX(); 167 this.centreY = (float)centre.getY(); 168 } 169 170 /** 171 * Get the centre of the effect as a proportion of the image size. 172 * @return the center 173 * @see #setCentre 174 */ 175 public Point2D getCentre() { 176 return new Point2D.Float( centreX, centreY ); 177 } 178 179 /** 180 * Set the radius of the effect. 181 * @param radius the radius 182 * @min-value 0 183 * @see #getRadius 184 */ 185 public void setRadius( float radius ) { 186 this.radius = radius; 187 } 188 189 /** 190 * Get the radius of the effect. 191 * @return the radius 192 * @see #setRadius 193 */ 194 public float getRadius() { 195 return radius; 196 } 197 198 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 199 icentreX = src.getWidth() * centreX; 200 icentreY = src.getHeight() * centreY; 201 return super.filter( src, dst ); 202 } 203 204 protected void transformInverse(int x, int y, float[] out) { 205 double dx = x-icentreX; 206 double dy = y-icentreY; 207 double r = Math.sqrt( dx*dx + dy*dy ); 208 double theta = Math.atan2( dy, dx ) - angle - angle2; 209 theta = ImageMath.triangle( (float)( theta/Math.PI*sides*.5 ) ); 210 if ( radius != 0 ) { 211 double c = Math.cos(theta); 212 double radiusc = radius/c; 213 r = radiusc * ImageMath.triangle( (float)(r/radiusc) ); 214 } 215 theta += angle; 216 217 out[0] = (float)(icentreX + r*Math.cos(theta)); 218 out[1] = (float)(icentreY + r*Math.sin(theta)); 219 } 220 221 public String toString() { 222 return "Distort/Kaleidoscope..."; 223 } 224 225 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 226 Object o; 227 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius")); 228 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 229 if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX")); 230 if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY")); 231 //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre")); 232 if((o=parameters.removeEL(KeyImpl.init("Sides")))!=null)setSides(ImageFilterUtil.toIntValue(o,"Sides")); 233 if((o=parameters.removeEL(KeyImpl.init("Angle2")))!=null)setAngle2(ImageFilterUtil.toFloatValue(o,"Angle2")); 234 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 235 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 236 237 // check for arguments not supported 238 if(parameters.size()>0) { 239 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]"); 240 } 241 242 return filter(src, dst); 243 } 244}