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.image.*;
021import java.util.*;
022
023/**
024 * A filter which uses the alpha channel of a "mask" image to interpolate between a source and destination image.
025 */
026public class ApplyMaskFilter extends AbstractBufferedImageOp {
027        
028        private BufferedImage destination;
029        private BufferedImage maskImage;
030
031    /**
032     * Construct an ApplyMaskFIlter.
033     */
034        public ApplyMaskFilter() {
035        }
036
037    /**
038     * Construct an ApplyMaskFIlter.
039     * @param maskImage the mask image
040     * @param destination the destination image
041     */
042        public ApplyMaskFilter( BufferedImage maskImage, BufferedImage destination ) {
043                this.maskImage = maskImage;
044                this.destination = destination;
045        }
046
047    /**
048     * Set the destination image.
049     * @param destination the destination image
050     * @see #getDestination
051     */
052        public void setDestination( BufferedImage destination ) {
053                this.destination = destination;
054        }
055        
056    /**
057     * Get the destination image.
058     * @return the destination image
059     * @see #setDestination
060     */
061        public BufferedImage getDestination() {
062                return destination;
063        }
064        
065    /**
066     * Set the mask image.
067     * @param maskImage the mask image
068     * @see #getMaskImage
069     */
070        public void setMaskImage( BufferedImage maskImage ) {
071                this.maskImage = maskImage;
072        }
073        
074    /**
075     * Get the mask image.
076     * @return the mask image
077     * @see #setMaskImage
078     */
079        public BufferedImage getMaskImage() {
080                return maskImage;
081        }
082                
083    /**
084     * Interpolates between two rasters according to the alpha level of a mask raster.
085     * @param src the source raster
086     * @param dst the destination raster
087     * @param sel the mask raster
088     */
089        public static void composeThroughMask(Raster src, WritableRaster dst, Raster sel) {
090                int x = src.getMinX();
091                int y = src.getMinY();
092                int w = src.getWidth();
093                int h = src.getHeight();
094
095                int srcRGB[] = null;
096                int selRGB[] = null;
097                int dstRGB[] = null;
098
099                for ( int i = 0; i < h; i++ ) {
100                        srcRGB = src.getPixels(x, y, w, 1, srcRGB);
101                        selRGB = sel.getPixels(x, y, w, 1, selRGB);
102                        dstRGB = dst.getPixels(x, y, w, 1, dstRGB);
103
104                        int k = x;
105                        for ( int j = 0; j < w; j++ ) {
106                                int sr = srcRGB[k];
107                                int dir = dstRGB[k];
108                                int sg = srcRGB[k+1];
109                                int dig = dstRGB[k+1];
110                                int sb = srcRGB[k+2];
111                                int dib = dstRGB[k+2];
112                                int sa = srcRGB[k+3];
113                                int dia = dstRGB[k+3];
114
115                                float a = selRGB[k+3]/255f;
116                                float ac = 1-a;
117
118                                dstRGB[k] = (int)(a*sr + ac*dir); 
119                                dstRGB[k+1] = (int)(a*sg + ac*dig); 
120                                dstRGB[k+2] = (int)(a*sb + ac*dib); 
121                                dstRGB[k+3] = (int)(a*sa + ac*dia);
122                                k += 4;
123                        }
124
125                        dst.setPixels(x, y, w, 1, dstRGB);
126                        y++;
127                }
128        }
129
130    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
131        int width = src.getWidth();
132        int height = src.getHeight();
133                int type = src.getType();
134                WritableRaster srcRaster = src.getRaster();
135
136        if ( dst == null )
137            dst = createCompatibleDestImage( src, null );
138                WritableRaster dstRaster = dst.getRaster();
139
140        if ( destination != null && maskImage != null )
141                        composeThroughMask( src.getRaster(), dst.getRaster(), maskImage.getRaster() );
142
143        return dst;
144    }
145
146        public String toString() {
147                return "Keying/Key...";
148        }
149}