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 distorts an image by twisting it from the centre out. 047 * The twisting is centred at the centre of the image and extends out to the smallest of 048 * the width and height. Pixels outside this radius are unaffected. 049 */ 050public class TwirlFilter extends TransformFilter implements DynFiltering { 051 052 private float angle = 0; 053 private float centreX = 0.5f; 054 private float centreY = 0.5f; 055 private float radius = 100; 056 057 private float radius2 = 0; 058 private float icentreX; 059 private float icentreY; 060 061 /** 062 * Construct a TwirlFilter with no distortion. 063 */ 064 public TwirlFilter() { 065 super(ConvolveFilter.CLAMP_EDGES ); 066 } 067 068 /** 069 * Set the angle of twirl in radians. 0 means no distortion. 070 * @param angle the angle of twirl. This is the angle by which pixels at the nearest edge of the image will move. 071 * @see #getAngle 072 */ 073 public void setAngle(float angle) { 074 this.angle = angle; 075 } 076 077 /** 078 * Get the angle of twist. 079 * @return the angle in radians. 080 * @see #setAngle 081 */ 082 public float getAngle() { 083 return angle; 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 /** 096 * Get the centre of the effect in the X direction as a proportion of the image size. 097 * @return the center 098 * @see #setCentreX 099 */ 100 public float getCentreX() { 101 return centreX; 102 } 103 104 /** 105 * Set the centre of the effect in the Y direction as a proportion of the image size. 106 * @param centreY the center 107 * @see #getCentreY 108 */ 109 public void setCentreY( float centreY ) { 110 this.centreY = centreY; 111 } 112 113 /** 114 * Get the centre of the effect in the Y direction as a proportion of the image size. 115 * @return the center 116 * @see #setCentreY 117 */ 118 public float getCentreY() { 119 return centreY; 120 } 121 122 /** 123 * Set the centre of the effect as a proportion of the image size. 124 * @param centre the center 125 * @see #getCentre 126 */ 127 public void setCentre( Point2D centre ) { 128 this.centreX = (float)centre.getX(); 129 this.centreY = (float)centre.getY(); 130 } 131 132 /** 133 * Get the centre of the effect as a proportion of the image size. 134 * @return the center 135 * @see #setCentre 136 */ 137 public Point2D getCentre() { 138 return new Point2D.Float( centreX, centreY ); 139 } 140 141 /** 142 * Set the radius of the effect. 143 * @param radius the radius 144 * @min-value 0 145 * @see #getRadius 146 */ 147 public void setRadius(float radius) { 148 this.radius = radius; 149 } 150 151 /** 152 * Get the radius of the effect. 153 * @return the radius 154 * @see #setRadius 155 */ 156 public float getRadius() { 157 return radius; 158 } 159 160 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 161 icentreX = src.getWidth() * centreX; 162 icentreY = src.getHeight() * centreY; 163 if ( radius == 0 ) 164 radius = Math.min(icentreX, icentreY); 165 radius2 = radius*radius; 166 return super.filter( src, dst ); 167 } 168 169 protected void transformInverse(int x, int y, float[] out) { 170 float dx = x-icentreX; 171 float dy = y-icentreY; 172 float distance = dx*dx + dy*dy; 173 if (distance > radius2) { 174 out[0] = x; 175 out[1] = y; 176 } else { 177 distance = (float)Math.sqrt(distance); 178 float a = (float)Math.atan2(dy, dx) + angle * (radius-distance) / radius; 179 out[0] = icentreX + distance*(float)Math.cos(a); 180 out[1] = icentreY + distance*(float)Math.sin(a); 181 } 182 } 183 184 public String toString() { 185 return "Distort/Twirl..."; 186 } 187 188 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 189 Object o; 190 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius")); 191 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 192 if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX")); 193 if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY")); 194 //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre")); 195 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 196 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 197 198 // check for arguments not supported 199 if(parameters.size()>0) { 200 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, EdgeAction, Interpolation]"); 201 } 202 203 return filter(src, dst); 204 } 205}