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; 036 037import lucee.runtime.engine.ThreadLocalPageContext; 038import lucee.runtime.exp.FunctionException; 039import lucee.runtime.exp.PageException; 040import lucee.runtime.img.ImageUtil; 041import lucee.runtime.type.KeyImpl; 042import lucee.runtime.type.Struct; 043import lucee.runtime.type.util.CollectionUtil; 044 045/** 046 * A filter which subtracts Gaussian blur from an image, sharpening it. 047 * 048 */ 049public class UnsharpFilter extends GaussianFilter implements DynFiltering { 050 051 private float amount = 0.5f; 052 private int threshold = 1; 053 054 public UnsharpFilter() { 055 radius = 2; 056 } 057 058 /** 059 * Set the threshold value. 060 * @param threshold the threshold value 061 * @see #getThreshold 062 */ 063 public void setThreshold( int threshold ) { 064 this.threshold = threshold; 065 } 066 067 /** 068 * Get the threshold value. 069 * @return the threshold value 070 * @see #setThreshold 071 */ 072 public int getThreshold() { 073 return threshold; 074 } 075 076 /** 077 * Set the amount of sharpening. 078 * @param amount the amount 079 * @min-value 0 080 * @max-value 1 081 * @see #getAmount 082 */ 083 public void setAmount( float amount ) { 084 this.amount = amount; 085 } 086 087 /** 088 * Get the amount of sharpening. 089 * @return the amount 090 * @see #setAmount 091 */ 092 public float getAmount() { 093 return amount; 094 } 095 096 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 097 int width = src.getWidth(); 098 int height = src.getHeight(); 099 100 if ( dst == null ) 101 dst = createCompatibleDestImage( src, null ); 102 103 int[] inPixels = new int[width*height]; 104 int[] outPixels = new int[width*height]; 105 src.getRGB( 0, 0, width, height, inPixels, 0, width ); 106 107 if ( radius > 0 ) { 108 convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, alpha && premultiplyAlpha, false, CLAMP_EDGES); 109 convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, false, alpha && premultiplyAlpha, CLAMP_EDGES); 110 } 111 112 src.getRGB( 0, 0, width, height, outPixels, 0, width ); 113 114 float a = 4*amount; 115 116 int index = 0; 117 for ( int y = 0; y < height; y++ ) { 118 for ( int x = 0; x < width; x++ ) { 119 int rgb1 = outPixels[index]; 120 int r1 = (rgb1 >> 16) & 0xff; 121 int g1 = (rgb1 >> 8) & 0xff; 122 int b1 = rgb1 & 0xff; 123 124 int rgb2 = inPixels[index]; 125 int r2 = (rgb2 >> 16) & 0xff; 126 int g2 = (rgb2 >> 8) & 0xff; 127 int b2 = rgb2 & 0xff; 128 129 if ( Math.abs( r1 - r2 ) >= threshold ) 130 r1 = PixelUtils.clamp( (int)((a+1) * (r1-r2) + r2) ); 131 if ( Math.abs( g1 - g2 ) >= threshold ) 132 g1 = PixelUtils.clamp( (int)((a+1) * (g1-g2) + g2) ); 133 if ( Math.abs( b1 - b2 ) >= threshold ) 134 b1 = PixelUtils.clamp( (int)((a+1) * (b1-b2) + b2) ); 135 136 inPixels[index] = (rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1; 137 index++; 138 } 139 } 140 141 dst.setRGB( 0, 0, width, height, inPixels, 0, width ); 142 return dst; 143 } 144 145 public String toString() { 146 return "Blur/Unsharp Mask..."; 147 } 148 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 149 Object o; 150 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 151 if((o=parameters.removeEL(KeyImpl.init("Threshold")))!=null)setThreshold(ImageFilterUtil.toIntValue(o,"Threshold")); 152 if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius")); 153 if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction")); 154 if((o=parameters.removeEL(KeyImpl.init("UseAlpha")))!=null)setUseAlpha(ImageFilterUtil.toBooleanValue(o,"UseAlpha")); 155 if((o=parameters.removeEL(KeyImpl.init("PremultiplyAlpha")))!=null)setPremultiplyAlpha(ImageFilterUtil.toBooleanValue(o,"PremultiplyAlpha")); 156 157 // check for arguments not supported 158 if(parameters.size()>0) { 159 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, Threshold, Radius, Kernel, EdgeAction, UseAlpha, PremultiplyAlpha]"); 160 } 161 162 return filter(src, dst); 163 } 164}