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 047public class WeaveFilter extends PointFilter implements DynFiltering { 048 049 private float xWidth = 16; 050 private float yWidth = 16; 051 private float xGap = 6; 052 private float yGap = 6; 053 private int rows = 4; 054 private int cols = 4; 055 private int rgbX = 0xffff8080; 056 private int rgbY = 0xff8080ff; 057 private boolean useImageColors = true; 058 private boolean roundThreads = false; 059 private boolean shadeCrossings = true; 060 061 public int[][] matrix = { 062 { 0, 1, 0, 1 }, 063 { 1, 0, 1, 0 }, 064 { 0, 1, 0, 1 }, 065 { 1, 0, 1, 0 }, 066 }; 067 068 public WeaveFilter() { 069 } 070 071 public void setXGap(float xGap) { 072 this.xGap = xGap; 073 } 074 075 public void setXWidth(float xWidth) { 076 this.xWidth = xWidth; 077 } 078 079 public float getXWidth() { 080 return xWidth; 081 } 082 083 public void setYWidth(float yWidth) { 084 this.yWidth = yWidth; 085 } 086 087 public float getYWidth() { 088 return yWidth; 089 } 090 091 public float getXGap() { 092 return xGap; 093 } 094 095 public void setYGap(float yGap) { 096 this.yGap = yGap; 097 } 098 099 public float getYGap() { 100 return yGap; 101 } 102 103 public void setCrossings(int[][] matrix) { 104 this.matrix = matrix; 105 } 106 107 public int[][] getCrossings() { 108 return matrix; 109 } 110 111 public void setUseImageColors(boolean useImageColors) { 112 this.useImageColors = useImageColors; 113 } 114 115 public boolean getUseImageColors() { 116 return useImageColors; 117 } 118 119 public void setRoundThreads(boolean roundThreads) { 120 this.roundThreads = roundThreads; 121 } 122 123 public boolean getRoundThreads() { 124 return roundThreads; 125 } 126 127 public void setShadeCrossings(boolean shadeCrossings) { 128 this.shadeCrossings = shadeCrossings; 129 } 130 131 public boolean getShadeCrossings() { 132 return shadeCrossings; 133 } 134 135 public int filterRGB(int x, int y, int rgb) { 136 x += xWidth+xGap/2; 137 y += yWidth+yGap/2; 138 float nx = ImageMath.mod(x, xWidth+xGap); 139 float ny = ImageMath.mod(y, yWidth+yGap); 140 int ix = (int)(x / (xWidth+xGap)); 141 int iy = (int)(y / (yWidth+yGap)); 142 boolean inX = nx < xWidth; 143 boolean inY = ny < yWidth; 144 float dX, dY; 145 float cX, cY; 146 int lrgbX, lrgbY; 147 148 if (roundThreads) { 149 dX = Math.abs(xWidth/2-nx) / xWidth / 2; 150 dY = Math.abs(yWidth/2-ny) / yWidth / 2; 151 } else { 152 dX = dY = 0; 153 } 154 155 if (shadeCrossings) { 156 cX = ImageMath.smoothStep(xWidth/2, xWidth/2+xGap, Math.abs(xWidth/2-nx)); 157 cY = ImageMath.smoothStep(yWidth/2, yWidth/2+yGap, Math.abs(yWidth/2-ny)); 158 } else { 159 cX = cY = 0; 160 } 161 162 if (useImageColors) { 163 lrgbX = lrgbY = rgb; 164 } else { 165 lrgbX = rgbX; 166 lrgbY = rgbY; 167 } 168 int v; 169 int ixc = ix % cols; 170 int iyr = iy % rows; 171 int m = matrix[iyr][ixc]; 172 if (inX) { 173 if (inY) { 174 v = m == 1 ? lrgbX : lrgbY; 175 v = ImageMath.mixColors(2 * (m == 1 ? dX : dY), v, 0xff000000); 176 } else { 177 if (shadeCrossings) { 178 if (m != matrix[(iy+1) % rows][ixc]) { 179 if (m == 0) 180 cY = 1-cY; 181 cY *= 0.5f; 182 lrgbX = ImageMath.mixColors(cY, lrgbX, 0xff000000); 183 } else if (m == 0) 184 lrgbX = ImageMath.mixColors(0.5f, lrgbX, 0xff000000); 185 } 186 v = ImageMath.mixColors(2 * dX, lrgbX, 0xff000000); 187 } 188 } else if (inY) { 189 if (shadeCrossings) { 190 if (m != matrix[iyr][(ix+1) % cols]) { 191 if (m == 1) 192 cX = 1-cX; 193 cX *= 0.5f; 194 lrgbY = ImageMath.mixColors(cX, lrgbY, 0xff000000); 195 } else if (m == 1) 196 lrgbY = ImageMath.mixColors(0.5f, lrgbY, 0xff000000); 197 } 198 v = ImageMath.mixColors(2 * dY, lrgbY, 0xff000000); 199 } else 200 v = 0x00000000; 201 return v; 202 } 203 204 public String toString() { 205 return "Texture/Weave..."; 206 } 207 208 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 209 Object o; 210 if((o=parameters.removeEL(KeyImpl.init("UseImageColors")))!=null)setUseImageColors(ImageFilterUtil.toBooleanValue(o,"UseImageColors")); 211 if((o=parameters.removeEL(KeyImpl.init("XGap")))!=null)setXGap(ImageFilterUtil.toFloatValue(o,"XGap")); 212 if((o=parameters.removeEL(KeyImpl.init("XWidth")))!=null)setXWidth(ImageFilterUtil.toFloatValue(o,"XWidth")); 213 if((o=parameters.removeEL(KeyImpl.init("YWidth")))!=null)setYWidth(ImageFilterUtil.toFloatValue(o,"YWidth")); 214 if((o=parameters.removeEL(KeyImpl.init("YGap")))!=null)setYGap(ImageFilterUtil.toFloatValue(o,"YGap")); 215 if((o=parameters.removeEL(KeyImpl.init("Crossings")))!=null)setCrossings(ImageFilterUtil.toAAInt(o,"Crossings")); 216 if((o=parameters.removeEL(KeyImpl.init("RoundThreads")))!=null)setRoundThreads(ImageFilterUtil.toBooleanValue(o,"RoundThreads")); 217 if((o=parameters.removeEL(KeyImpl.init("ShadeCrossings")))!=null)setShadeCrossings(ImageFilterUtil.toBooleanValue(o,"ShadeCrossings")); 218 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 219 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 220 setDimensions(dim[0],dim[1]); 221 } 222 223 // check for arguments not supported 224 if(parameters.size()>0) { 225 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 [UseImageColors, XGap, XWidth, YWidth, YGap, Crossings, RoundThreads, ShadeCrossings, Dimensions]"); 226 } 227 228 return filter(src, dst); 229 } 230} 231 232