001 /* 002 * 003 004 Licensed under the Apache License, Version 2.0 (the "License"); 005 you may not use this file except in compliance with the License. 006 You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010 Unless required by applicable law or agreed to in writing, software 011 distributed under the License is distributed on an "AS IS" BASIS, 012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 See the License for the specific language governing permissions and 014 limitations under the License. 015 */ 016 017 package railo.runtime.img.filter;import java.awt.image.BufferedImage; 018 019 import railo.runtime.engine.ThreadLocalPageContext; 020 import railo.runtime.exp.FunctionException; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.img.ImageUtil; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.List; 025 import railo.runtime.type.Struct; 026 027 028 029 public class WeaveFilter extends PointFilter implements DynFiltering { 030 031 private float xWidth = 16; 032 private float yWidth = 16; 033 private float xGap = 6; 034 private float yGap = 6; 035 private int rows = 4; 036 private int cols = 4; 037 private int rgbX = 0xffff8080; 038 private int rgbY = 0xff8080ff; 039 private boolean useImageColors = true; 040 private boolean roundThreads = false; 041 private boolean shadeCrossings = true; 042 043 public int[][] matrix = { 044 { 0, 1, 0, 1 }, 045 { 1, 0, 1, 0 }, 046 { 0, 1, 0, 1 }, 047 { 1, 0, 1, 0 }, 048 }; 049 050 public WeaveFilter() { 051 } 052 053 public void setXGap(float xGap) { 054 this.xGap = xGap; 055 } 056 057 public void setXWidth(float xWidth) { 058 this.xWidth = xWidth; 059 } 060 061 public float getXWidth() { 062 return xWidth; 063 } 064 065 public void setYWidth(float yWidth) { 066 this.yWidth = yWidth; 067 } 068 069 public float getYWidth() { 070 return yWidth; 071 } 072 073 public float getXGap() { 074 return xGap; 075 } 076 077 public void setYGap(float yGap) { 078 this.yGap = yGap; 079 } 080 081 public float getYGap() { 082 return yGap; 083 } 084 085 public void setCrossings(int[][] matrix) { 086 this.matrix = matrix; 087 } 088 089 public int[][] getCrossings() { 090 return matrix; 091 } 092 093 public void setUseImageColors(boolean useImageColors) { 094 this.useImageColors = useImageColors; 095 } 096 097 public boolean getUseImageColors() { 098 return useImageColors; 099 } 100 101 public void setRoundThreads(boolean roundThreads) { 102 this.roundThreads = roundThreads; 103 } 104 105 public boolean getRoundThreads() { 106 return roundThreads; 107 } 108 109 public void setShadeCrossings(boolean shadeCrossings) { 110 this.shadeCrossings = shadeCrossings; 111 } 112 113 public boolean getShadeCrossings() { 114 return shadeCrossings; 115 } 116 117 public int filterRGB(int x, int y, int rgb) { 118 x += xWidth+xGap/2; 119 y += yWidth+yGap/2; 120 float nx = ImageMath.mod(x, xWidth+xGap); 121 float ny = ImageMath.mod(y, yWidth+yGap); 122 int ix = (int)(x / (xWidth+xGap)); 123 int iy = (int)(y / (yWidth+yGap)); 124 boolean inX = nx < xWidth; 125 boolean inY = ny < yWidth; 126 float dX, dY; 127 float cX, cY; 128 int lrgbX, lrgbY; 129 130 if (roundThreads) { 131 dX = Math.abs(xWidth/2-nx) / xWidth / 2; 132 dY = Math.abs(yWidth/2-ny) / yWidth / 2; 133 } else { 134 dX = dY = 0; 135 } 136 137 if (shadeCrossings) { 138 cX = ImageMath.smoothStep(xWidth/2, xWidth/2+xGap, Math.abs(xWidth/2-nx)); 139 cY = ImageMath.smoothStep(yWidth/2, yWidth/2+yGap, Math.abs(yWidth/2-ny)); 140 } else { 141 cX = cY = 0; 142 } 143 144 if (useImageColors) { 145 lrgbX = lrgbY = rgb; 146 } else { 147 lrgbX = rgbX; 148 lrgbY = rgbY; 149 } 150 int v; 151 int ixc = ix % cols; 152 int iyr = iy % rows; 153 int m = matrix[iyr][ixc]; 154 if (inX) { 155 if (inY) { 156 v = m == 1 ? lrgbX : lrgbY; 157 v = ImageMath.mixColors(2 * (m == 1 ? dX : dY), v, 0xff000000); 158 } else { 159 if (shadeCrossings) { 160 if (m != matrix[(iy+1) % rows][ixc]) { 161 if (m == 0) 162 cY = 1-cY; 163 cY *= 0.5f; 164 lrgbX = ImageMath.mixColors(cY, lrgbX, 0xff000000); 165 } else if (m == 0) 166 lrgbX = ImageMath.mixColors(0.5f, lrgbX, 0xff000000); 167 } 168 v = ImageMath.mixColors(2 * dX, lrgbX, 0xff000000); 169 } 170 } else if (inY) { 171 if (shadeCrossings) { 172 if (m != matrix[iyr][(ix+1) % cols]) { 173 if (m == 1) 174 cX = 1-cX; 175 cX *= 0.5f; 176 lrgbY = ImageMath.mixColors(cX, lrgbY, 0xff000000); 177 } else if (m == 1) 178 lrgbY = ImageMath.mixColors(0.5f, lrgbY, 0xff000000); 179 } 180 v = ImageMath.mixColors(2 * dY, lrgbY, 0xff000000); 181 } else 182 v = 0x00000000; 183 return v; 184 } 185 186 public String toString() { 187 return "Texture/Weave..."; 188 } 189 190 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 191 Object o; 192 if((o=parameters.removeEL(KeyImpl.init("UseImageColors")))!=null)setUseImageColors(ImageFilterUtil.toBooleanValue(o,"UseImageColors")); 193 if((o=parameters.removeEL(KeyImpl.init("XGap")))!=null)setXGap(ImageFilterUtil.toFloatValue(o,"XGap")); 194 if((o=parameters.removeEL(KeyImpl.init("XWidth")))!=null)setXWidth(ImageFilterUtil.toFloatValue(o,"XWidth")); 195 if((o=parameters.removeEL(KeyImpl.init("YWidth")))!=null)setYWidth(ImageFilterUtil.toFloatValue(o,"YWidth")); 196 if((o=parameters.removeEL(KeyImpl.init("YGap")))!=null)setYGap(ImageFilterUtil.toFloatValue(o,"YGap")); 197 if((o=parameters.removeEL(KeyImpl.init("Crossings")))!=null)setCrossings(ImageFilterUtil.toAAInt(o,"Crossings")); 198 if((o=parameters.removeEL(KeyImpl.init("RoundThreads")))!=null)setRoundThreads(ImageFilterUtil.toBooleanValue(o,"RoundThreads")); 199 if((o=parameters.removeEL(KeyImpl.init("ShadeCrossings")))!=null)setShadeCrossings(ImageFilterUtil.toBooleanValue(o,"ShadeCrossings")); 200 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 201 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 202 setDimensions(dim[0],dim[1]); 203 } 204 205 // check for arguments not supported 206 if(parameters.size()>0) { 207 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [UseImageColors, XGap, XWidth, YWidth, YGap, Crossings, RoundThreads, ShadeCrossings, Dimensions]"); 208 } 209 210 return filter(src, dst); 211 } 212 } 213 214