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.Rectangle; 018 import java.awt.image.BufferedImage; 019 import java.util.Date; 020 import java.util.Random; 021 022 import railo.runtime.engine.ThreadLocalPageContext; 023 import railo.runtime.exp.FunctionException; 024 import railo.runtime.exp.PageException; 025 import railo.runtime.img.ImageUtil; 026 import railo.runtime.type.KeyImpl; 027 import railo.runtime.type.Struct; 028 import railo.runtime.type.util.CollectionUtil; 029 030 public class PlasmaFilter extends WholeImageFilter implements DynFiltering { 031 032 public float turbulence = 1.0f; 033 private float scaling = 0.0f; 034 private Colormap colormap = new LinearColormap(); 035 private Random randomGenerator; 036 private long seed = 567; 037 private boolean useColormap = false; 038 private boolean useImageColors = false; 039 040 public PlasmaFilter() { 041 randomGenerator = new Random(); 042 } 043 044 /** 045 * Specifies the turbulence of the texture. 046 * @param turbulence the turbulence of the texture. 047 * @min-value 0 048 * @max-value 10 049 * @see #getTurbulence 050 */ 051 public void setTurbulence(float turbulence) { 052 this.turbulence = turbulence; 053 } 054 055 /** 056 * Returns the turbulence of the effect. 057 * @return the turbulence of the effect. 058 * @see #setTurbulence 059 */ 060 public float getTurbulence() { 061 return turbulence; 062 } 063 064 public void setScaling(float scaling) { 065 this.scaling = scaling; 066 } 067 068 public float getScaling() { 069 return scaling; 070 } 071 072 /** 073 * Set the colormap to be used for the filter. 074 * @param colormap the colormap 075 * @see #getColormap 076 */ 077 public void setColormap(Colormap colormap) { 078 this.colormap = colormap; 079 } 080 081 /** 082 * Get the colormap to be used for the filter. 083 * @return the colormap 084 * @see #setColormap 085 */ 086 public Colormap getColormap() { 087 return colormap; 088 } 089 090 public void setUseColormap(boolean useColormap) { 091 this.useColormap = useColormap; 092 } 093 094 public boolean getUseColormap() { 095 return useColormap; 096 } 097 098 public void setUseImageColors(boolean useImageColors) { 099 this.useImageColors = useImageColors; 100 } 101 102 public boolean getUseImageColors() { 103 return useImageColors; 104 } 105 106 public void setSeed(int seed) { 107 this.seed = seed; 108 } 109 110 public int getSeed() { 111 return (int)seed; 112 } 113 114 public void randomize() { 115 seed = new Date().getTime(); 116 } 117 118 private int randomRGB(int[] inPixels, int x, int y) { 119 if (useImageColors) { 120 return inPixels[y*originalSpace.width+x]; 121 } 122 int r = (int)(255 * randomGenerator.nextFloat()); 123 int g = (int)(255 * randomGenerator.nextFloat()); 124 int b = (int)(255 * randomGenerator.nextFloat()); 125 return 0xff000000 | (r << 16) | (g << 8) | b; 126 } 127 128 private int displace(int rgb, float amount) { 129 int r = (rgb >> 16) & 0xff; 130 int g = (rgb >> 8) & 0xff; 131 int b = rgb & 0xff; 132 r = PixelUtils.clamp(r + (int)(amount * (randomGenerator.nextFloat()-0.5))); 133 g = PixelUtils.clamp(g + (int)(amount * (randomGenerator.nextFloat()-0.5))); 134 b = PixelUtils.clamp(b + (int)(amount * (randomGenerator.nextFloat()-0.5))); 135 return 0xff000000 | (r << 16) | (g << 8) | b; 136 } 137 138 private int average(int rgb1, int rgb2) { 139 return PixelUtils.combinePixels(rgb1, rgb2, PixelUtils.AVERAGE); 140 } 141 142 private int getPixel(int x, int y, int[] pixels, int stride) { 143 return pixels[y*stride+x]; 144 } 145 146 private void putPixel(int x, int y, int rgb, int[] pixels, int stride) { 147 pixels[y*stride+x] = rgb; 148 } 149 150 private boolean doPixel(int x1, int y1, int x2, int y2, int[] pixels, int stride, int depth, int scale) { 151 int mx, my; 152 153 if (depth == 0) { 154 int ml, mr, mt, mb, mm, t; 155 156 int tl = getPixel(x1, y1, pixels, stride); 157 int bl = getPixel(x1, y2, pixels, stride); 158 int tr = getPixel(x2, y1, pixels, stride); 159 int br = getPixel(x2, y2, pixels, stride); 160 161 float amount = (256.0f / (2.0f * scale)) * turbulence; 162 163 mx = (x1 + x2) / 2; 164 my = (y1 + y2) / 2; 165 166 if (mx == x1 && mx == x2 && my == y1 && my == y2) 167 return true; 168 169 if (mx != x1 || mx != x2) { 170 ml = average(tl, bl); 171 ml = displace(ml, amount); 172 putPixel(x1, my, ml, pixels, stride); 173 174 if (x1 != x2){ 175 mr = average(tr, br); 176 mr = displace(mr, amount); 177 putPixel(x2, my, mr, pixels, stride); 178 } 179 } 180 181 if (my != y1 || my != y2){ 182 if (x1 != mx || my != y2){ 183 mb = average(bl, br); 184 mb = displace(mb, amount); 185 putPixel(mx, y2, mb, pixels, stride); 186 } 187 188 if (y1 != y2){ 189 mt = average(tl, tr); 190 mt = displace(mt, amount); 191 putPixel(mx, y1, mt, pixels, stride); 192 } 193 } 194 195 if (y1 != y2 || x1 != x2) { 196 mm = average(tl, br); 197 t = average(bl, tr); 198 mm = average(mm, t); 199 mm = displace(mm, amount); 200 putPixel(mx, my, mm, pixels, stride); 201 } 202 203 if (x2-x1 < 3 && y2-y1 < 3) 204 return false; 205 return true; 206 } 207 208 mx = (x1 + x2) / 2; 209 my = (y1 + y2) / 2; 210 211 doPixel(x1, y1, mx, my, pixels, stride, depth-1, scale+1); 212 doPixel(x1, my, mx ,y2, pixels, stride, depth-1, scale+1); 213 doPixel(mx, y1, x2 , my, pixels, stride, depth-1, scale+1); 214 return doPixel(mx, my, x2, y2, pixels, stride, depth-1, scale+1); 215 } 216 217 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 218 int[] outPixels = new int[width * height]; 219 220 randomGenerator.setSeed(seed); 221 222 int w1 = width-1; 223 int h1 = height-1; 224 putPixel(0, 0, randomRGB(inPixels, 0, 0), outPixels, width); 225 putPixel(w1, 0, randomRGB(inPixels, w1, 0), outPixels, width); 226 putPixel(0, h1, randomRGB(inPixels, 0, h1), outPixels, width); 227 putPixel(w1, h1, randomRGB(inPixels, w1, h1), outPixels, width); 228 putPixel(w1/2, h1/2, randomRGB(inPixels, w1/2, h1/2), outPixels, width); 229 putPixel(0, h1/2, randomRGB(inPixels, 0, h1/2), outPixels, width); 230 putPixel(w1, h1/2, randomRGB(inPixels, w1, h1/2), outPixels, width); 231 putPixel(w1/2, 0, randomRGB(inPixels, w1/2, 0), outPixels, width); 232 putPixel(w1/2, h1, randomRGB(inPixels, w1/2, h1), outPixels, width); 233 234 int depth = 1; 235 while (doPixel(0, 0, width-1, height-1, outPixels, width, depth, 0)) 236 depth++; 237 238 if (useColormap && colormap != null) { 239 int index = 0; 240 for (int y = 0; y < height; y++) { 241 for (int x = 0; x < width; x++) { 242 outPixels[index] = colormap.getColor((outPixels[index] & 0xff)/255.0f); 243 index++; 244 } 245 } 246 } 247 return outPixels; 248 } 249 250 public String toString() { 251 return "Texture/Plasma..."; 252 } 253 254 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 255 Object o; 256 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 257 if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence")); 258 if((o=parameters.removeEL(KeyImpl.init("Scaling")))!=null)setScaling(ImageFilterUtil.toFloatValue(o,"Scaling")); 259 if((o=parameters.removeEL(KeyImpl.init("UseColormap")))!=null)setUseColormap(ImageFilterUtil.toBooleanValue(o,"UseColormap")); 260 if((o=parameters.removeEL(KeyImpl.init("UseImageColors")))!=null)setUseImageColors(ImageFilterUtil.toBooleanValue(o,"UseImageColors")); 261 if((o=parameters.removeEL(KeyImpl.init("Seed")))!=null)setSeed(ImageFilterUtil.toIntValue(o,"Seed")); 262 263 // check for arguments not supported 264 if(parameters.size()>0) { 265 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, Turbulence, Scaling, UseColormap, UseImageColors, Seed]"); 266 } 267 268 return filter(src, dst); 269 } 270 }