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.Color; 018 import java.awt.image.BufferedImage; 019 import java.awt.image.WritableRaster; 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.type.KeyImpl; 026 import railo.runtime.type.List; 027 import railo.runtime.type.Struct; 028 029 /** 030 * An experimental filter which can be used for keying against a clean shot. Given a source image, a clean image and a destination image, 031 * the filter replaces all pixels in the source which nearly equal the equivalent clean pixel by destination pixels. 032 */ 033 public class KeyFilter extends AbstractBufferedImageOp implements DynFiltering { 034 035 private float hTolerance = 0; 036 private float sTolerance = 0; 037 private float bTolerance = 0; 038 private BufferedImage destination; 039 private BufferedImage cleanImage; 040 041 public KeyFilter() { 042 } 043 044 /** 045 * Set the hue tolerance of the image in the range 0..1. 046 * @param hTolerance the tolerance 047 * @see #getHTolerance 048 */ 049 public void setHTolerance( float hTolerance ) { 050 this.hTolerance = hTolerance; 051 } 052 053 /** 054 * Get the hue tolerance. 055 * @return the tolerance 056 * @see #setHTolerance 057 */ 058 public float getHTolerance() { 059 return hTolerance; 060 } 061 062 /** 063 * Set the saturation tolerance of the image in the range 0..1. 064 * @param sTolerance the tolerance 065 * @see #getSTolerance 066 */ 067 public void setSTolerance( float sTolerance ) { 068 this.sTolerance = sTolerance; 069 } 070 071 /** 072 * Get the saturation tolerance. 073 * @return the tolerance 074 * @see #setSTolerance 075 */ 076 public float getSTolerance() { 077 return sTolerance; 078 } 079 080 /** 081 * Set the brightness tolerance of the image in the range 0..1. 082 * @param bTolerance the tolerance 083 * @see #getBTolerance 084 */ 085 public void setBTolerance( float bTolerance ) { 086 this.bTolerance = bTolerance; 087 } 088 089 /** 090 * Get the brightness tolerance. 091 * @return the tolerance 092 * @see #setBTolerance 093 */ 094 public float getBTolerance() { 095 return bTolerance; 096 } 097 098 /** 099 * Set the destination image. 100 * @param destination the destination image 101 * @see #getDestination 102 */ 103 public void setDestination( BufferedImage destination ) { 104 this.destination = destination; 105 } 106 107 /** 108 * Get the destination image. 109 * @return the destination image 110 * @see #setDestination 111 */ 112 public BufferedImage getDestination() { 113 return destination; 114 } 115 116 /** 117 * Get the clean image. 118 * @param cleanImage the clean image 119 * @see #getCleanImage 120 */ 121 public void setCleanImage( BufferedImage cleanImage ) { 122 this.cleanImage = cleanImage; 123 } 124 125 /** 126 * Get the clean image. 127 * @return the clean image 128 * @see #setCleanImage 129 */ 130 public BufferedImage getCleanImage() { 131 return cleanImage; 132 } 133 134 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 135 int width = src.getWidth(); 136 int height = src.getHeight(); 137 int type = src.getType(); 138 WritableRaster srcRaster = src.getRaster(); 139 140 if ( dst == null ) 141 dst = createCompatibleDestImage( src, null ); 142 WritableRaster dstRaster = dst.getRaster(); 143 144 if ( destination != null && cleanImage != null ) { 145 float[] hsb1 = null; 146 float[] hsb2 = null; 147 int[] inPixels = null; 148 int[] outPixels = null; 149 int[] cleanPixels = null; 150 for ( int y = 0; y < height; y++ ) { 151 inPixels = getRGB( src, 0, y, width, 1, inPixels ); 152 outPixels = getRGB( destination, 0, y, width, 1, outPixels ); 153 cleanPixels = getRGB( cleanImage, 0, y, width, 1, cleanPixels ); 154 for ( int x = 0; x < width; x++ ) { 155 int rgb1 = inPixels[x]; 156 int out = outPixels[x]; 157 int rgb2 = cleanPixels[x]; 158 159 int r1 = (rgb1 >> 16) & 0xff; 160 int g1 = (rgb1 >> 8) & 0xff; 161 int b1 = rgb1 & 0xff; 162 int r2 = (rgb2 >> 16) & 0xff; 163 int g2 = (rgb2 >> 8) & 0xff; 164 int b2 = rgb2 & 0xff; 165 hsb1 = Color.RGBtoHSB( r1, b1, g1, hsb1 ); 166 hsb2 = Color.RGBtoHSB( r2, b2, g2, hsb2 ); 167 // int tolerance = (int)(255*tolerance); 168 // return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance; 169 170 // if ( PixelUtils.nearColors( in, clean, (int)(255*tolerance) ) ) 171 if ( Math.abs( hsb1[0] - hsb2[0] ) < hTolerance && Math.abs( hsb1[1] - hsb2[1] ) < sTolerance && Math.abs( hsb1[2] - hsb2[2] ) < bTolerance ) 172 inPixels[x] = out; 173 else 174 inPixels[x] = rgb1; 175 } 176 setRGB( dst, 0, y, width, 1, inPixels ); 177 } 178 } 179 180 return dst; 181 } 182 183 public String toString() { 184 return "Keying/Key..."; 185 } 186 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 187 Object o; 188 if((o=parameters.removeEL(KeyImpl.init("HTolerance")))!=null)setHTolerance(ImageFilterUtil.toFloatValue(o,"HTolerance")); 189 if((o=parameters.removeEL(KeyImpl.init("STolerance")))!=null)setSTolerance(ImageFilterUtil.toFloatValue(o,"STolerance")); 190 if((o=parameters.removeEL(KeyImpl.init("BTolerance")))!=null)setBTolerance(ImageFilterUtil.toFloatValue(o,"BTolerance")); 191 if((o=parameters.removeEL(KeyImpl.init("CleanImage")))!=null)setCleanImage(ImageFilterUtil.toBufferedImage(o,"CleanImage")); 192 if((o=parameters.removeEL(KeyImpl.init("destination")))!=null)setDestination(ImageFilterUtil.toBufferedImage(o,"destination")); 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":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [HTolerance, STolerance, BTolerance, CleanImage]"); 197 } 198 199 return filter(src, dst); 200 } 201 }