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