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}