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 import java.awt.image.Raster; 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.type.KeyImpl; 025 import railo.runtime.type.List; 026 import railo.runtime.type.Struct; 027 028 /** 029 * A filter which uses the alpha channel of a "mask" image to interpolate between a source and destination image. 030 */ 031 public class ApplyMaskFilter extends AbstractBufferedImageOp implements DynFiltering { 032 033 private BufferedImage destination; 034 private BufferedImage maskImage; 035 036 /** 037 * Construct an ApplyMaskFIlter. 038 */ 039 public ApplyMaskFilter() { 040 } 041 042 /** 043 * Construct an ApplyMaskFIlter. 044 * @param maskImage the mask image 045 * @param destination the destination image 046 */ 047 public ApplyMaskFilter( BufferedImage maskImage, BufferedImage destination ) { 048 this.maskImage = maskImage; 049 this.destination = destination; 050 } 051 052 /** 053 * Set the destination image. 054 * @param destination the destination image 055 * @see #getDestination 056 */ 057 public void setDestination( BufferedImage destination ) { 058 this.destination = destination; 059 } 060 061 /** 062 * Get the destination image. 063 * @return the destination image 064 * @see #setDestination 065 */ 066 public BufferedImage getDestination() { 067 return destination; 068 } 069 070 /** 071 * Set the mask image. 072 * @param maskImage the mask image 073 * @see #getMaskImage 074 */ 075 public void setMaskImage( BufferedImage maskImage ) { 076 this.maskImage = maskImage; 077 } 078 079 /** 080 * Get the mask image. 081 * @return the mask image 082 * @see #setMaskImage 083 */ 084 public BufferedImage getMaskImage() { 085 return maskImage; 086 } 087 088 /** 089 * Interpolates between two rasters according to the alpha level of a mask raster. 090 * @param src the source raster 091 * @param dst the destination raster 092 * @param sel the mask raster 093 */ 094 public static void composeThroughMask(Raster src, WritableRaster dst, Raster sel) { 095 int x = src.getMinX(); 096 int y = src.getMinY(); 097 int w = src.getWidth(); 098 int h = src.getHeight(); 099 100 int srcRGB[] = null; 101 int selRGB[] = null; 102 int dstRGB[] = null; 103 104 for ( int i = 0; i < h; i++ ) { 105 srcRGB = src.getPixels(x, y, w, 1, srcRGB); 106 selRGB = sel.getPixels(x, y, w, 1, selRGB); 107 dstRGB = dst.getPixels(x, y, w, 1, dstRGB); 108 109 int k = x; 110 for ( int j = 0; j < w; j++ ) { 111 int sr = srcRGB[k]; 112 int dir = dstRGB[k]; 113 int sg = srcRGB[k+1]; 114 int dig = dstRGB[k+1]; 115 int sb = srcRGB[k+2]; 116 int dib = dstRGB[k+2]; 117 int sa = srcRGB[k+3]; 118 int dia = dstRGB[k+3]; 119 120 float a = selRGB[k+3]/255f; 121 float ac = 1-a; 122 123 dstRGB[k] = (int)(a*sr + ac*dir); 124 dstRGB[k+1] = (int)(a*sg + ac*dig); 125 dstRGB[k+2] = (int)(a*sb + ac*dib); 126 dstRGB[k+3] = (int)(a*sa + ac*dia); 127 k += 4; 128 } 129 130 dst.setPixels(x, y, w, 1, dstRGB); 131 y++; 132 } 133 } 134 135 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 136 int width = src.getWidth(); 137 int height = src.getHeight(); 138 int type = src.getType(); 139 WritableRaster srcRaster = src.getRaster(); 140 141 if ( dst == null ) 142 dst = createCompatibleDestImage( src, null ); 143 WritableRaster dstRaster = dst.getRaster(); 144 145 if ( destination != null && maskImage != null ) 146 composeThroughMask( src.getRaster(), dst.getRaster(), maskImage.getRaster() ); 147 148 return dst; 149 } 150 151 public String toString() { 152 return "Keying/Key..."; 153 } 154 public BufferedImage filter(BufferedImage src ,Struct parameters) throws PageException { 155 BufferedImage dst=src; 156 Object o; 157 if((o=parameters.removeEL(KeyImpl.init("MaskImage")))!=null)setMaskImage(ImageFilterUtil.toBufferedImage(o,"MaskImage")); 158 if((o=parameters.removeEL(KeyImpl.init("destination")))!=null)setDestination(ImageFilterUtil.toBufferedImage(o,"destination")); 159 160 // check for arguments not supported 161 if(parameters.size()>0) { 162 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 [MaskImage]"); 163 } 164 165 return filter(src, dst); 166 } 167 }