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.image.BufferedImage; 036import java.util.Random; 037 038import lucee.runtime.engine.ThreadLocalPageContext; 039import lucee.runtime.exp.FunctionException; 040import lucee.runtime.exp.PageException; 041import lucee.runtime.img.ImageUtil; 042import lucee.runtime.type.KeyImpl; 043import lucee.runtime.type.Struct; 044import lucee.runtime.type.util.CollectionUtil; 045 046/** 047 * A filter which adds random noise into an image. 048 */ 049public class NoiseFilter extends PointFilter implements DynFiltering { 050 051 /** 052 * Gaussian distribution for the noise. 053 */ 054 public final static int GAUSSIAN = 0; 055 056 /** 057 * Uniform distribution for the noise. 058 */ 059 public final static int UNIFORM = 1; 060 061 private int amount = 25; 062 private int distribution = UNIFORM; 063 private boolean monochrome = false; 064 private float density = 1; 065 private Random randomNumbers = new Random(); 066 067 public NoiseFilter() { 068 } 069 070 /** 071 * Set the amount of effect. 072 * @param amount the amount 073 * @min-value 0 074 * @max-value 1 075 * @see #getAmount 076 */ 077 public void setAmount(int amount) { 078 this.amount = amount; 079 } 080 081 /** 082 * Get the amount of noise. 083 * @return the amount 084 * @see #setAmount 085 */ 086 public int getAmount() { 087 return amount; 088 } 089 090 /** 091 * Set the distribution of the noise. 092 * @param distribution the distribution 093 * @see #getDistribution 094 */ 095 public void setDistribution( int distribution ) { 096 this.distribution = distribution; 097 } 098 099 /** 100 * Get the distribution of the noise. 101 * @return the distribution 102 * @see #setDistribution 103 */ 104 public int getDistribution() { 105 return distribution; 106 } 107 108 /** 109 * Set whether to use monochrome noise. 110 * @param monochrome true for monochrome noise 111 * @see #getMonochrome 112 */ 113 public void setMonochrome(boolean monochrome) { 114 this.monochrome = monochrome; 115 } 116 117 /** 118 * Get whether to use monochrome noise. 119 * @return true for monochrome noise 120 * @see #setMonochrome 121 */ 122 public boolean getMonochrome() { 123 return monochrome; 124 } 125 126 /** 127 * Set the density of the noise. 128 * @param density the density 129 * @see #getDensity 130 */ 131 public void setDensity( float density ) { 132 this.density = density; 133 } 134 135 /** 136 * Get the density of the noise. 137 * @return the density 138 * @see #setDensity 139 */ 140 public float getDensity() { 141 return density; 142 } 143 144 private int random(int x) { 145 x += (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount); 146 if (x < 0) 147 x = 0; 148 else if (x > 0xff) 149 x = 0xff; 150 return x; 151 } 152 153 public int filterRGB(int x, int y, int rgb) { 154 if ( randomNumbers.nextFloat() <= density ) { 155 int a = rgb & 0xff000000; 156 int r = (rgb >> 16) & 0xff; 157 int g = (rgb >> 8) & 0xff; 158 int b = rgb & 0xff; 159 if (monochrome) { 160 int n = (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount); 161 r = PixelUtils.clamp(r+n); 162 g = PixelUtils.clamp(g+n); 163 b = PixelUtils.clamp(b+n); 164 } else { 165 r = random(r); 166 g = random(g); 167 b = random(b); 168 } 169 return a | (r << 16) | (g << 8) | b; 170 } 171 return rgb; 172 } 173 174 public String toString() { 175 return "Stylize/Add Noise..."; 176 } 177 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 178 Object o; 179 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toIntValue(o,"Amount")); 180 if((o=parameters.removeEL(KeyImpl.init("Monochrome")))!=null)setMonochrome(ImageFilterUtil.toBooleanValue(o,"Monochrome")); 181 if((o=parameters.removeEL(KeyImpl.init("Density")))!=null)setDensity(ImageFilterUtil.toFloatValue(o,"Density")); 182 if((o=parameters.removeEL(KeyImpl.init("Distribution")))!=null)setDistribution(ImageFilterUtil.toIntValue(o,"Distribution")); 183 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 184 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 185 setDimensions(dim[0],dim[1]); 186 } 187 188 // check for arguments not supported 189 if(parameters.size()>0) { 190 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, Monochrome, Density, Distribution, Dimensions]"); 191 } 192 193 return filter(src, dst); 194 } 195}