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