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.image.BufferedImage; 018 019 import railo.runtime.engine.ThreadLocalPageContext; 020 import railo.runtime.exp.FunctionException; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.img.ImageUtil; 023 import railo.runtime.img.math.Function2D; 024 import railo.runtime.img.math.Noise; 025 import railo.runtime.type.KeyImpl; 026 import railo.runtime.type.Struct; 027 import railo.runtime.type.util.CollectionUtil; 028 029 public class TextureFilter extends PointFilter implements DynFiltering { 030 031 private float scale = 32; 032 private float stretch = 1.0f; 033 private float angle = 0.0f; 034 public float amount = 1.0f; 035 public float turbulence = 1.0f; 036 public float gain = 0.5f; 037 public float bias = 0.5f; 038 public int operation; 039 private float m00 = 1.0f; 040 private float m01 = 0.0f; 041 private float m10 = 0.0f; 042 private float m11 = 1.0f; 043 private Colormap colormap = new Gradient(); 044 private Function2D function = new Noise(); 045 046 public TextureFilter() { 047 } 048 049 /** 050 * Set the amount of texture. 051 * @param amount the amount 052 * @min-value 0 053 * @max-value 1 054 * @see #getAmount 055 */ 056 public void setAmount(float amount) { 057 this.amount = amount; 058 } 059 060 /** 061 * Get the amount of texture. 062 * @return the amount 063 * @see #setAmount 064 */ 065 public float getAmount() { 066 return amount; 067 } 068 069 public void setFunction(Function2D function) { 070 this.function = function; 071 } 072 073 public Function2D getFunction() { 074 return function; 075 } 076 077 public void setOperation(int operation) { 078 this.operation = operation; 079 } 080 081 public int getOperation() { 082 return operation; 083 } 084 085 /** 086 * Specifies the scale of the texture. 087 * @param scale the scale of the texture. 088 * @min-value 1 089 * @max-value 300+ 090 * @see #getScale 091 */ 092 public void setScale(float scale) { 093 this.scale = scale; 094 } 095 096 /** 097 * Returns the scale of the texture. 098 * @return the scale of the texture. 099 * @see #setScale 100 */ 101 public float getScale() { 102 return scale; 103 } 104 105 /** 106 * Specifies the stretch factor of the texture. 107 * @param stretch the stretch factor of the texture. 108 * @min-value 1 109 * @max-value 50+ 110 * @see #getStretch 111 */ 112 public void setStretch(float stretch) { 113 this.stretch = stretch; 114 } 115 116 /** 117 * Returns the stretch factor of the texture. 118 * @return the stretch factor of the texture. 119 * @see #setStretch 120 */ 121 public float getStretch() { 122 return stretch; 123 } 124 125 /** 126 * Specifies the angle of the texture. 127 * @param angle the angle of the texture. 128 * @angle 129 * @see #getAngle 130 */ 131 public void setAngle(float angle) { 132 this.angle = angle; 133 float cos = (float)Math.cos(angle); 134 float sin = (float)Math.sin(angle); 135 m00 = cos; 136 m01 = sin; 137 m10 = -sin; 138 m11 = cos; 139 } 140 141 /** 142 * Returns the angle of the texture. 143 * @return the angle of the texture. 144 * @see #setAngle 145 */ 146 public float getAngle() { 147 return angle; 148 } 149 150 /** 151 * Specifies the turbulence of the texture. 152 * @param turbulence the turbulence of the texture. 153 * @min-value 0 154 * @max-value 1 155 * @see #getTurbulence 156 */ 157 public void setTurbulence(float turbulence) { 158 this.turbulence = turbulence; 159 } 160 161 /** 162 * Returns the turbulence of the texture. 163 * @return the turbulence of the texture. 164 * @see #setTurbulence 165 */ 166 public float getTurbulence() { 167 return turbulence; 168 } 169 170 /** 171 * Set the colormap to be used for the filter. 172 * @param colormap the colormap 173 * @see #getColormap 174 */ 175 public void setColormap(Colormap colormap) { 176 this.colormap = colormap; 177 } 178 179 /** 180 * Get the colormap to be used for the filter. 181 * @return the colormap 182 * @see #setColormap 183 */ 184 public Colormap getColormap() { 185 return colormap; 186 } 187 188 public int filterRGB(int x, int y, int rgb) { 189 float nx = m00*x + m01*y; 190 float ny = m10*x + m11*y; 191 nx /= scale; 192 ny /= scale * stretch; 193 float f = turbulence == 1.0 ? Noise.noise2(nx, ny) : Noise.turbulence2(nx, ny, turbulence); 194 f = (f * 0.5f) + 0.5f; 195 f = ImageMath.gain(f, gain); 196 f = ImageMath.bias(f, bias); 197 f *= amount; 198 int a = rgb & 0xff000000; 199 int v; 200 if (colormap != null) 201 v = colormap.getColor(f); 202 else { 203 v = PixelUtils.clamp((int)(f*255)); 204 int r = v << 16; 205 int g = v << 8; 206 int b = v; 207 v = a|r|g|b; 208 } 209 if (operation != PixelUtils.REPLACE) 210 v = PixelUtils.combinePixels(rgb, v, operation); 211 return v; 212 } 213 214 public String toString() { 215 return "Texture/Noise..."; 216 } 217 218 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 219 Object o; 220 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 221 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 222 if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence")); 223 if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch")); 224 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 225 if((o=parameters.removeEL(KeyImpl.init("Operation")))!=null)setOperation(ImageFilterUtil.toIntValue(o,"Operation")); 226 if((o=parameters.removeEL(KeyImpl.init("Function")))!=null)setFunction(ImageFilterUtil.toFunction2D(o,"Function")); 227 if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale")); 228 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 229 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 230 setDimensions(dim[0],dim[1]); 231 } 232 233 // check for arguments not supported 234 if(parameters.size()>0) { 235 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, Turbulence, Stretch, Angle, Operation, Function, Scale, Dimensions]"); 236 } 237 238 return filter(src, dst); 239 } 240 }