/* ** Copyright 2005 Huxtable.com. All rights reserved. */ package com.jhlabs.image; import java.awt.image.*; import java.awt.geom.*; public class MotionBlurFilter extends AbstractBufferedImageOp { public final static int LINEAR = 0; public final static int RADIAL = 1; public final static int ZOOM = 2; private float angle = 0.0f; // private float falloff = 1.0f; private float distance = 1.0f; private float zoom = 0.0f; private float rotation = 0.0f; private boolean wrapEdges = false; public MotionBlurFilter() { } public void setAngle( float angle ) { this.angle = angle; } public float getAngle() { return angle; } public void setDistance( float distance ) { this.distance = distance; } public float getDistance() { return distance; } public void setRotation( float rotation ) { this.rotation = rotation; } public float getRotation() { return rotation; } public void setZoom( float zoom ) { this.zoom = zoom; } public float getZoom() { return zoom; } public void setWrapEdges(boolean wrapEdges) { this.wrapEdges = wrapEdges; } public boolean getWrapEdges() { return wrapEdges; } public BufferedImage filter( BufferedImage src, BufferedImage dst ) { int width = src.getWidth(); int height = src.getHeight(); if ( dst == null ) dst = createCompatibleDestImage( src, null ); int[] inPixels = new int[width*height]; int[] outPixels = new int[width*height]; getRGB( src, 0, 0, width, height, inPixels ); // float sinAngle = (float)Math.sin(angle); // float cosAngle = (float)Math.cos(angle); // // float total; int cx = width/2; int cy = height/2; int index = 0; float imageRadius = (float)Math.sqrt( cx*cx + cy*cy ); float translateX = (float)(distance * Math.cos( angle )); float translateY = (float)(distance * -Math.sin( angle )); float maxDistance = distance + Math.abs(rotation*imageRadius) + zoom*imageRadius; int repetitions = (int)maxDistance; AffineTransform t = new AffineTransform(); Point2D.Float p = new Point2D.Float(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int a = 0, r = 0, g = 0, b = 0; int count = 0; for (int i = 0; i < repetitions; i++) { int newX = x, newY = y; float f = (float)i/repetitions; p.x = x; p.y = y; t.setToIdentity(); t.translate( cx+f*translateX, cy+f*translateY ); float s = 1-zoom*f; t.scale( s, s ); if ( rotation != 0 ) t.rotate( -rotation*f ); t.translate( -cx, -cy ); t.transform( p, p ); newX = (int)p.x; newY = (int)p.y; if (newX < 0 || newX >= width) { if ( wrapEdges ) newX = ImageMath.mod( newX, width ); else break; } if (newY < 0 || newY >= height) { if ( wrapEdges ) newY = ImageMath.mod( newY, height ); else break; } count++; int rgb = inPixels[newY*width+newX]; a += (rgb >> 24) & 0xff; r += (rgb >> 16) & 0xff; g += (rgb >> 8) & 0xff; b += rgb & 0xff; } if (count == 0) { outPixels[index] = inPixels[index]; } else { a = PixelUtils.clamp((int)(a/count)); r = PixelUtils.clamp((int)(r/count)); g = PixelUtils.clamp((int)(g/count)); b = PixelUtils.clamp((int)(b/count)); outPixels[index] = (a << 24) | (r << 16) | (g << 8) | b; } index++; } } setRGB( dst, 0, 0, width, height, inPixels ); return dst; } public String toString() { return "Blur/Motion Blur..."; } }