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