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.Rectangle;
036import java.awt.image.BufferedImage;
037
038import lucee.runtime.engine.ThreadLocalPageContext;
039import lucee.runtime.exp.FunctionException;
040import lucee.runtime.exp.PageException;
041import lucee.runtime.img.ImageUtil;
042import lucee.runtime.type.KeyImpl;
043import lucee.runtime.type.Struct;
044import lucee.runtime.type.util.CollectionUtil;
045
046public class ShearFilter extends TransformFilter  implements DynFiltering {
047
048        private float xangle = 0.0f;
049        private float yangle = 0.0f;
050        private float shx = 0.0f;
051        private float shy = 0.0f;
052        private float xoffset = 0.0f;
053        private float yoffset = 0.0f;
054        private boolean resize = true;
055
056        public ShearFilter() {
057        }
058
059        public void setResize(boolean resize) {
060                this.resize = resize;
061        }
062
063        public boolean isResize() {
064                return resize;
065        }
066
067        public void setXAngle(float xangle) {
068                this.xangle = xangle;
069                initialize();
070        }
071
072        public float getXAngle() {
073                return xangle;
074        }
075
076        public void setYAngle(float yangle) {
077                this.yangle = yangle;
078                initialize();
079        }
080
081        public float getYAngle() {
082                return yangle;
083        }
084
085        private void initialize() {
086                shx = (float)Math.sin(xangle);
087                shy = (float)Math.sin(yangle);
088        }
089        
090        protected void transformSpace(Rectangle r) {
091                float tangent = (float)Math.tan(xangle);
092                xoffset = -r.height * tangent;
093                if (tangent < 0.0)
094                        tangent = -tangent;
095                r.width = (int)(r.height * tangent + r.width + 0.999999f);
096                tangent = (float)Math.tan(yangle);
097                yoffset = -r.width * tangent;
098                if (tangent < 0.0)
099                        tangent = -tangent;
100                r.height = (int)(r.width * tangent + r.height + 0.999999f);
101        }
102
103/*
104        public void imageComplete(int status) {
105try {
106                if (status == IMAGEERROR || status == IMAGEABORTED) {
107                        consumer.imageComplete(status);
108                        return;
109                }
110
111                int width = originalSpace.width;
112                int height = originalSpace.height;
113
114                float tangent = Math.tan(angle);
115                if (tangent < 0.0)
116                        tangent = -tangent;
117                int newWidth = (int)(height * tangent + width + 0.999999);
118                int[] outPixels = new int[height*newWidth];
119                int inIndex = 0;
120                int yOffset = 0;
121                for (int y = 0; y < height; y++) {
122                        float newCol;
123                        if (angle >= 0.0)
124                                newCol = y * tangent;
125                        else
126                                newCol = (height-y) * tangent;
127                        int iNewCol = (int)newCol;
128                        float f = newCol - iNewCol;
129                        f = 1.0 - f;
130
131                        int outIndex = yOffset+iNewCol;
132                        int lastRGB = inPixels[inIndex];
133                        for (int x = 0; x < width; x++) {
134                                int rgb = inPixels[inIndex];
135                                outPixels[outIndex] = ImageMath.mixColors(f, lastRGB, rgb);
136                                lastRGB = rgb;
137                                inIndex++;
138                                outIndex++;
139                        }
140                        outPixels[outIndex] = ImageMath.mixColors(f, lastRGB, 0);
141                        yOffset += newWidth;
142                }
143                consumer.setPixels(0, 0, newWidth, height, defaultRGBModel, outPixels, 0, newWidth);
144                consumer.imageComplete(status);
145                inPixels = null;
146}
147catch (Exception e) {
148        
149}
150        }
151*/
152        
153        protected void transformInverse(int x, int y, float[] out) {
154                out[0] = x + xoffset + (y * shx);
155                out[1] = y + yoffset + (x * shy);
156        }
157
158        public String toString() {
159                return "Distort/Shear...";
160        }
161
162        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
163                Object o;
164                if((o=parameters.removeEL(KeyImpl.init("Resize")))!=null)setResize(ImageFilterUtil.toBooleanValue(o,"Resize"));
165                if((o=parameters.removeEL(KeyImpl.init("XAngle")))!=null)setXAngle(ImageFilterUtil.toFloatValue(o,"XAngle"));
166                if((o=parameters.removeEL(KeyImpl.init("YAngle")))!=null)setYAngle(ImageFilterUtil.toFloatValue(o,"YAngle"));
167                if((o=parameters.removeEL(KeyImpl.init("EdgeAction")))!=null)setEdgeAction(ImageFilterUtil.toString(o,"EdgeAction"));
168                if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toString(o,"Interpolation"));
169
170                // check for arguments not supported
171                if(parameters.size()>0) {
172                        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 [Resize, XAngle, YAngle, EdgeAction, Interpolation]");
173                }
174
175                return filter(src, dst);
176        }
177}