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.AlphaComposite; 018 import java.awt.Graphics2D; 019 import java.awt.RenderingHints; 020 import java.awt.geom.Point2D; 021 import java.awt.image.BufferedImage; 022 023 /** 024 * A filter which produces motion blur the faster, but lower-quality way. 025 */ 026 public class MotionBlurOp extends AbstractBufferedImageOp { 027 028 private float centreX = 0.5f, centreY = 0.5f; 029 private float distance; 030 private float angle; 031 private float rotation; 032 private float zoom; 033 034 /** 035 * Construct a MotionBlurOp. 036 */ 037 public MotionBlurOp() { 038 } 039 040 /** 041 * Construct a MotionBlurOp. 042 * @param distance the distance of blur. 043 * @param angle the angle of blur. 044 * @param rotation the angle of rotation. 045 * @param zoom the zoom factor. 046 */ 047 public MotionBlurOp( float distance, float angle, float rotation, float zoom ) { 048 this.distance = distance; 049 this.angle = angle; 050 this.rotation = rotation; 051 this.zoom = zoom; 052 } 053 054 /** 055 * Specifies the angle of blur. 056 * @param angle the angle of blur. 057 * @angle 058 * @see #getAngle 059 */ 060 public void setAngle( float angle ) { 061 this.angle = angle; 062 } 063 064 /** 065 * Returns the angle of blur. 066 * @return the angle of blur. 067 * @see #setAngle 068 */ 069 public float getAngle() { 070 return angle; 071 } 072 073 /** 074 * Set the distance of blur. 075 * @param distance the distance of blur. 076 * @see #getDistance 077 */ 078 public void setDistance( float distance ) { 079 this.distance = distance; 080 } 081 082 /** 083 * Get the distance of blur. 084 * @return the distance of blur. 085 * @see #setDistance 086 */ 087 public float getDistance() { 088 return distance; 089 } 090 091 /** 092 * Set the blur rotation. 093 * @param rotation the angle of rotation. 094 * @see #getRotation 095 */ 096 public void setRotation( float rotation ) { 097 this.rotation = rotation; 098 } 099 100 /** 101 * Get the blur rotation. 102 * @return the angle of rotation. 103 * @see #setRotation 104 */ 105 public float getRotation() { 106 return rotation; 107 } 108 109 /** 110 * Set the blur zoom. 111 * @param zoom the zoom factor. 112 * @see #getZoom 113 */ 114 public void setZoom( float zoom ) { 115 this.zoom = zoom; 116 } 117 118 /** 119 * Get the blur zoom. 120 * @return the zoom factor. 121 * @see #setZoom 122 */ 123 public float getZoom() { 124 return zoom; 125 } 126 127 /** 128 * Set the centre of the effect in the X direction as a proportion of the image size. 129 * @param centreX the center 130 * @see #getCentreX 131 */ 132 public void setCentreX( float centreX ) { 133 this.centreX = centreX; 134 } 135 136 /** 137 * Get the centre of the effect in the X direction as a proportion of the image size. 138 * @return the center 139 * @see #setCentreX 140 */ 141 public float getCentreX() { 142 return centreX; 143 } 144 145 /** 146 * Set the centre of the effect in the Y direction as a proportion of the image size. 147 * @param centreY the center 148 * @see #getCentreY 149 */ 150 public void setCentreY( float centreY ) { 151 this.centreY = centreY; 152 } 153 154 /** 155 * Get the centre of the effect in the Y direction as a proportion of the image size. 156 * @return the center 157 * @see #setCentreY 158 */ 159 public float getCentreY() { 160 return centreY; 161 } 162 163 /** 164 * Get the centre of the effect as a proportion of the image size. 165 * @return the center 166 * @see #setCentre 167 */ 168 public Point2D getCentre() { 169 return new Point2D.Float( centreX, centreY ); 170 } 171 172 private int log2( int n ) { 173 int m = 1; 174 int log2n = 0; 175 176 while (m < n) { 177 m *= 2; 178 log2n++; 179 } 180 return log2n; 181 } 182 183 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 184 if ( dst == null ) 185 dst = createCompatibleDestImage( src, null ); 186 BufferedImage tsrc = src; 187 float cx = src.getWidth() * centreX; 188 float cy = src.getHeight() * centreY; 189 float imageRadius = (float)Math.sqrt( cx*cx + cy*cy ); 190 float translateX = (float)(distance * Math.cos( angle )); 191 float translateY = (float)(distance * -Math.sin( angle )); 192 float scale = zoom; 193 float rotate = rotation; 194 float maxDistance = distance + Math.abs(rotation*imageRadius) + zoom*imageRadius; 195 int steps = log2((int)maxDistance); 196 197 translateX /= maxDistance; 198 translateY /= maxDistance; 199 scale /= maxDistance; 200 rotate /= maxDistance; 201 202 if ( steps == 0 ) { 203 Graphics2D g = dst.createGraphics(); 204 g.drawRenderedImage( src, null ); 205 g.dispose(); 206 return dst; 207 } 208 209 BufferedImage tmp = createCompatibleDestImage( src, null ); 210 for ( int i = 0; i < steps; i++ ) { 211 Graphics2D g = tmp.createGraphics(); 212 g.drawImage( tsrc, null, null ); 213 g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); 214 g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); 215 g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f ) ); 216 217 g.translate( cx+translateX, cy+translateY ); 218 g.scale( 1.0001+scale, 1.0001+scale ); // The .0001 works round a bug on Windows where drawImage throws an ArrayIndexOutofBoundException 219 if ( rotation != 0 ) 220 g.rotate( rotate ); 221 g.translate( -cx, -cy ); 222 223 g.drawImage( dst, null, null ); 224 g.dispose(); 225 BufferedImage ti = dst; 226 dst = tmp; 227 tmp = ti; 228 tsrc = dst; 229 230 translateX *= 2; 231 translateY *= 2; 232 scale *= 2; 233 rotate *= 2; 234 } 235 return dst; 236 } 237 238 public String toString() { 239 return "Blur/Faster Motion Blur..."; 240 } 241 }