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.Rectangle; 036import java.awt.image.BufferedImage; 037import java.util.Date; 038import java.util.Random; 039 040import lucee.runtime.engine.ThreadLocalPageContext; 041import lucee.runtime.exp.FunctionException; 042import lucee.runtime.exp.PageException; 043import lucee.runtime.img.ImageUtil; 044import lucee.runtime.type.KeyImpl; 045import lucee.runtime.type.Struct; 046import lucee.runtime.type.util.CollectionUtil; 047 048public class QuiltFilter extends WholeImageFilter implements DynFiltering { 049 050 private Random randomGenerator; 051 private long seed = 567; 052 private int iterations = 25000; 053 private float a = -0.59f; 054 private float b = 0.2f; 055 private float c = 0.1f; 056 private float d = 0; 057 private int k = 0; 058 private Colormap colormap = new LinearColormap(); 059 060 public QuiltFilter() { 061 randomGenerator = new Random(); 062 } 063 064 public void randomize() { 065 seed = new Date().getTime(); 066 randomGenerator.setSeed(seed); 067 a = randomGenerator.nextFloat(); 068 b = randomGenerator.nextFloat(); 069 c = randomGenerator.nextFloat(); 070 d = randomGenerator.nextFloat(); 071 k = randomGenerator.nextInt() % 20 - 10; 072 } 073 074 /** 075 * Set the number of iterations the effect is performed. 076 * @param iterations the number of iterations 077 * @min-value 0 078 * @see #getIterations 079 */ 080 public void setIterations(int iterations) { 081 this.iterations = iterations; 082 } 083 084 /** 085 * Get the number of iterations the effect is performed. 086 * @return the number of iterations 087 * @see #setIterations 088 */ 089 public int getIterations() { 090 return iterations; 091 } 092 093 public void setA(float a) { 094 this.a = a; 095 } 096 097 public float getA() { 098 return a; 099 } 100 101 public void setB(float b) { 102 this.b = b; 103 } 104 105 public float getB() { 106 return b; 107 } 108 109 public void setC(float c) { 110 this.c = c; 111 } 112 113 public float getC() { 114 return c; 115 } 116 117 public void setD(float d) { 118 this.d = d; 119 } 120 121 public float getD() { 122 return d; 123 } 124 125 public void setK(int k) { 126 this.k = k; 127 } 128 129 public int getK() { 130 return k; 131 } 132 133 /** 134 * Set the colormap to be used for the filter. 135 * @param colormap the colormap 136 * @see #getColormap 137 */ 138 public void setColormap(Colormap colormap) { 139 this.colormap = colormap; 140 } 141 142 /** 143 * Get the colormap to be used for the filter. 144 * @return the colormap 145 * @see #setColormap 146 */ 147 public Colormap getColormap() { 148 return colormap; 149 } 150 151 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 152 int[] outPixels = new int[width * height]; 153 154 //int i = 0; 155 int max = 0; 156 157 float x = 0.1f; 158 float y = 0.3f; 159 160 for (int n = 0; n < 20; n++) { 161 float mx = ImageMath.PI*x; 162 float my = ImageMath.PI*y; 163 float smx2 = (float)Math.sin(2*mx); 164 float smy2 = (float)Math.sin(2*my); 165 float x1 = (float)(a*smx2 + b*smx2*Math.cos(2*my) + 166 c*Math.sin(4*mx) + d*Math.sin(6*mx)*Math.cos(4*my) + k*x); 167 x1 = x1 >= 0 ? x1 - (int)x1 : x1 - (int)x1 + 1; 168 169 float y1 = (float)(a*smy2 + b*smy2*Math.cos(2*mx) + 170 c*Math.sin(4*my) + d*Math.sin(6*my)*Math.cos(4*mx) + k*y); 171 y1 = y1 >= 0 ? y1 - (int)y1 : y1 - (int)y1 + 1; 172 x = x1; 173 y = y1; 174 } 175 176 for (int n = 0; n < iterations; n++) { 177 float mx = ImageMath.PI*x; 178 float my = ImageMath.PI*y; 179 float x1 = (float)(a*Math.sin(2*mx) + b*Math.sin(2*mx)*Math.cos(2*my) + 180 c*Math.sin(4*mx) + d*Math.sin(6*mx)*Math.cos(4*my) + k*x); 181 x1 = x1 >= 0 ? x1 - (int)x1 : x1 - (int)x1 + 1; 182 183 float y1 = (float)(a*Math.sin(2*my) + b*Math.sin(2*my)*Math.cos(2*mx) + 184 c*Math.sin(4*my) + d*Math.sin(6*my)*Math.cos(4*mx) + k*y); 185 y1 = y1 >= 0 ? y1 - (int)y1 : y1 - (int)y1 + 1; 186 x = x1; 187 y = y1; 188 int ix = (int)(width*x); 189 int iy = (int)(height*y); 190 if (ix >= 0 && ix < width && iy >= 0 && iy < height) { 191 int t = outPixels[width*iy+ix]++; 192 if (t > max) 193 max = t; 194 } 195 } 196 197 if (colormap != null) { 198 int index = 0; 199 for (y = 0; y < height; y++) { 200 for (x = 0; x < width; x++) { 201 outPixels[index] = colormap.getColor(outPixels[index] / (float)max); 202 index++; 203 } 204 } 205 } 206 return outPixels; 207 } 208 209 public String toString() { 210 return "Texture/Chaotic Quilt..."; 211 } 212 213 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 214 Object o; 215 if((o=parameters.removeEL(KeyImpl.init("Iterations")))!=null)setIterations(ImageFilterUtil.toIntValue(o,"Iterations")); 216 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 217 if((o=parameters.removeEL(KeyImpl.init("A")))!=null)setA(ImageFilterUtil.toFloatValue(o,"A")); 218 if((o=parameters.removeEL(KeyImpl.init("B")))!=null)setB(ImageFilterUtil.toFloatValue(o,"B")); 219 if((o=parameters.removeEL(KeyImpl.init("C")))!=null)setC(ImageFilterUtil.toFloatValue(o,"C")); 220 if((o=parameters.removeEL(KeyImpl.init("D")))!=null)setD(ImageFilterUtil.toFloatValue(o,"D")); 221 if((o=parameters.removeEL(KeyImpl.init("K")))!=null)setK(ImageFilterUtil.toIntValue(o,"K")); 222 223 // check for arguments not supported 224 if(parameters.size()>0) { 225 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 [Iterations, Colormap, A, B, C, D, K]"); 226 } 227 228 return filter(src, dst); 229 } 230}