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.AlphaComposite;
036import java.awt.Color;
037import java.awt.GradientPaint;
038import java.awt.Graphics2D;
039import java.awt.Shape;
040import java.awt.image.BufferedImage;
041
042import lucee.runtime.engine.ThreadLocalPageContext;
043import lucee.runtime.exp.FunctionException;
044import lucee.runtime.exp.PageException;
045import lucee.runtime.img.ImageUtil;
046import lucee.runtime.type.KeyImpl;
047import lucee.runtime.type.Struct;
048import lucee.runtime.type.util.CollectionUtil;
049
050public class MirrorFilter extends AbstractBufferedImageOp  implements DynFiltering {
051    private float opacity = 1.0f;
052        private float centreY = 0.5f;
053    private float distance;
054    private float angle;
055    private float rotation;
056    private float gap;
057
058    public MirrorFilter() {
059        }
060        
061        /**
062     * Specifies the angle of the mirror.
063     * @param angle the angle of the mirror.
064     * @angle
065     * @see #getAngle
066     */
067        public void setAngle( float angle ) {
068                this.angle = angle;
069        }
070
071        /**
072     * Returns the angle of the mirror.
073     * @return the angle of the mirror.
074     * @see #setAngle
075     */
076        public float getAngle() {
077                return angle;
078        }
079        
080        public void setDistance( float distance ) {
081                this.distance = distance;
082        }
083
084        public float getDistance() {
085                return distance;
086        }
087        
088        public void setRotation( float rotation ) {
089                this.rotation = rotation;
090        }
091
092        public float getRotation() {
093                return rotation;
094        }
095        
096        public void setGap( float gap ) {
097                this.gap = gap;
098        }
099
100        public float getGap() {
101                return gap;
102        }
103        
104        /**
105     * Set the opacity of the reflection.
106     * @param opacity the opacity.
107     * @see #getOpacity
108     */
109        public void setOpacity( float opacity ) {
110                this.opacity = opacity;
111        }
112
113        /**
114     * Get the opacity of the reflection.
115     * @return the opacity.
116     * @see #setOpacity
117     */
118        public float getOpacity() {
119                return opacity;
120        }
121        
122        public void setCentreY( float centreY ) {
123                this.centreY = centreY;
124        }
125
126        public float getCentreY() {
127                return centreY;
128        }
129        
130    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
131        if ( dst == null )
132            dst = createCompatibleDestImage( src, null );
133        //BufferedImage tsrc = src;
134                Shape clip;
135                int width = src.getWidth();
136                int height = src.getHeight();
137                int h = (int)(centreY * height);
138                int d = (int)(gap * height);
139
140                Graphics2D g = dst.createGraphics();
141                clip = g.getClip();
142                g.clipRect( 0, 0, width, h );
143                g.drawRenderedImage( src, null );
144                g.setClip( clip );
145                g.clipRect( 0, h+d, width, height-h-d );
146                g.translate( 0, 2*h+d );
147                g.scale( 1, -1 );
148                g.drawRenderedImage( src, null );
149                g.setPaint( new GradientPaint( 0, 0, new Color( 1.0f, 0.0f, 0.0f, 0.0f ), 0, h, new Color( 0.0f, 1.0f, 0.0f, opacity ) ) );
150                g.setComposite( AlphaComposite.getInstance( AlphaComposite.DST_IN ) );
151                g.fillRect( 0, 0, width, h );
152                g.setClip( clip );
153                g.dispose();
154        
155        return dst;
156    }
157    
158        public String toString() {
159                return "Effects/Mirror...";
160        }
161        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
162                Object o;
163                if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
164                if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY"));
165                if((o=parameters.removeEL(KeyImpl.init("Distance")))!=null)setDistance(ImageFilterUtil.toFloatValue(o,"Distance"));
166                if((o=parameters.removeEL(KeyImpl.init("Rotation")))!=null)setRotation(ImageFilterUtil.toFloatValue(o,"Rotation"));
167                if((o=parameters.removeEL(KeyImpl.init("Gap")))!=null)setGap(ImageFilterUtil.toFloatValue(o,"Gap"));
168                if((o=parameters.removeEL(KeyImpl.init("Opacity")))!=null)setOpacity(ImageFilterUtil.toFloatValue(o,"Opacity"));
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 [Angle, CentreY, Distance, Rotation, Gap, Opacity]");
173                }
174
175                return filter(src, dst);
176        }
177}