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.AlphaComposite; 018 import java.awt.Graphics2D; 019 import java.awt.image.BufferedImage; 020 021 import railo.runtime.engine.ThreadLocalPageContext; 022 import railo.runtime.exp.FunctionException; 023 import railo.runtime.exp.PageException; 024 import railo.runtime.img.ImageUtil; 025 import railo.runtime.img.composite.MiscComposite; 026 import railo.runtime.type.KeyImpl; 027 import railo.runtime.type.Struct; 028 import railo.runtime.type.util.CollectionUtil; 029 030 /** 031 * A filter which produces the effect of light rays shining out of an image. 032 */ 033 public class RaysFilter extends MotionBlurOp implements DynFiltering { 034 035 private float opacity = 1.0f; 036 private float threshold = 0.0f; 037 private float strength = 0.5f; 038 private boolean raysOnly = false; 039 private Colormap colormap=new GrayscaleColormap(); 040 041 public RaysFilter() { 042 } 043 044 /** 045 * Set the opacity of the rays. 046 * @param opacity the opacity. 047 * @see #getOpacity 048 */ 049 public void setOpacity(float opacity) { 050 this.opacity = opacity; 051 } 052 053 /** 054 * Get the opacity of the rays. 055 * @return the opacity. 056 * @see #setOpacity 057 */ 058 public float getOpacity() { 059 return opacity; 060 } 061 062 /** 063 * Set the threshold value. 064 * @param threshold the threshold value 065 * @see #getThreshold 066 */ 067 public void setThreshold( float threshold ) { 068 this.threshold = threshold; 069 } 070 071 /** 072 * Get the threshold value. 073 * @return the threshold value 074 * @see #setThreshold 075 */ 076 public float getThreshold() { 077 return threshold; 078 } 079 080 /** 081 * Set the strength of the rays. 082 * @param strength the strength. 083 * @see #getStrength 084 */ 085 public void setStrength( float strength ) { 086 this.strength = strength; 087 } 088 089 /** 090 * Get the strength of the rays. 091 * @return the strength. 092 * @see #setStrength 093 */ 094 public float getStrength() { 095 return strength; 096 } 097 098 /** 099 * Set whether to render only the rays. 100 * @param raysOnly true to render rays only. 101 * @see #getRaysOnly 102 */ 103 public void setRaysOnly(boolean raysOnly) { 104 this.raysOnly = raysOnly; 105 } 106 107 /** 108 * Get whether to render only the rays. 109 * @return true to render rays only. 110 * @see #setRaysOnly 111 */ 112 public boolean getRaysOnly() { 113 return raysOnly; 114 } 115 116 /** 117 * Set the colormap to be used for the filter. 118 * @param colormap the colormap 119 * @see #getColormap 120 */ 121 public void setColormap(Colormap colormap) { 122 this.colormap = colormap; 123 } 124 125 /** 126 * Get the colormap to be used for the filter. 127 * @return the colormap 128 * @see #setColormap 129 */ 130 public Colormap getColormap() { 131 return colormap; 132 } 133 134 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 135 int width = src.getWidth(); 136 int height = src.getHeight(); 137 int[] pixels = new int[width]; 138 int[] srcPixels = new int[width]; 139 140 BufferedImage rays = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 141 142 int threshold3 = (int)(threshold*3*255); 143 for ( int y = 0; y < height; y++ ) { 144 getRGB( src, 0, y, width, 1, pixels ); 145 for ( int x = 0; x < width; x++ ) { 146 int rgb = pixels[x]; 147 int a = rgb & 0xff000000; 148 int r = (rgb >> 16) & 0xff; 149 int g = (rgb >> 8) & 0xff; 150 int b = rgb & 0xff; 151 int l = r + g + b; 152 if (l < threshold3) 153 pixels[x] = 0xff000000; 154 else { 155 l /= 3; 156 pixels[x] = a | (l << 16) | (l << 8) | l; 157 } 158 } 159 setRGB( rays, 0, y, width, 1, pixels ); 160 } 161 162 rays = super.filter( rays, null ); 163 164 for ( int y = 0; y < height; y++ ) { 165 getRGB( rays, 0, y, width, 1, pixels ); 166 getRGB( src, 0, y, width, 1, srcPixels ); 167 for ( int x = 0; x < width; x++ ) { 168 int rgb = pixels[x]; 169 int a = rgb & 0xff000000; 170 int r = (rgb >> 16) & 0xff; 171 int g = (rgb >> 8) & 0xff; 172 int b = rgb & 0xff; 173 174 if ( colormap != null ) { 175 int l = r + g + b; 176 rgb = colormap.getColor( l * strength * (1/3f) ); 177 } else { 178 r = PixelUtils.clamp((int)(r * strength)); 179 g = PixelUtils.clamp((int)(g * strength)); 180 b = PixelUtils.clamp((int)(b * strength)); 181 rgb = a | (r << 16) | (g << 8) | b; 182 } 183 184 pixels[x] = rgb; 185 } 186 setRGB( rays, 0, y, width, 1, pixels ); 187 } 188 189 if ( dst == null ) 190 dst = createCompatibleDestImage( src, null ); 191 192 Graphics2D g = dst.createGraphics(); 193 if ( !raysOnly ) { 194 g.setComposite( AlphaComposite.SrcOver ); 195 g.drawRenderedImage( src, null ); 196 } 197 g.setComposite( MiscComposite.getInstance( MiscComposite.ADD, opacity ) ); 198 g.drawRenderedImage( rays, null ); 199 g.dispose(); 200 201 return dst; 202 } 203 204 public String toString() { 205 return "Stylize/Rays..."; 206 } 207 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 208 Object o; 209 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 210 if((o=parameters.removeEL(KeyImpl.init("Strength")))!=null)setStrength(ImageFilterUtil.toFloatValue(o,"Strength")); 211 if((o=parameters.removeEL(KeyImpl.init("Opacity")))!=null)setOpacity(ImageFilterUtil.toFloatValue(o,"Opacity")); 212 if((o=parameters.removeEL(KeyImpl.init("RaysOnly")))!=null)setRaysOnly(ImageFilterUtil.toBooleanValue(o,"RaysOnly")); 213 if((o=parameters.removeEL(KeyImpl.init("Threshold")))!=null)setThreshold(ImageFilterUtil.toFloatValue(o,"Threshold")); 214 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 215 if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX")); 216 if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY")); 217 //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre")); 218 if((o=parameters.removeEL(KeyImpl.init("Distance")))!=null)setDistance(ImageFilterUtil.toFloatValue(o,"Distance")); 219 if((o=parameters.removeEL(KeyImpl.init("Rotation")))!=null)setRotation(ImageFilterUtil.toFloatValue(o,"Rotation")); 220 if((o=parameters.removeEL(KeyImpl.init("Zoom")))!=null)setZoom(ImageFilterUtil.toFloatValue(o,"Zoom")); 221 222 // check for arguments not supported 223 if(parameters.size()>0) { 224 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 [Colormap, Strength, Opacity, RaysOnly, Threshold, Angle, CentreX, CentreY, Centre, Distance, Rotation, Zoom]"); 225 } 226 227 return filter(src, dst); 228 } 229 }