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 047/** 048 * A filter which applies a crystallizing effect to an image, by producing Voronoi cells filled with colours from the image. 049 */ 050public class CrystallizeFilter extends CellularFilter implements DynFiltering { 051 052 private float edgeThickness = 0.4f; 053 private boolean fadeEdges = false; 054 private int edgeColor = 0xff000000; 055 056 public CrystallizeFilter() { 057 setScale(16); 058 setRandomness(0.0f); 059 } 060 061 public void setEdgeThickness(float edgeThickness) { 062 this.edgeThickness = edgeThickness; 063 } 064 065 public float getEdgeThickness() { 066 return edgeThickness; 067 } 068 069 public void setFadeEdges(boolean fadeEdges) { 070 this.fadeEdges = fadeEdges; 071 } 072 073 public boolean getFadeEdges() { 074 return fadeEdges; 075 } 076 077 public void setEdgeColor(int edgeColor) { 078 this.edgeColor = edgeColor; 079 } 080 081 public int getEdgeColor() { 082 return edgeColor; 083 } 084 085 public int getPixel(int x, int y, int[] inPixels, int width, int height) { 086 float nx = m00*x + m01*y; 087 float ny = m10*x + m11*y; 088 nx /= scale; 089 ny /= scale * stretch; 090 nx += 1000; 091 ny += 1000; // Reduce artifacts around 0,0 092 float f = evaluate(nx, ny); 093 094 float f1 = results[0].distance; 095 float f2 = results[1].distance; 096 int srcx = ImageMath.clamp((int)((results[0].x-1000)*scale), 0, width-1); 097 int srcy = ImageMath.clamp((int)((results[0].y-1000)*scale), 0, height-1); 098 int v = inPixels[srcy * width + srcx]; 099 f = (f2 - f1) / edgeThickness; 100 f = ImageMath.smoothStep(0, edgeThickness, f); 101 if (fadeEdges) { 102 srcx = ImageMath.clamp((int)((results[1].x-1000)*scale), 0, width-1); 103 srcy = ImageMath.clamp((int)((results[1].y-1000)*scale), 0, height-1); 104 int v2 = inPixels[srcy * width + srcx]; 105 v2 = ImageMath.mixColors(0.5f, v2, v); 106 v = ImageMath.mixColors(f, v2, v); 107 } else 108 v = ImageMath.mixColors(f, edgeColor, v); 109 return v; 110 } 111 112 public String toString() { 113 return "Stylize/Crystallize..."; 114 } 115 116 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 117 Object o; 118 if((o=parameters.removeEL(KeyImpl.init("EdgeThickness")))!=null)setEdgeThickness(ImageFilterUtil.toFloatValue(o,"EdgeThickness")); 119 if((o=parameters.removeEL(KeyImpl.init("FadeEdges")))!=null)setFadeEdges(ImageFilterUtil.toBooleanValue(o,"FadeEdges")); 120 if((o=parameters.removeEL(KeyImpl.init("EdgeColor")))!=null)setEdgeColor(ImageFilterUtil.toColorRGB(o,"EdgeColor")); 121 if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap")); 122 if((o=parameters.removeEL(KeyImpl.init("Amount")))!=null)setAmount(ImageFilterUtil.toFloatValue(o,"Amount")); 123 if((o=parameters.removeEL(KeyImpl.init("Turbulence")))!=null)setTurbulence(ImageFilterUtil.toFloatValue(o,"Turbulence")); 124 if((o=parameters.removeEL(KeyImpl.init("Stretch")))!=null)setStretch(ImageFilterUtil.toFloatValue(o,"Stretch")); 125 if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle")); 126 if((o=parameters.removeEL(KeyImpl.init("AngleCoefficient")))!=null)setAngleCoefficient(ImageFilterUtil.toFloatValue(o,"AngleCoefficient")); 127 if((o=parameters.removeEL(KeyImpl.init("GradientCoefficient")))!=null)setGradientCoefficient(ImageFilterUtil.toFloatValue(o,"GradientCoefficient")); 128 if((o=parameters.removeEL(KeyImpl.init("F1")))!=null)setF1(ImageFilterUtil.toFloatValue(o,"F1")); 129 if((o=parameters.removeEL(KeyImpl.init("F2")))!=null)setF2(ImageFilterUtil.toFloatValue(o,"F2")); 130 if((o=parameters.removeEL(KeyImpl.init("F3")))!=null)setF3(ImageFilterUtil.toFloatValue(o,"F3")); 131 if((o=parameters.removeEL(KeyImpl.init("F4")))!=null)setF4(ImageFilterUtil.toFloatValue(o,"F4")); 132 if((o=parameters.removeEL(KeyImpl.init("Randomness")))!=null)setRandomness(ImageFilterUtil.toFloatValue(o,"Randomness")); 133 if((o=parameters.removeEL(KeyImpl.init("GridType")))!=null)setGridType(ImageFilterUtil.toString(o,"GridType")); 134 if((o=parameters.removeEL(KeyImpl.init("DistancePower")))!=null)setDistancePower(ImageFilterUtil.toFloatValue(o,"DistancePower")); 135 if((o=parameters.removeEL(KeyImpl.init("Scale")))!=null)setScale(ImageFilterUtil.toFloatValue(o,"Scale")); 136 137 // check for arguments not supported 138 if(parameters.size()>0) { 139 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 [EdgeThickness, FadeEdges, EdgeColor, Colormap, Amount, Turbulence, Stretch, Angle, Coefficient, AngleCoefficient, GradientCoefficient, F1, F2, F3, F4, Randomness, GridType, DistancePower, Scale]"); 140 } 141 142 return filter(src, dst); 143 } 144}