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.math.Noise; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.Struct; 025 import railo.runtime.type.util.CollectionUtil; 026 027 /** 028 * This filter applies a marbling effect to an image, displacing pixels by random amounts. 029 */ 030 public class MarbleFilter extends TransformFilter implements DynFiltering { 031 032 private float[] sinTable, cosTable; 033 private float xScale = 4; 034 private float yScale = 4; 035 private float amount = 1; 036 private float turbulence = 1; 037 038 public MarbleFilter() { 039 super(ConvolveFilter.CLAMP_EDGES); 040 } 041 042 /** 043 * Set the X scale of the effect. 044 * @param xScale the scale. 045 * @see #getXScale 046 */ 047 public void setXScale(float xScale) { 048 this.xScale = xScale; 049 } 050 051 /** 052 * Get the X scale of the effect. 053 * @return the scale. 054 * @see #setXScale 055 */ 056 public float getXScale() { 057 return xScale; 058 } 059 060 /** 061 * Set the Y scale of the effect. 062 * @param yScale the scale. 063 * @see #getYScale 064 */ 065 public void setYScale(float yScale) { 066 this.yScale = yScale; 067 } 068 069 /** 070 * Get the Y scale of the effect. 071 * @return the scale. 072 * @see #setYScale 073 */ 074 public float getYScale() { 075 return yScale; 076 } 077 078 /** 079 * Set the amount of effect. 080 * @param amount the amount 081 * @min-value 0 082 * @max-value 1 083 * @see #getAmount 084 */ 085 public void setAmount(float amount) { 086 this.amount = amount; 087 } 088 089 /** 090 * Get the amount of effect. 091 * @return the amount 092 * @see #setAmount 093 */ 094 public float getAmount() { 095 return amount; 096 } 097 098 /** 099 * Specifies the turbulence of the effect. 100 * @param turbulence the turbulence of the effect. 101 * @min-value 0 102 * @max-value 1 103 * @see #getTurbulence 104 */ 105 public void setTurbulence(float turbulence) { 106 this.turbulence = turbulence; 107 } 108 109 /** 110 * Returns the turbulence of the effect. 111 * @return the turbulence of the effect. 112 * @see #setTurbulence 113 */ 114 public float getTurbulence() { 115 return turbulence; 116 } 117 118 private void initialize() { 119 sinTable = new float[256]; 120 cosTable = new float[256]; 121 for (int i = 0; i < 256; i++) { 122 float angle = ImageMath.TWO_PI*i/256f*turbulence; 123 sinTable[i] = (float)(-yScale*Math.sin(angle)); 124 cosTable[i] = (float)(yScale*Math.cos(angle)); 125 } 126 } 127 128 private int displacementMap(int x, int y) { 129 return PixelUtils.clamp((int)(127 * (1+Noise.noise2(x / xScale, y / xScale)))); 130 } 131 132 protected void transformInverse(int x, int y, float[] out) { 133 int displacement = displacementMap(x, y); 134 out[0] = x + sinTable[displacement]; 135 out[1] = y + cosTable[displacement]; 136 } 137 138 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 139 initialize(); 140 return super.filter( src, dst ); 141 } 142 143 public String toString() { 144 return "Distort/Marble..."; 145 } 146 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 147 Object o; 148 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 149 if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence")); 150 if((o=parameters.removeEL(KeyImpl.init("XScale")))!=null)setXScale(ImageFilterUtil.toFloatValue(o,"XScale")); 151 if((o=parameters.removeEL(KeyImpl.init("YScale")))!=null)setYScale(ImageFilterUtil.toFloatValue(o,"YScale")); 152 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 153 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 154 155 // check for arguments not supported 156 if(parameters.size()>0) { 157 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 [Amount, Turbulence, XScale, YScale, EdgeAction, Interpolation]"); 158 } 159 160 return filter(src, dst); 161 } 162 }