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 import java.util.Random; 019 020 import railo.runtime.engine.ThreadLocalPageContext; 021 import railo.runtime.exp.FunctionException; 022 import railo.runtime.exp.PageException; 023 import railo.runtime.img.ImageUtil; 024 import railo.runtime.type.KeyImpl; 025 import railo.runtime.type.List; 026 import railo.runtime.type.Struct; 027 028 public class SparkleFilter extends PointFilter implements DynFiltering { 029 030 private int rays = 50; 031 private int radius = 25; 032 private int amount = 50; 033 private int color = 0xffffffff; 034 private int randomness = 25; 035 private int width, height; 036 private int centreX, centreY; 037 private long seed = 371; 038 private float[] rayLengths; 039 private Random randomNumbers = new Random(); 040 041 public SparkleFilter() { 042 } 043 044 public void setColor(int color) { 045 this.color = color; 046 } 047 048 public int getColor() { 049 return color; 050 } 051 052 public void setRandomness(int randomness) { 053 this.randomness = randomness; 054 } 055 056 public int getRandomness() { 057 return randomness; 058 } 059 060 /** 061 * Set the amount of sparkle. 062 * @param amount the amount 063 * @min-value 0 064 * @max-value 1 065 * @see #getAmount 066 */ 067 public void setAmount(int amount) { 068 this.amount = amount; 069 } 070 071 /** 072 * Get the amount of sparkle. 073 * @return the amount 074 * @see #setAmount 075 */ 076 public int getAmount() { 077 return amount; 078 } 079 080 public void setRays(int rays) { 081 this.rays = rays; 082 } 083 084 public int getRays() { 085 return rays; 086 } 087 088 /** 089 * Set the radius of the effect. 090 * @param radius the radius 091 * @min-value 0 092 * @see #getRadius 093 */ 094 public void setRadius(int radius) { 095 this.radius = radius; 096 } 097 098 /** 099 * Get the radius of the effect. 100 * @return the radius 101 * @see #setRadius 102 */ 103 public int getRadius() { 104 return radius; 105 } 106 107 public void setDimensions(int width, int height) { 108 this.width = width; 109 this.height = height; 110 centreX = width/2; 111 centreY = height/2; 112 super.setDimensions(width, height); 113 randomNumbers.setSeed(seed); 114 rayLengths = new float[rays]; 115 for (int i = 0; i < rays; i++) 116 rayLengths[i] = radius + randomness / 100.0f * radius * (float)randomNumbers.nextGaussian(); 117 } 118 119 public int filterRGB(int x, int y, int rgb) { 120 float dx = x-centreX; 121 float dy = y-centreY; 122 float distance = dx*dx+dy*dy; 123 float angle = (float)Math.atan2(dy, dx); 124 float d = (angle+ImageMath.PI) / (ImageMath.TWO_PI) * rays; 125 int i = (int)d; 126 float f = d - i; 127 128 if (radius != 0) { 129 float length = ImageMath.lerp(f, rayLengths[i % rays], rayLengths[(i+1) % rays]); 130 float g = length*length / (distance+0.0001f); 131 g = (float)Math.pow(g, (100-amount) / 50.0); 132 f -= 0.5f; 133 // f *= amount/50.0f; 134 f = 1 - f*f; 135 f *= g; 136 } 137 f = ImageMath.clamp(f, 0, 1); 138 return ImageMath.mixColors(f, rgb, color); 139 } 140 141 public String toString() { 142 return "Stylize/Sparkle..."; 143 } 144 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 145 Object o; 146 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toIntValue(o,"Radius")); 147 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toIntValue(o,"Amount")); 148 if((o=parameters.removeEL(KeyImpl.init("Randomness")))!=null)setRandomness(ImageFilterUtil.toIntValue(o,"Randomness")); 149 if((o=parameters.removeEL(KeyImpl.init("Rays")))!=null)setRays(ImageFilterUtil.toIntValue(o,"Rays")); 150 if((o=parameters.removeEL(KeyImpl.init("Color")))!=null)setColor(ImageFilterUtil.toColorRGB(o,"Color")); 151 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 152 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 153 setDimensions(dim[0],dim[1]); 154 } 155 156 // check for arguments not supported 157 if(parameters.size()>0) { 158 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Radius, Amount, Randomness, Rays, Color, Dimensions]"); 159 } 160 161 return filter(src, dst); 162 } 163 }