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.BasicStroke; 036import java.awt.Color; 037import java.awt.Graphics2D; 038import java.awt.RenderingHints; 039import java.awt.geom.Line2D; 040import java.awt.image.BufferedImage; 041import java.util.ArrayList; 042import java.util.Random; 043 044import lucee.runtime.engine.ThreadLocalPageContext; 045import lucee.runtime.exp.FunctionException; 046import lucee.runtime.exp.PageException; 047import lucee.runtime.type.KeyImpl; 048import lucee.runtime.type.Struct; 049import lucee.runtime.type.util.CollectionUtil; 050 051public class ScratchFilter extends AbstractBufferedImageOp implements DynFiltering { 052 private float density = 0.1f; 053 private float angle; 054 private float angleVariation = 1.0f; 055 private float width = 0.5f; 056 private float length = 0.5f; 057 private int color = 0xffffffff; 058 private int seed = 0; 059 060 public ScratchFilter() { 061 } 062 063 public void setAngle( float angle ) { 064 this.angle = angle; 065 } 066 067 public float getAngle() { 068 return angle; 069 } 070 071 public void setAngleVariation( float angleVariation ) { 072 this.angleVariation = angleVariation; 073 } 074 075 public float getAngleVariation() { 076 return angleVariation; 077 } 078 079 public void setDensity( float density ) { 080 this.density = density; 081 } 082 083 public float getDensity() { 084 return density; 085 } 086 087 public void setLength( float length ) { 088 this.length = length; 089 } 090 091 public float getLength() { 092 return length; 093 } 094 095 public void setWidth( float width ) { 096 this.width = width; 097 } 098 099 public float getWidth() { 100 return width; 101 } 102 103 public void setColor( int color ) { 104 this.color = color; 105 } 106 107 public int getColor() { 108 return color; 109 } 110 111 public void setSeed( int seed ) { 112 this.seed = seed; 113 } 114 115 public int getSeed() { 116 return seed; 117 } 118 119 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 120 if ( dst == null ) 121 dst = createCompatibleDestImage( src, null ); 122 123 int width = src.getWidth(); 124 int height = src.getHeight(); 125 int numScratches = (int)(density * width * height / 100); 126ArrayList lines = new ArrayList(); 127{ 128 float l = length * width; 129 Random random = new Random( seed ); 130 Graphics2D g = dst.createGraphics(); 131 g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); 132 g.setColor( new Color( color ) ); 133 g.setStroke( new BasicStroke( this.width ) ); 134 for ( int i = 0; i < numScratches; i++ ) { 135 float x = width * random.nextFloat(); 136 float y = height * random.nextFloat(); 137 float a = angle + ImageMath.TWO_PI * (angleVariation * (random.nextFloat() - 0.5f)); 138 float s = (float)Math.sin( a ) * l; 139 float c = (float)Math.cos( a ) * l; 140 float x1 = x-c; 141 float y1 = y-s; 142 float x2 = x+c; 143 float y2 = y+s; 144 g.drawLine( (int)x1, (int)y1, (int)x2, (int)y2 ); 145lines.add( new Line2D.Float( x1, y1, x2, y2 ) ); 146 } 147 g.dispose(); 148} 149 150if ( false ) { 151// int[] inPixels = getRGB( src, 0, 0, width, height, null ); 152 int[] inPixels = new int[width*height]; 153 int index = 0; 154 for ( int y = 0; y < height; y++ ) { 155 for ( int x = 0; x < width; x++ ) { 156 float sx = x, sy = y; 157 for ( int i = 0; i < numScratches; i++ ) { 158 Line2D.Float l = (Line2D.Float)lines.get( i ); 159 float dot = (l.x2-l.x1)*(sx-l.x1) + (l.y2-l.y1)*(sy-l.y1); 160 if ( dot > 0 ) 161 inPixels[index] |= (1 << i ); 162 } 163 index++; 164 } 165 } 166 167 Colormap colormap = new LinearColormap(); 168 index = 0; 169 for ( int y = 0; y < height; y++ ) { 170 for ( int x = 0; x < width; x++ ) { 171 float f = (float)(inPixels[index] & 0x7fffffff) / 0x7fffffff; 172 inPixels[index] = colormap.getColor( f ); 173 index++; 174 } 175 } 176 setRGB( dst, 0, 0, width, height, inPixels ); 177} 178 return dst; 179 } 180 181 public String toString() { 182 return "Render/Scratches..."; 183 } 184 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=src;//ImageUtil.createBufferedImage(src); 185 Object o; 186 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 187 if((o=parameters.removeEL(KeyImpl.init("Density")))!=null)setDensity(ImageFilterUtil.toFloatValue(o,"Density")); 188 if((o=parameters.removeEL(KeyImpl.init("AngleVariation")))!=null)setAngleVariation(ImageFilterUtil.toFloatValue(o,"AngleVariation")); 189 if((o=parameters.removeEL(KeyImpl.init("Length")))!=null)setLength(ImageFilterUtil.toFloatValue(o,"Length")); 190 if((o=parameters.removeEL(KeyImpl.init("Seed")))!=null)setSeed(ImageFilterUtil.toIntValue(o,"Seed")); 191 if((o=parameters.removeEL(KeyImpl.init("Color")))!=null)setColor(ImageFilterUtil.toColorRGB(o,"Color")); 192 if((o=parameters.removeEL(KeyImpl.init("Width")))!=null)setWidth(ImageFilterUtil.toFloatValue(o,"Width")); 193 194 // check for arguments not supported 195 if(parameters.size()>0) { 196 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 [Angle, Density, AngleVariation, Length, Seed, Color, Width]"); 197 } 198 199 return filter(src, dst); 200 } 201}