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.Graphics2D;
019    import java.awt.image.BufferedImage;
020    
021    import railo.runtime.engine.ThreadLocalPageContext;
022    import railo.runtime.exp.FunctionException;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.img.ImageUtil;
025    import railo.runtime.img.composite.MiscComposite;
026    import railo.runtime.type.KeyImpl;
027    import railo.runtime.type.List;
028    import railo.runtime.type.Struct;
029    
030    /**
031     * A filter which produces the effect of light rays shining out of an image.
032     */
033    public class RaysFilter extends MotionBlurOp  implements DynFiltering {
034    
035        private float opacity = 1.0f;
036        private float threshold = 0.0f;
037        private float strength = 0.5f;
038            private boolean raysOnly = false;
039            private Colormap colormap=new GrayscaleColormap();
040    
041        public RaysFilter() {
042            }
043            
044            /**
045         * Set the opacity of the rays.
046         * @param opacity the opacity.
047         * @see #getOpacity
048         */
049            public void setOpacity(float opacity) {
050                    this.opacity = opacity;
051            }
052    
053            /**
054         * Get the opacity of the rays.
055         * @return the opacity.
056         * @see #setOpacity
057         */
058            public float getOpacity() {
059                    return opacity;
060            }
061    
062            /**
063         * Set the threshold value.
064         * @param threshold the threshold value
065         * @see #getThreshold
066         */
067            public void setThreshold( float threshold ) {
068                    this.threshold = threshold;
069            }
070            
071            /**
072         * Get the threshold value.
073         * @return the threshold value
074         * @see #setThreshold
075         */
076            public float getThreshold() {
077                    return threshold;
078            }
079            
080            /**
081         * Set the strength of the rays.
082         * @param strength the strength.
083         * @see #getStrength
084         */
085            public void setStrength( float strength ) {
086                    this.strength = strength;
087            }
088            
089            /**
090         * Get the strength of the rays.
091         * @return the strength.
092         * @see #setStrength
093         */
094            public float getStrength() {
095                    return strength;
096            }
097            
098            /**
099         * Set whether to render only the rays.
100         * @param raysOnly true to render rays only.
101         * @see #getRaysOnly
102         */
103            public void setRaysOnly(boolean raysOnly) {
104                    this.raysOnly = raysOnly;
105            }
106    
107            /**
108         * Get whether to render only the rays.
109         * @return true to render rays only.
110         * @see #setRaysOnly
111         */
112            public boolean getRaysOnly() {
113                    return raysOnly;
114            }
115    
116        /**
117         * Set the colormap to be used for the filter.
118         * @param colormap the colormap
119         * @see #getColormap
120         */
121            public void setColormap(Colormap colormap) {
122                    this.colormap = colormap;
123            }
124            
125        /**
126         * Get the colormap to be used for the filter.
127         * @return the colormap
128         * @see #setColormap
129         */
130            public Colormap getColormap() {
131                    return colormap;
132            }
133            
134        public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
135            int width = src.getWidth();
136            int height = src.getHeight();
137                    int[] pixels = new int[width];
138                    int[] srcPixels = new int[width];
139    
140            BufferedImage rays = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
141    
142                    int threshold3 = (int)(threshold*3*255);
143                    for ( int y = 0; y < height; y++ ) {
144                            getRGB( src, 0, y, width, 1, pixels );
145                            for ( int x = 0; x < width; x++ ) {
146                                    int rgb = pixels[x];
147                                    int a = rgb & 0xff000000;
148                                    int r = (rgb >> 16) & 0xff;
149                                    int g = (rgb >> 8) & 0xff;
150                                    int b = rgb & 0xff;
151                                    int l = r + g + b;
152                                    if (l < threshold3)
153                                            pixels[x] = 0xff000000;
154                                    else {
155                                            l /= 3;
156                                            pixels[x] = a | (l << 16) | (l << 8) | l;
157                                    }
158                            }
159                            setRGB( rays, 0, y, width, 1, pixels );
160                    }
161    
162                    rays = super.filter( rays, null );
163    
164                    for ( int y = 0; y < height; y++ ) {
165                            getRGB( rays, 0, y, width, 1, pixels );
166                            getRGB( src, 0, y, width, 1, srcPixels );
167                            for ( int x = 0; x < width; x++ ) {
168                                    int rgb = pixels[x];
169                                    int a = rgb & 0xff000000;
170                                    int r = (rgb >> 16) & 0xff;
171                                    int g = (rgb >> 8) & 0xff;
172                                    int b = rgb & 0xff;
173                                    
174                                    if ( colormap != null ) {
175                                            int l = r + g + b;
176                                            rgb = colormap.getColor( l * strength * (1/3f) );
177                                    } else {
178                                            r = PixelUtils.clamp((int)(r * strength));
179                                            g = PixelUtils.clamp((int)(g * strength));
180                                            b = PixelUtils.clamp((int)(b * strength));
181                                            rgb = a | (r << 16) | (g << 8) | b;
182                                    }
183    
184                                    pixels[x] = rgb;
185                            }
186                            setRGB( rays, 0, y, width, 1, pixels );
187                    }
188    
189            if ( dst == null )
190                dst = createCompatibleDestImage( src, null );
191    
192                    Graphics2D g = dst.createGraphics();
193                    if ( !raysOnly ) {
194                            g.setComposite( AlphaComposite.SrcOver );
195                            g.drawRenderedImage( src, null );
196                    }
197                    g.setComposite( MiscComposite.getInstance( MiscComposite.ADD, opacity ) );
198                    g.drawRenderedImage( rays, null );
199                    g.dispose();
200    
201            return dst;
202        }
203        
204            public String toString() {
205                    return "Stylize/Rays...";
206            }
207            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
208                    Object o;
209                    if((o=parameters.removeEL(KeyImpl.init("Colormap")))!=null)setColormap(ImageFilterUtil.toColormap(o,"Colormap"));
210                    if((o=parameters.removeEL(KeyImpl.init("Strength")))!=null)setStrength(ImageFilterUtil.toFloatValue(o,"Strength"));
211                    if((o=parameters.removeEL(KeyImpl.init("Opacity")))!=null)setOpacity(ImageFilterUtil.toFloatValue(o,"Opacity"));
212                    if((o=parameters.removeEL(KeyImpl.init("RaysOnly")))!=null)setRaysOnly(ImageFilterUtil.toBooleanValue(o,"RaysOnly"));
213                    if((o=parameters.removeEL(KeyImpl.init("Threshold")))!=null)setThreshold(ImageFilterUtil.toFloatValue(o,"Threshold"));
214                    if((o=parameters.removeEL(KeyImpl.init("Angle")))!=null)setAngle(ImageFilterUtil.toFloatValue(o,"Angle"));
215                    if((o=parameters.removeEL(KeyImpl.init("CentreX")))!=null)setCentreX(ImageFilterUtil.toFloatValue(o,"CentreX"));
216                    if((o=parameters.removeEL(KeyImpl.init("CentreY")))!=null)setCentreY(ImageFilterUtil.toFloatValue(o,"CentreY"));
217                    //if((o=parameters.removeEL(KeyImpl.init("Centre")))!=null)setCentre(ImageFilterUtil.toPoint2D(o,"Centre"));
218                    if((o=parameters.removeEL(KeyImpl.init("Distance")))!=null)setDistance(ImageFilterUtil.toFloatValue(o,"Distance"));
219                    if((o=parameters.removeEL(KeyImpl.init("Rotation")))!=null)setRotation(ImageFilterUtil.toFloatValue(o,"Rotation"));
220                    if((o=parameters.removeEL(KeyImpl.init("Zoom")))!=null)setZoom(ImageFilterUtil.toFloatValue(o,"Zoom"));
221    
222                    // check for arguments not supported
223                    if(parameters.size()>0) {
224                            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 [Colormap, Strength, Opacity, RaysOnly, Threshold, Angle, CentreX, CentreY, Centre, Distance, Rotation, Zoom]");
225                    }
226    
227                    return filter(src, dst);
228            }
229    }