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.image.BufferedImage; 036import java.util.Random; 037 038import lucee.runtime.engine.ThreadLocalPageContext; 039import lucee.runtime.exp.FunctionException; 040import lucee.runtime.exp.PageException; 041import lucee.runtime.img.ImageUtil; 042import lucee.runtime.img.math.CellularFunction2D; 043import lucee.runtime.img.math.FBM; 044import lucee.runtime.img.math.Function2D; 045import lucee.runtime.img.math.Noise; 046import lucee.runtime.img.math.RidgedFBM; 047import lucee.runtime.img.math.SCNoise; 048import lucee.runtime.img.math.VLNoise; 049import lucee.runtime.type.KeyImpl; 050import lucee.runtime.type.Struct; 051import lucee.runtime.type.util.CollectionUtil; 052 053/** 054 * A filter which produces textures from fractal Brownian motion. 055 */ 056public class FBMFilter extends PointFilter implements Cloneable, DynFiltering { 057 058 public final static int NOISE = 0; 059 public final static int RIDGED = 1; 060 public final static int VLNOISE = 2; 061 public final static int SCNOISE = 3; 062 public final static int CELLULAR = 4; 063 064 private float scale = 32; 065 private float stretch = 1.0f; 066 private float angle = 0.0f; 067 private float amount = 1.0f; 068 private float H = 1.0f; 069 private float octaves = 4.0f; 070 private float lacunarity = 2.0f; 071 private float gain = 0.5f; 072 private float bias = 0.5f; 073 private int operation; 074 private float m00 = 1.0f; 075 private float m01 = 0.0f; 076 private float m10 = 0.0f; 077 private float m11 = 1.0f; 078 private float min; 079 private float max; 080 private Colormap colormap = new Gradient(); 081 //private boolean ridged; 082 private FBM fBm; 083 protected Random random = new Random(); 084 private int basisType = NOISE; 085 private Function2D basis; 086 087 public FBMFilter() { 088 setBasisType(NOISE); 089 } 090 091 /** 092 * Set the amount of effect. 093 * @param amount the amount 094 * @min-value 0 095 * @max-value 1 096 * @see #getAmount 097 */ 098 public void setAmount(float amount) { 099 this.amount = amount; 100 } 101 102 /** 103 * Get the amount of texture. 104 * @return the amount 105 * @see #setAmount 106 */ 107 public float getAmount() { 108 return amount; 109 } 110 111 public void setOperation(int operation) { 112 this.operation = operation; 113 } 114 115 public int getOperation() { 116 return operation; 117 } 118 119 /** 120 * Specifies the scale of the texture. 121 * @param scale the scale of the texture. 122 * @min-value 1 123 * @max-value 300+ 124 * @see #getScale 125 */ 126 public void setScale(float scale) { 127 this.scale = scale; 128 } 129 130 /** 131 * Returns the scale of the texture. 132 * @return the scale of the texture. 133 * @see #setScale 134 */ 135 public float getScale() { 136 return scale; 137 } 138 139 /** 140 * Specifies the stretch factor of the texture. 141 * @param stretch the stretch factor of the texture. 142 * @min-value 1 143 * @max-value 50+ 144 * @see #getStretch 145 */ 146 public void setStretch(float stretch) { 147 this.stretch = stretch; 148 } 149 150 /** 151 * Returns the stretch factor of the texture. 152 * @return the stretch factor of the texture. 153 * @see #setStretch 154 */ 155 public float getStretch() { 156 return stretch; 157 } 158 159 /** 160 * Specifies the angle of the texture. 161 * @param angle the angle of the texture. 162 * @angle 163 * @see #getAngle 164 */ 165 public void setAngle(float angle) { 166 this.angle = angle; 167 float cos = (float)Math.cos(this.angle); 168 float sin = (float)Math.sin(this.angle); 169 m00 = cos; 170 m01 = sin; 171 m10 = -sin; 172 m11 = cos; 173 } 174 175 /** 176 * Returns the angle of the texture. 177 * @return the angle of the texture. 178 * @see #setAngle 179 */ 180 public float getAngle() { 181 return angle; 182 } 183 184 public void setOctaves(float octaves) { 185 this.octaves = octaves; 186 } 187 188 public float getOctaves() { 189 return octaves; 190 } 191 192 public void setH(float H) { 193 this.H = H; 194 } 195 196 public float getH() { 197 return H; 198 } 199 200 public void setLacunarity(float lacunarity) { 201 this.lacunarity = lacunarity; 202 } 203 204 public float getLacunarity() { 205 return lacunarity; 206 } 207 208 public void setGain(float gain) { 209 this.gain = gain; 210 } 211 212 public float getGain() { 213 return gain; 214 } 215 216 public void setBias(float bias) { 217 this.bias = bias; 218 } 219 220 public float getBias() { 221 return bias; 222 } 223 224 /** 225 * Set the colormap to be used for the filter. 226 * @param colormap the colormap 227 * @see #getColormap 228 */ 229 public void setColormap(Colormap colormap) { 230 this.colormap = colormap; 231 } 232 233 /** 234 * Get the colormap to be used for the filter. 235 * @return the colormap 236 * @see #setColormap 237 */ 238 public Colormap getColormap() { 239 return colormap; 240 } 241 242 public void setBasisType(int basisType) { 243 this.basisType = basisType; 244 switch (basisType) { 245 default: 246 case NOISE: 247 basis = new Noise(); 248 break; 249 case RIDGED: 250 basis = new RidgedFBM(); 251 break; 252 case VLNOISE: 253 basis = new VLNoise(); 254 break; 255 case SCNOISE: 256 basis = new SCNoise(); 257 break; 258 case CELLULAR: 259 basis = new CellularFunction2D(); 260 break; 261 } 262 } 263 264 public int getBasisType() { 265 return basisType; 266 } 267 268 public void setBasis(Function2D basis) { 269 this.basis = basis; 270 } 271 272 public Function2D getBasis() { 273 return basis; 274 } 275 276 protected FBM makeFBM(float H, float lacunarity, float octaves) { 277 FBM fbm = new FBM(H, lacunarity, octaves, basis); 278 float[] minmax = Noise.findRange(fbm, null); 279 min = minmax[0]; 280 max = minmax[1]; 281 return fbm; 282 } 283 284 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 285 fBm = makeFBM(H, lacunarity, octaves); 286 return super.filter( src, dst ); 287 } 288 289 public int filterRGB(int x, int y, int rgb) { 290 float nx = m00*x + m01*y; 291 float ny = m10*x + m11*y; 292 nx /= scale; 293 ny /= scale * stretch; 294 float f = fBm.evaluate(nx, ny); 295 // Normalize to 0..1 296 f = (f-min)/(max-min); 297 f = ImageMath.gain(f, gain); 298 f = ImageMath.bias(f, bias); 299 f *= amount; 300 int a = rgb & 0xff000000; 301 int v; 302 if (colormap != null) 303 v = colormap.getColor(f); 304 else { 305 v = PixelUtils.clamp((int)(f*255)); 306 int r = v << 16; 307 int g = v << 8; 308 int b = v; 309 v = a|r|g|b; 310 } 311 if (operation != PixelUtils.REPLACE) 312 v = PixelUtils.combinePixels(rgb, v, operation); 313 return v; 314 } 315 316 public String toString() { 317 return "Texture/Fractal Brownian Motion..."; 318 } 319 320 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 321 Object o; 322 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 323 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 324 if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch")); 325 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 326 if((o=parameters.removeEL(KeyImpl.init("BasisType")))!=null)setBasisType(ImageFilterUtil.toIntValue(o,"BasisType")); 327 if((o=parameters.removeEL(KeyImpl.init("Operation")))!=null)setOperation(ImageFilterUtil.toIntValue(o,"Operation")); 328 if((o=parameters.removeEL(KeyImpl.init("Octaves")))!=null)setOctaves(ImageFilterUtil.toFloatValue(o,"Octaves")); 329 if((o=parameters.removeEL(KeyImpl.init("H")))!=null)setH(ImageFilterUtil.toFloatValue(o,"H")); 330 if((o=parameters.removeEL(KeyImpl.init("Lacunarity")))!=null)setLacunarity(ImageFilterUtil.toFloatValue(o,"Lacunarity")); 331 if((o=parameters.removeEL(KeyImpl.init("Gain")))!=null)setGain(ImageFilterUtil.toFloatValue(o,"Gain")); 332 if((o=parameters.removeEL(KeyImpl.init("Bias")))!=null)setBias(ImageFilterUtil.toFloatValue(o,"Bias")); 333 if((o=parameters.removeEL(KeyImpl.init("Basis")))!=null)setBasis(ImageFilterUtil.toFunction2D(o,"Basis")); 334 if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale")); 335 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 336 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 337 setDimensions(dim[0],dim[1]); 338 } 339 340 // check for arguments not supported 341 if(parameters.size()>0) { 342 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 [Colormap, Amount, Stretch, Angle, BasisType, Operation, Octaves, H, Lacunarity, Gain, Bias, Basis, Scale, Dimensions]"); 343 } 344 345 return filter(src, dst); 346 } 347}