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.lang.reflect.*;
022import java.beans.*;
023import java.util.*;
024
025/**
026 * A filter which uses another filter to perform a transition.
027 * e.g. to create a blur transition, you could write: new TransitionFilter( new BoxBlurFilter(), "radius", 0, 100 );
028 */
029public class TransitionFilter extends AbstractBufferedImageOp {
030        
031        private float transition = 0;
032        private BufferedImage destination;
033    private String property;
034    private Method method;
035
036    /**
037     * The filter used for the transition.
038     */
039    protected BufferedImageOp filter;
040
041    /**
042     * The start value for the filter property.
043     */
044    protected float minValue;
045
046    /**
047     * The end value for the filter property.
048     */
049    protected float maxValue;
050
051    /**
052     * Construct a TransitionFilter.
053     */
054        private TransitionFilter() {
055        }
056
057    /**
058     * Construct a TransitionFilter.
059     * @param filter the filter to use
060     * @param property the filter property which is changed over the transition
061     * @param minValue the start value for the filter property
062     * @param maxValue the end value for the filter property
063     */
064        public TransitionFilter( BufferedImageOp filter, String property, float minValue, float maxValue ) {
065                this.filter = filter;
066                this.property = property;
067                this.minValue = minValue;
068                this.maxValue = maxValue;
069                try {
070                        BeanInfo info = Introspector.getBeanInfo( filter.getClass() );
071            PropertyDescriptor[] pds = info.getPropertyDescriptors();
072            for ( int i = 0; i < pds.length; i++ ) {
073                PropertyDescriptor pd = pds[i];
074                if ( property.equals( pd.getName() ) ) {
075                    method = pd.getWriteMethod();
076                    break;
077                }
078            }
079            if ( method == null )
080                throw new IllegalArgumentException( "No such property in object: "+property );
081                }
082                catch (IntrospectionException e) {
083            throw new IllegalArgumentException( e.toString() );
084                }
085        }
086
087        /**
088         * Set the transition of the image in the range 0..1.
089         * @param transition the transition
090     * @min-value 0
091     * @max-value 1
092     * @see #getTransition
093         */
094        public void setTransition( float transition ) {
095                this.transition = transition;
096        }
097        
098        /**
099         * Get the transition of the image.
100         * @return the transition
101     * @see #setTransition
102         */
103        public float getTransition() {
104                return transition;
105        }
106        
107    /**
108     * Set the destination image.
109     * @param destination the destination image
110     * @see #getDestination
111     */
112        public void setDestination( BufferedImage destination ) {
113                this.destination = destination;
114        }
115        
116    /**
117     * Get the destination image.
118     * @return the destination image
119     * @see #setDestination
120     */
121        public BufferedImage getDestination() {
122                return destination;
123        }
124        
125/*
126        public void setFilter( BufferedImageOp filter ) {
127                this.filter = filter;
128        }
129        
130        public int getFilter() {
131                return filter;
132        }
133*/
134        
135    /**
136     * Prepare the filter for the transiton at a given time.
137     * The default implementation sets the given filter property, but you could override this method to make other changes.
138     * @param transition the transition time in the range 0 - 1
139     */
140        public void prepareFilter( float transition ) {
141        try {
142            method.invoke( filter, new Object[] { new Float( transition ) } );
143        }
144        catch ( Exception e ) {
145            throw new IllegalArgumentException("Error setting value for property: "+property);
146        }
147        }
148        
149    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
150        if ( dst == null )
151            dst = createCompatibleDestImage( src, null );
152                if ( destination == null )
153                        return dst;
154
155                float itransition = 1-transition;
156
157                Graphics2D g = dst.createGraphics();
158                if ( transition != 1 ) {
159            float t = minValue + transition * ( maxValue-minValue );
160                        prepareFilter( t );
161            g.drawImage( src, filter, 0, 0 );
162                }
163                if ( transition != 0 ) {
164            g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, transition ) );
165            float t = minValue + itransition * ( maxValue-minValue );
166                        prepareFilter( t );
167            g.drawImage( destination, filter, 0, 0 );
168                }
169                g.dispose();
170
171        return dst;
172    }
173
174        public String toString() {
175                return "Transitions/Transition...";
176        }
177}