001/*
002Copyright 2006 Jerry Huxtable
003
004Licensed under the Apache License, Version 2.0 (the "License");
005you may not use this file except in compliance with the License.
006You may obtain a copy of the License at
007
008   http://www.apache.org/licenses/LICENSE-2.0
009
010Unless required by applicable law or agreed to in writing, software
011distributed under the License is distributed on an "AS IS" BASIS,
012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013See the License for the specific language governing permissions and
014limitations under the License.
015*/
016
017package com.jhlabs.image;
018
019import java.awt.*;
020import java.awt.geom.*;
021import java.awt.image.*;
022import com.jhlabs.composite.*;
023
024/**
025 * A filter which produces the effect of light rays shining out of an image.
026 */
027public class RaysFilter extends MotionBlurOp {
028
029    private float opacity = 1.0f;
030    private float threshold = 0.0f;
031    private float strength = 0.5f;
032        private boolean raysOnly = false;
033        private Colormap colormap;
034
035    public RaysFilter() {
036        }
037        
038        /**
039     * Set the opacity of the rays.
040     * @param opacity the opacity.
041     * @see #getOpacity
042     */
043        public void setOpacity(float opacity) {
044                this.opacity = opacity;
045        }
046
047        /**
048     * Get the opacity of the rays.
049     * @return the opacity.
050     * @see #setOpacity
051     */
052        public float getOpacity() {
053                return opacity;
054        }
055
056        /**
057     * Set the threshold value.
058     * @param threshold the threshold value
059     * @see #getThreshold
060     */
061        public void setThreshold( float threshold ) {
062                this.threshold = threshold;
063        }
064        
065        /**
066     * Get the threshold value.
067     * @return the threshold value
068     * @see #setThreshold
069     */
070        public float getThreshold() {
071                return threshold;
072        }
073        
074        /**
075     * Set the strength of the rays.
076     * @param strength the strength.
077     * @see #getStrength
078     */
079        public void setStrength( float strength ) {
080                this.strength = strength;
081        }
082        
083        /**
084     * Get the strength of the rays.
085     * @return the strength.
086     * @see #setStrength
087     */
088        public float getStrength() {
089                return strength;
090        }
091        
092        /**
093     * Set whether to render only the rays.
094     * @param raysOnly true to render rays only.
095     * @see #getRaysOnly
096     */
097        public void setRaysOnly(boolean raysOnly) {
098                this.raysOnly = raysOnly;
099        }
100
101        /**
102     * Get whether to render only the rays.
103     * @return true to render rays only.
104     * @see #setRaysOnly
105     */
106        public boolean getRaysOnly() {
107                return raysOnly;
108        }
109
110    /**
111     * Set the colormap to be used for the filter.
112     * @param colormap the colormap
113     * @see #getColormap
114     */
115        public void setColormap(Colormap colormap) {
116                this.colormap = colormap;
117        }
118        
119    /**
120     * Get the colormap to be used for the filter.
121     * @return the colormap
122     * @see #setColormap
123     */
124        public Colormap getColormap() {
125                return colormap;
126        }
127        
128    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
129        int width = src.getWidth();
130        int height = src.getHeight();
131                int[] pixels = new int[width];
132                int[] srcPixels = new int[width];
133
134        BufferedImage rays = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
135
136                int threshold3 = (int)(threshold*3*255);
137                for ( int y = 0; y < height; y++ ) {
138                        getRGB( src, 0, y, width, 1, pixels );
139                        for ( int x = 0; x < width; x++ ) {
140                                int rgb = pixels[x];
141                                int a = rgb & 0xff000000;
142                                int r = (rgb >> 16) & 0xff;
143                                int g = (rgb >> 8) & 0xff;
144                                int b = rgb & 0xff;
145                                int l = r + g + b;
146                                if (l < threshold3)
147                                        pixels[x] = 0xff000000;
148                                else {
149                                        l /= 3;
150                                        pixels[x] = a | (l << 16) | (l << 8) | l;
151                                }
152                        }
153                        setRGB( rays, 0, y, width, 1, pixels );
154                }
155
156                rays = super.filter( rays, null );
157
158                for ( int y = 0; y < height; y++ ) {
159                        getRGB( rays, 0, y, width, 1, pixels );
160                        getRGB( src, 0, y, width, 1, srcPixels );
161                        for ( int x = 0; x < width; x++ ) {
162                                int rgb = pixels[x];
163                                int a = rgb & 0xff000000;
164                                int r = (rgb >> 16) & 0xff;
165                                int g = (rgb >> 8) & 0xff;
166                                int b = rgb & 0xff;
167                                
168                                if ( colormap != null ) {
169                                        int l = r + g + b;
170                                        rgb = colormap.getColor( l * strength * (1/3f) );
171                                } else {
172                                        r = PixelUtils.clamp((int)(r * strength));
173                                        g = PixelUtils.clamp((int)(g * strength));
174                                        b = PixelUtils.clamp((int)(b * strength));
175                                        rgb = a | (r << 16) | (g << 8) | b;
176                                }
177
178                                pixels[x] = rgb;
179                        }
180                        setRGB( rays, 0, y, width, 1, pixels );
181                }
182
183        if ( dst == null )
184            dst = createCompatibleDestImage( src, null );
185
186                Graphics2D g = dst.createGraphics();
187                if ( !raysOnly ) {
188                        g.setComposite( AlphaComposite.SrcOver );
189                        g.drawRenderedImage( src, null );
190                }
191                g.setComposite( MiscComposite.getInstance( MiscComposite.ADD, opacity ) );
192                g.drawRenderedImage( rays, null );
193                g.dispose();
194
195        return dst;
196    }
197    
198        public String toString() {
199                return "Stylize/Rays...";
200        }
201}