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.ImageUtil; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.Struct; 025 import railo.runtime.type.util.CollectionUtil; 026 027 /** 028 * A filter which can be used to produce wipes by transferring the luma of a mask image into the alpha channel of the source. 029 */ 030 public class HalftoneFilter extends AbstractBufferedImageOp implements DynFiltering { 031 032 private float density = 0; 033 private float softness = 0; 034 private boolean invert; 035 private BufferedImage mask; 036 037 public HalftoneFilter() { 038 } 039 040 /** 041 * Set the density of the image in the range 0..1. 042 * *arg density The density 043 */ 044 public void setDensity( float density ) { 045 this.density = density; 046 } 047 048 public float getDensity() { 049 return density; 050 } 051 052 /** 053 * Set the softness of the effect in the range 0..1. 054 * @param softness the softness 055 * @min-value 0 056 * @max-value 1 057 * @see #getSoftness 058 */ 059 public void setSoftness( float softness ) { 060 this.softness = softness; 061 } 062 063 /** 064 * Get the softness of the effect. 065 * @return the softness 066 * @see #setSoftness 067 */ 068 public float getSoftness() { 069 return softness; 070 } 071 072 public void setMask( BufferedImage mask ) { 073 this.mask = mask; 074 } 075 076 public BufferedImage getMask() { 077 return mask; 078 } 079 080 public void setInvert( boolean invert ) { 081 this.invert = invert; 082 } 083 084 public boolean getInvert() { 085 return invert; 086 } 087 088 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 089 int width = src.getWidth(); 090 int height = src.getHeight(); 091 092 if ( dst == null ) 093 dst = createCompatibleDestImage( src, null ); 094 if ( mask == null ) 095 return dst; 096 097 int maskWidth = mask.getWidth(); 098 int maskHeight = mask.getHeight(); 099 100 //float d = density * (1+softness); 101 //float lower = 255 * (d-softness); 102 //float upper = 255 * d; 103 float s = 255*softness; 104 105 int[] inPixels = new int[width]; 106 int[] maskPixels = new int[maskWidth]; 107 108 for ( int y = 0; y < height; y++ ) { 109 getRGB( src, 0, y, width, 1, inPixels ); 110 getRGB( mask, 0, y % maskHeight, maskWidth, 1, maskPixels ); 111 112 for ( int x = 0; x < width; x++ ) { 113 int maskRGB = maskPixels[x % maskWidth]; 114 int inRGB = inPixels[x]; 115 int v = PixelUtils.brightness( maskRGB ); 116 int iv = PixelUtils.brightness( inRGB ); 117 float f = ImageMath.smoothStep( iv-s, iv+s, v ); 118 int a = (int)(255 * f); 119 120 if ( invert ) 121 a = 255-a; 122 // inPixels[x] = (a << 24) | (inRGB & 0x00ffffff); 123 inPixels[x] = (inRGB & 0xff000000) | (a << 16) | (a << 8) | a; 124 } 125 126 setRGB( dst, 0, y, width, 1, inPixels ); 127 } 128 129 return dst; 130 } 131 132 public String toString() { 133 return "Stylize/Halftone..."; 134 } 135 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 136 Object o; 137 if((o=parameters.removeEL(KeyImpl.init("Density")))!=null)setDensity(ImageFilterUtil.toFloatValue(o,"Density")); 138 if((o=parameters.removeEL(KeyImpl.init("Softness")))!=null)setSoftness(ImageFilterUtil.toFloatValue(o,"Softness")); 139 if((o=parameters.removeEL(KeyImpl.init("Invert")))!=null)setInvert(ImageFilterUtil.toBooleanValue(o,"Invert")); 140 if((o=parameters.removeEL(KeyImpl.init("Mask")))!=null)setMask(ImageFilterUtil.toBufferedImage(o,"Mask")); 141 142 // check for arguments not supported 143 if(parameters.size()>0) { 144 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 [Density, Softness, Invert, Mask]"); 145 } 146 147 return filter(src, dst); 148 } 149 }