001    /*
002    *
003    
004    Licensed under the Apache License, Version 2.0 (the "License");
005    you may not use this file except in compliance with the License.
006    You may obtain a copy of the License at
007    
008       http://www.apache.org/licenses/LICENSE-2.0
009    
010    Unless required by applicable law or agreed to in writing, software
011    distributed under the License is distributed on an "AS IS" BASIS,
012    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013    See the License for the specific language governing permissions and
014    limitations under the License.
015    */
016    
017    package railo.runtime.img.filter;import java.awt.AlphaComposite;
018    import java.awt.Color;
019    import java.awt.Graphics2D;
020    import java.awt.image.BufferedImage;
021    
022    import railo.runtime.engine.ThreadLocalPageContext;
023    import railo.runtime.exp.FunctionException;
024    import railo.runtime.exp.PageException;
025    import railo.runtime.img.ImageUtil;
026    import railo.runtime.img.composite.AddComposite;
027    import railo.runtime.type.KeyImpl;
028    import railo.runtime.type.List;
029    import railo.runtime.type.Struct;
030    
031    public class ShineFilter extends AbstractBufferedImageOp  implements DynFiltering {
032            
033            private float radius = 5;
034            private float angle = (float)Math.PI*7/4;
035            private float distance = 5;
036            private float bevel = 0.5f;
037            private boolean shadowOnly = false;
038            private int shineColor = 0xffffffff;
039            private float brightness = 0.2f;
040            private float softness = 0;
041    
042            public ShineFilter() {
043            }
044    
045            public void setAngle(float angle) {
046                    this.angle = angle;
047            }
048    
049            public float getAngle() {
050                    return angle;
051            }
052    
053            public void setDistance(float distance) {
054                    this.distance = distance;
055            }
056    
057            public float getDistance() {
058                    return distance;
059            }
060    
061            /**
062             * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
063             * @param radius the radius of the blur in pixels.
064             */
065            public void setRadius(float radius) {
066                    this.radius = radius;
067            }
068            
069            /**
070             * Get the radius of the kernel.
071             * @return the radius
072             */
073            public float getRadius() {
074                    return radius;
075            }
076    
077            public void setBevel(float bevel) {
078                    this.bevel = bevel;
079            }
080    
081            public float getBevel() {
082                    return bevel;
083            }
084    
085            public void setShineColor(int shineColor) {
086                    this.shineColor = shineColor;
087            }
088    
089            public int getShineColor() {
090                    return shineColor;
091            }
092    
093            public void setShadowOnly(boolean shadowOnly) {
094                    this.shadowOnly = shadowOnly;
095            }
096    
097            public boolean getShadowOnly() {
098                    return shadowOnly;
099            }
100    
101            public void setBrightness(float brightness) {
102                    this.brightness = brightness;
103            }
104            
105            public float getBrightness() {
106                    return brightness;
107            }
108            
109            public void setSoftness(float softness) {
110                    this.softness = softness;
111            }
112    
113            public float getSoftness() {
114                    return softness;
115            }
116    
117        public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
118            int width = src.getWidth();
119            int height = src.getHeight();
120    
121            if ( dst == null )
122                dst = createCompatibleDestImage( src, null );
123    
124                    float xOffset = distance*(float)Math.cos(angle);
125                    float yOffset = -distance*(float)Math.sin(angle);
126    
127            BufferedImage matte = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
128            ErodeAlphaFilter s = new ErodeAlphaFilter( bevel * 10, 0.75f, 0.1f );
129            matte = s.filter( src, (BufferedImage)null );
130    
131            BufferedImage shineLayer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
132                    Graphics2D g = shineLayer.createGraphics();
133                    g.setColor( new Color( shineColor ) );
134            g.fillRect( 0, 0, width, height );
135            g.setComposite( AlphaComposite.DstIn );
136            g.drawRenderedImage( matte, null );
137            g.setComposite( AlphaComposite.DstOut );
138            g.translate( xOffset, yOffset );
139            g.drawRenderedImage( matte, null );
140                    g.dispose();
141            shineLayer = new GaussianFilter( radius ).filter( shineLayer, (BufferedImage)null );
142            shineLayer = new RescaleFilter( 3*brightness ).filter( shineLayer, shineLayer );
143    
144                    g = dst.createGraphics();
145            g.drawRenderedImage( src, null );
146            g.setComposite( new AddComposite( 1.0f ) );
147            g.drawRenderedImage( shineLayer, null );
148                    g.dispose();
149    
150            return dst;
151            }
152    
153            public String toString() {
154                    return "Stylize/Shine...";
155            }
156            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
157                    Object o;
158                    if((o=parameters.removeEL(KeyImpl.init("Radius")))!=null)setRadius(ImageFilterUtil.toFloatValue(o,"Radius"));
159                    if((o=parameters.removeEL(KeyImpl.init("Brightness")))!=null)setBrightness(ImageFilterUtil.toFloatValue(o,"Brightness"));
160                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
161                    if((o=parameters.removeEL(KeyImpl.init("Softness")))!=null)setSoftness(ImageFilterUtil.toFloatValue(o,"Softness"));
162                    if((o=parameters.removeEL(KeyImpl.init("Distance")))!=null)setDistance(ImageFilterUtil.toFloatValue(o,"Distance"));
163                    if((o=parameters.removeEL(KeyImpl.init("ShadowOnly")))!=null)setShadowOnly(ImageFilterUtil.toBooleanValue(o,"ShadowOnly"));
164                    if((o=parameters.removeEL(KeyImpl.init("Bevel")))!=null)setBevel(ImageFilterUtil.toFloatValue(o,"Bevel"));
165                    if((o=parameters.removeEL(KeyImpl.init("ShineColor")))!=null)setShineColor(ImageFilterUtil.toColorRGB(o,"ShineColor"));
166    
167                    // check for arguments not supported
168                    if(parameters.size()>0) {
169                            throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Radius, Brightness, Angle, Softness, Distance, ShadowOnly, Bevel, ShineColor]");
170                    }
171    
172                    return filter(src, dst);
173            }
174    }