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.Color;
018    import java.awt.image.BufferedImage;
019    
020    import railo.runtime.engine.ThreadLocalPageContext;
021    import railo.runtime.exp.FunctionException;
022    import railo.runtime.exp.PageException;
023    import railo.runtime.img.ImageUtil;
024    import railo.runtime.type.KeyImpl;
025    import railo.runtime.type.Struct;
026    import railo.runtime.type.util.CollectionUtil;
027    
028    /**
029     * An experimental filter which can be used for keying against a clean shot. Given a source image, a clean image and a destination image, 
030     * the filter replaces all pixels in the source which nearly equal the equivalent clean pixel by destination pixels.
031     */
032    public class KeyFilter extends AbstractBufferedImageOp  implements DynFiltering {
033            
034            private float hTolerance = 0;
035            private float sTolerance = 0;
036            private float bTolerance = 0;
037            private BufferedImage destination;
038            private BufferedImage cleanImage;
039    
040            public KeyFilter() {
041            }
042    
043            /**
044             * Set the hue tolerance of the image in the range 0..1.
045             * @param hTolerance the tolerance
046         * @see #getHTolerance
047             */
048            public void setHTolerance( float hTolerance ) {
049                    this.hTolerance = hTolerance;
050            }
051            
052            /**
053             * Get the hue tolerance.
054             * @return the tolerance
055         * @see #setHTolerance
056             */
057            public float getHTolerance() {
058                    return hTolerance;
059            }
060            
061            /**
062             * Set the saturation tolerance of the image in the range 0..1.
063             * @param sTolerance the tolerance
064         * @see #getSTolerance
065             */
066            public void setSTolerance( float sTolerance ) {
067                    this.sTolerance = sTolerance;
068            }
069            
070            /**
071             * Get the saturation tolerance.
072             * @return the tolerance
073         * @see #setSTolerance
074             */
075            public float getSTolerance() {
076                    return sTolerance;
077            }
078            
079            /**
080             * Set the brightness tolerance of the image in the range 0..1.
081             * @param bTolerance the tolerance
082         * @see #getBTolerance
083             */
084            public void setBTolerance( float bTolerance ) {
085                    this.bTolerance = bTolerance;
086            }
087            
088            /**
089             * Get the brightness tolerance.
090             * @return the tolerance
091         * @see #setBTolerance
092             */
093            public float getBTolerance() {
094                    return bTolerance;
095            }
096            
097        /**
098         * Set the destination image.
099         * @param destination the destination image
100         * @see #getDestination
101         */
102            public void setDestination( BufferedImage destination ) {
103                    this.destination = destination;
104            }
105            
106        /**
107         * Get the destination image.
108         * @return the destination image
109         * @see #setDestination
110         */
111            public BufferedImage getDestination() {
112                    return destination;
113            }
114            
115        /**
116         * Get the clean image.
117         * @param cleanImage the clean image
118         * @see #getCleanImage
119         */
120            public void setCleanImage( BufferedImage cleanImage ) {
121                    this.cleanImage = cleanImage;
122            }
123            
124        /**
125         * Get the clean image.
126         * @return the clean image
127         * @see #setCleanImage
128         */
129            public BufferedImage getCleanImage() {
130                    return cleanImage;
131            }
132                    
133        public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
134            int width = src.getWidth();
135            int height = src.getHeight();
136                    //int type = src.getType();
137                    //WritableRaster srcRaster = 
138                    src.getRaster();
139    
140            if ( dst == null )
141                dst = createCompatibleDestImage( src, null );
142                    //WritableRaster dstRaster = 
143            dst.getRaster();
144    
145            if ( destination != null && cleanImage != null ) {
146                float[] hsb1 = null;
147                float[] hsb2 = null;
148                int[] inPixels = null;
149                int[] outPixels = null;
150                int[] cleanPixels = null;
151                for ( int y = 0; y < height; y++ ) {
152                    inPixels = getRGB( src, 0, y, width, 1, inPixels );
153                    outPixels = getRGB( destination, 0, y, width, 1, outPixels );
154                    cleanPixels = getRGB( cleanImage, 0, y, width, 1, cleanPixels );
155                    for ( int x = 0; x < width; x++ ) {
156                        int rgb1 = inPixels[x];
157                        int out = outPixels[x];
158                        int rgb2 = cleanPixels[x];
159    
160                        int r1 = (rgb1 >> 16) & 0xff;
161                        int g1 = (rgb1 >> 8) & 0xff;
162                        int b1 = rgb1 & 0xff;
163                        int r2 = (rgb2 >> 16) & 0xff;
164                        int g2 = (rgb2 >> 8) & 0xff;
165                        int b2 = rgb2 & 0xff;
166                        hsb1 = Color.RGBtoHSB( r1, b1, g1, hsb1 );
167                        hsb2 = Color.RGBtoHSB( r2, b2, g2, hsb2 );
168    //                    int tolerance = (int)(255*tolerance);
169    //                    return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
170    
171     //                   if ( PixelUtils.nearColors( in, clean, (int)(255*tolerance) ) )
172                        if ( Math.abs( hsb1[0] - hsb2[0] ) < hTolerance && Math.abs( hsb1[1] - hsb2[1] ) < sTolerance && Math.abs( hsb1[2] - hsb2[2] ) < bTolerance )
173                            inPixels[x] = out;
174                        else
175                            inPixels[x] = rgb1;
176                    }
177                    setRGB( dst, 0, y, width, 1, inPixels );
178                }
179            }
180    
181            return dst;
182        }
183    
184            public String toString() {
185                    return "Keying/Key...";
186            }
187            public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
188                    Object o;
189                    if((o=parameters.removeEL(KeyImpl.init("HTolerance")))!=null)setHTolerance(ImageFilterUtil.toFloatValue(o,"HTolerance"));
190                    if((o=parameters.removeEL(KeyImpl.init("STolerance")))!=null)setSTolerance(ImageFilterUtil.toFloatValue(o,"STolerance"));
191                    if((o=parameters.removeEL(KeyImpl.init("BTolerance")))!=null)setBTolerance(ImageFilterUtil.toFloatValue(o,"BTolerance"));
192                    if((o=parameters.removeEL(KeyImpl.init("CleanImage")))!=null)setCleanImage(ImageFilterUtil.toBufferedImage(o,"CleanImage"));
193                    if((o=parameters.removeEL(KeyImpl.init("destination")))!=null)setDestination(ImageFilterUtil.toBufferedImage(o,"destination"));
194    
195                    // check for arguments not supported
196                    if(parameters.size()>0) {
197                            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 [HTolerance, STolerance, BTolerance, CleanImage]");
198                    }
199    
200                    return filter(src, dst);
201            }
202    }