001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019/* 020* 021 022Licensed under the Apache License, Version 2.0 (the "License"); 023you may not use this file except in compliance with the License. 024You may obtain a copy of the License at 025 026 http://www.apache.org/licenses/LICENSE-2.0 027 028Unless required by applicable law or agreed to in writing, software 029distributed under the License is distributed on an "AS IS" BASIS, 030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 031See the License for the specific language governing permissions and 032limitations under the License. 033*/ 034 035package lucee.runtime.img.filter;import java.awt.image.BufferedImage; 036import java.awt.image.Raster; 037import java.awt.image.WritableRaster; 038 039import lucee.runtime.engine.ThreadLocalPageContext; 040import lucee.runtime.exp.FunctionException; 041import lucee.runtime.exp.PageException; 042import lucee.runtime.type.KeyImpl; 043import lucee.runtime.type.Struct; 044import lucee.runtime.type.util.CollectionUtil; 045 046/** 047 * A filter which uses the alpha channel of a "mask" image to interpolate between a source and destination image. 048 */ 049public class ApplyMaskFilter extends AbstractBufferedImageOp implements DynFiltering { 050 051 private BufferedImage destination; 052 private BufferedImage maskImage; 053 054 /** 055 * Construct an ApplyMaskFIlter. 056 */ 057 public ApplyMaskFilter() { 058 } 059 060 /** 061 * Construct an ApplyMaskFIlter. 062 * @param maskImage the mask image 063 * @param destination the destination image 064 */ 065 public ApplyMaskFilter( BufferedImage maskImage, BufferedImage destination ) { 066 this.maskImage = maskImage; 067 this.destination = destination; 068 } 069 070 /** 071 * Set the destination image. 072 * @param destination the destination image 073 * @see #getDestination 074 */ 075 public void setDestination( BufferedImage destination ) { 076 this.destination = destination; 077 } 078 079 /** 080 * Get the destination image. 081 * @return the destination image 082 * @see #setDestination 083 */ 084 public BufferedImage getDestination() { 085 return destination; 086 } 087 088 /** 089 * Set the mask image. 090 * @param maskImage the mask image 091 * @see #getMaskImage 092 */ 093 public void setMaskImage( BufferedImage maskImage ) { 094 this.maskImage = maskImage; 095 } 096 097 /** 098 * Get the mask image. 099 * @return the mask image 100 * @see #setMaskImage 101 */ 102 public BufferedImage getMaskImage() { 103 return maskImage; 104 } 105 106 /** 107 * Interpolates between two rasters according to the alpha level of a mask raster. 108 * @param src the source raster 109 * @param dst the destination raster 110 * @param sel the mask raster 111 */ 112 public static void composeThroughMask(Raster src, WritableRaster dst, Raster sel) { 113 int x = src.getMinX(); 114 int y = src.getMinY(); 115 int w = src.getWidth(); 116 int h = src.getHeight(); 117 118 int srcRGB[] = null; 119 int selRGB[] = null; 120 int dstRGB[] = null; 121 122 for ( int i = 0; i < h; i++ ) { 123 srcRGB = src.getPixels(x, y, w, 1, srcRGB); 124 selRGB = sel.getPixels(x, y, w, 1, selRGB); 125 dstRGB = dst.getPixels(x, y, w, 1, dstRGB); 126 127 int k = x; 128 for ( int j = 0; j < w; j++ ) { 129 int sr = srcRGB[k]; 130 int dir = dstRGB[k]; 131 int sg = srcRGB[k+1]; 132 int dig = dstRGB[k+1]; 133 int sb = srcRGB[k+2]; 134 int dib = dstRGB[k+2]; 135 int sa = srcRGB[k+3]; 136 int dia = dstRGB[k+3]; 137 138 float a = selRGB[k+3]/255f; 139 float ac = 1-a; 140 141 dstRGB[k] = (int)(a*sr + ac*dir); 142 dstRGB[k+1] = (int)(a*sg + ac*dig); 143 dstRGB[k+2] = (int)(a*sb + ac*dib); 144 dstRGB[k+3] = (int)(a*sa + ac*dia); 145 k += 4; 146 } 147 148 dst.setPixels(x, y, w, 1, dstRGB); 149 y++; 150 } 151 } 152 153 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 154 //int width = src.getWidth(); 155 //int height = src.getHeight(); 156 //int type = src.getType(); 157 //WritableRaster srcRaster = 158 src.getRaster(); 159 160 if ( dst == null ) 161 dst = createCompatibleDestImage( src, null ); 162 //WritableRaster dstRaster = 163 dst.getRaster(); 164 165 if ( destination != null && maskImage != null ) 166 composeThroughMask( src.getRaster(), dst.getRaster(), maskImage.getRaster() ); 167 168 return dst; 169 } 170 171 public String toString() { 172 return "Keying/Key..."; 173 } 174 public BufferedImage filter(BufferedImage src ,Struct parameters) throws PageException { 175 BufferedImage dst=src; 176 Object o; 177 if((o=parameters.removeEL(KeyImpl.init("MaskImage")))!=null)setMaskImage(ImageFilterUtil.toBufferedImage(o,"MaskImage")); 178 if((o=parameters.removeEL(KeyImpl.init("destination")))!=null)setDestination(ImageFilterUtil.toBufferedImage(o,"destination")); 179 180 // check for arguments not supported 181 if(parameters.size()>0) { 182 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 [MaskImage]"); 183 } 184 185 return filter(src, dst); 186 } 187}