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; 036 037import java.awt.image.BufferedImage; 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 simulates the appearance of looking through glass. A separate grayscale displacement image is provided and 048 * pixels in the source image are displaced according to the gradient of the displacement map. 049 */ 050public class DisplaceFilter extends TransformFilter implements DynFiltering { 051 052 private float amount = 1; 053 private BufferedImage displacementMap = null; 054 private int[] xmap, ymap; 055 private int dw, dh; 056 057 public DisplaceFilter() { 058 } 059 060 /** 061 * Set the displacement map. 062 * @param displacementMap an image representing the displacment at each point 063 * @see #getDisplacementMap 064 */ 065 public void setDisplacementMap(BufferedImage displacementMap) { 066 this.displacementMap = displacementMap; 067 } 068 069 /** 070 * Get the displacement map. 071 * @return an image representing the displacment at each point 072 * @see #setDisplacementMap 073 */ 074 public BufferedImage getDisplacementMap() { 075 return displacementMap; 076 } 077 078 /** 079 * Set the amount of distortion. 080 * @param amount the amount 081 * @min-value 0 082 * @max-value 1 083 * @see #getAmount 084 */ 085 public void setAmount(float amount) { 086 this.amount = amount; 087 } 088 089 /** 090 * Get the amount of distortion. 091 * @return the amount 092 * @see #setAmount 093 */ 094 public float getAmount() { 095 return amount; 096 } 097 098 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 099 //int w = src.getWidth(); 100 //int h = src.getHeight(); 101 102 BufferedImage dm = displacementMap != null ? displacementMap : src; 103 104 dw = dm.getWidth(); 105 dh = dm.getHeight(); 106 107 int[] mapPixels = new int[dw*dh]; 108 getRGB( dm, 0, 0, dw, dh, mapPixels ); 109 xmap = new int[dw*dh]; 110 ymap = new int[dw*dh]; 111 112 int i = 0; 113 for ( int y = 0; y < dh; y++ ) { 114 for ( int x = 0; x < dw; x++ ) { 115 int rgb = mapPixels[i]; 116 int r = (rgb >> 16) & 0xff; 117 int g = (rgb >> 8) & 0xff; 118 int b = rgb & 0xff; 119 mapPixels[i] = (r+g+b) / 8; // An arbitrary scaling factor which gives a good range for "amount" 120 i++; 121 } 122 } 123 124 i = 0; 125 for ( int y = 0; y < dh; y++ ) { 126 int j1 = ((y+dh-1) % dh) * dw; 127 int j2 = y*dw; 128 int j3 = ((y+1) % dh) * dw; 129 for ( int x = 0; x < dw; x++ ) { 130 int k1 = (x+dw-1) % dw; 131 int k2 = x; 132 int k3 = (x+1) % dw; 133 xmap[i] = mapPixels[k1+j1] + mapPixels[k1+j2] + mapPixels[k1+j3] - mapPixels[k3+j1] - mapPixels[k3+j2] - mapPixels[k3+j3]; 134 ymap[i] = mapPixels[k1+j3] + mapPixels[k2+j3] + mapPixels[k3+j3] - mapPixels[k1+j1] - mapPixels[k2+j1] - mapPixels[k3+j1]; 135 i++; 136 } 137 } 138 mapPixels = null; 139 dst = super.filter( src, dst ); 140 xmap = ymap = null; 141 return dst; 142 } 143 144 protected void transformInverse(int x, int y, float[] out) { 145 //float xDisplacement, yDisplacement; 146 //float nx = x; 147 //float ny = y; 148 int i = (y % dh)*dw + x % dw; 149 out[0] = x + amount * xmap[i]; 150 out[1] = y + amount * ymap[i]; 151 } 152 153 public String toString() { 154 return "Distort/Displace..."; 155 } 156 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=null;//ImageUtil.createBufferedImage(src); 157 Object o; 158 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 159 if((o=parameters.removeEL(KeyImpl.init("DisplacementMap")))!=null)setDisplacementMap(ImageFilterUtil.toBufferedImage(o,"DisplacementMap")); 160 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 161 if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation")); 162 163 // check for arguments not supported 164 if(parameters.size()>0) { 165 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 [Amount, DisplacementMap, EdgeAction, Interpolation]"); 166 } 167 168 return filter(src, dst); 169 } 170}