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.Graphics2D;
038import java.awt.image.BufferedImage;
039
040import lucee.runtime.engine.ThreadLocalPageContext;
041import lucee.runtime.exp.FunctionException;
042import lucee.runtime.exp.PageException;
043import lucee.runtime.img.ImageUtil;
044import lucee.runtime.img.composite.AddComposite;
045import lucee.runtime.type.KeyImpl;
046import lucee.runtime.type.Struct;
047import lucee.runtime.type.util.CollectionUtil;
048
049public class ShineFilter extends AbstractBufferedImageOp  implements DynFiltering {
050        
051        private float radius = 5;
052        private float angle = (float)Math.PI*7/4;
053        private float distance = 5;
054        private float bevel = 0.5f;
055        private boolean shadowOnly = false;
056        private int shineColor = 0xffffffff;
057        private float brightness = 0.2f;
058        private float softness = 0;
059
060        public ShineFilter() {
061        }
062
063        public void setAngle(float angle) {
064                this.angle = angle;
065        }
066
067        public float getAngle() {
068                return angle;
069        }
070
071        public void setDistance(float distance) {
072                this.distance = distance;
073        }
074
075        public float getDistance() {
076                return distance;
077        }
078
079        /**
080         * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
081         * @param radius the radius of the blur in pixels.
082         */
083        public void setRadius(float radius) {
084                this.radius = radius;
085        }
086        
087        /**
088         * Get the radius of the kernel.
089         * @return the radius
090         */
091        public float getRadius() {
092                return radius;
093        }
094
095        public void setBevel(float bevel) {
096                this.bevel = bevel;
097        }
098
099        public float getBevel() {
100                return bevel;
101        }
102
103        public void setShineColor(int shineColor) {
104                this.shineColor = shineColor;
105        }
106
107        public int getShineColor() {
108                return shineColor;
109        }
110
111        public void setShadowOnly(boolean shadowOnly) {
112                this.shadowOnly = shadowOnly;
113        }
114
115        public boolean getShadowOnly() {
116                return shadowOnly;
117        }
118
119        public void setBrightness(float brightness) {
120                this.brightness = brightness;
121        }
122        
123        public float getBrightness() {
124                return brightness;
125        }
126        
127        public void setSoftness(float softness) {
128                this.softness = softness;
129        }
130
131        public float getSoftness() {
132                return softness;
133        }
134
135    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
136        int width = src.getWidth();
137        int height = src.getHeight();
138
139        if ( dst == null )
140            dst = createCompatibleDestImage( src, null );
141
142                float xOffset = distance*(float)Math.cos(angle);
143                float yOffset = -distance*(float)Math.sin(angle);
144
145        BufferedImage matte = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
146        ErodeAlphaFilter s = new ErodeAlphaFilter( bevel * 10, 0.75f, 0.1f );
147        matte = s.filter( src, (BufferedImage)null );
148
149        BufferedImage shineLayer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
150                Graphics2D g = shineLayer.createGraphics();
151                g.setColor( new Color( shineColor ) );
152        g.fillRect( 0, 0, width, height );
153        g.setComposite( AlphaComposite.DstIn );
154        g.drawRenderedImage( matte, null );
155        g.setComposite( AlphaComposite.DstOut );
156        g.translate( xOffset, yOffset );
157        g.drawRenderedImage( matte, null );
158                g.dispose();
159        shineLayer = new GaussianFilter( radius ).filter( shineLayer, (BufferedImage)null );
160        shineLayer = new RescaleFilter( 3*brightness ).filter( shineLayer, shineLayer );
161
162                g = dst.createGraphics();
163        g.drawRenderedImage( src, null );
164        g.setComposite( new AddComposite( 1.0f ) );
165        g.drawRenderedImage( shineLayer, null );
166                g.dispose();
167
168        return dst;
169        }
170
171        public String toString() {
172                return "Stylize/Shine...";
173        }
174        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
175                Object o;
176                if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius"));
177                if((o=parameters.removeEL(KeyImpl.init("Brightness")))!=null)setBrightness(ImageFilterUtil.toFloatValue(o,"Brightness"));
178                if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
179                if((o=parameters.removeEL(KeyImpl.init("Softness")))!=null)setSoftness(ImageFilterUtil.toFloatValue(o,"Softness"));
180                if((o=parameters.removeEL(KeyImpl.init("Distance")))!=null)setDistance(ImageFilterUtil.toFloatValue(o,"Distance"));
181                if((o=parameters.removeEL(KeyImpl.init("ShadowOnly")))!=null)setShadowOnly(ImageFilterUtil.toBooleanValue(o,"ShadowOnly"));
182                if((o=parameters.removeEL(KeyImpl.init("Bevel")))!=null)setBevel(ImageFilterUtil.toFloatValue(o,"Bevel"));
183                if((o=parameters.removeEL(KeyImpl.init("ShineColor")))!=null)setShineColor(ImageFilterUtil.toColorRGB(o,"ShineColor"));
184
185                // check for arguments not supported
186                if(parameters.size()>0) {
187                        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 [Radius, Brightness, Angle, Softness, Distance, ShadowOnly, Bevel, ShineColor]");
188                }
189
190                return filter(src, dst);
191        }
192}