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}