/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ /* * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package lucee.runtime.img.filter;import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; /** * A filter which produces motion blur the faster, but lower-quality way. */ public class MotionBlurOp extends AbstractBufferedImageOp { private float centreX = 0.5f, centreY = 0.5f; private float distance; private float angle; private float rotation; private float zoom; /** * Construct a MotionBlurOp. */ public MotionBlurOp() { } /** * Construct a MotionBlurOp. * @param distance the distance of blur. * @param angle the angle of blur. * @param rotation the angle of rotation. * @param zoom the zoom factor. */ public MotionBlurOp( float distance, float angle, float rotation, float zoom ) { this.distance = distance; this.angle = angle; this.rotation = rotation; this.zoom = zoom; } /** * Specifies the angle of blur. * @param angle the angle of blur. * @angle * @see #getAngle */ public void setAngle( float angle ) { this.angle = angle; } /** * Returns the angle of blur. * @return the angle of blur. * @see #setAngle */ public float getAngle() { return angle; } /** * Set the distance of blur. * @param distance the distance of blur. * @see #getDistance */ public void setDistance( float distance ) { this.distance = distance; } /** * Get the distance of blur. * @return the distance of blur. * @see #setDistance */ public float getDistance() { return distance; } /** * Set the blur rotation. * @param rotation the angle of rotation. * @see #getRotation */ public void setRotation( float rotation ) { this.rotation = rotation; } /** * Get the blur rotation. * @return the angle of rotation. * @see #setRotation */ public float getRotation() { return rotation; } /** * Set the blur zoom. * @param zoom the zoom factor. * @see #getZoom */ public void setZoom( float zoom ) { this.zoom = zoom; } /** * Get the blur zoom. * @return the zoom factor. * @see #setZoom */ public float getZoom() { return zoom; } /** * Set the centre of the effect in the X direction as a proportion of the image size. * @param centreX the center * @see #getCentreX */ public void setCentreX( float centreX ) { this.centreX = centreX; } /** * Get the centre of the effect in the X direction as a proportion of the image size. * @return the center * @see #setCentreX */ public float getCentreX() { return centreX; } /** * Set the centre of the effect in the Y direction as a proportion of the image size. * @param centreY the center * @see #getCentreY */ public void setCentreY( float centreY ) { this.centreY = centreY; } /** * Get the centre of the effect in the Y direction as a proportion of the image size. * @return the center * @see #setCentreY */ public float getCentreY() { return centreY; } /** * Get the centre of the effect as a proportion of the image size. * @return the center * @see #setCentre */ public Point2D getCentre() { return new Point2D.Float( centreX, centreY ); } private int log2( int n ) { int m = 1; int log2n = 0; while (m < n) { m *= 2; log2n++; } return log2n; } @Override public BufferedImage filter( BufferedImage src, BufferedImage dst ) { if ( dst == null ) dst = createCompatibleDestImage( src, null ); BufferedImage tsrc = src; float cx = src.getWidth() * centreX; float cy = src.getHeight() * centreY; float imageRadius = (float)Math.sqrt( cx*cx + cy*cy ); float translateX = (float)(distance * Math.cos( angle )); float translateY = (float)(distance * -Math.sin( angle )); float scale = zoom; float rotate = rotation; float maxDistance = distance + Math.abs(rotation*imageRadius) + zoom*imageRadius; int steps = log2((int)maxDistance); translateX /= maxDistance; translateY /= maxDistance; scale /= maxDistance; rotate /= maxDistance; if ( steps == 0 ) { Graphics2D g = dst.createGraphics(); g.drawRenderedImage( src, null ); g.dispose(); return dst; } BufferedImage tmp = createCompatibleDestImage( src, null ); for ( int i = 0; i < steps; i++ ) { Graphics2D g = tmp.createGraphics(); g.drawImage( tsrc, null, null ); g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR ); g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f ) ); g.translate( cx+translateX, cy+translateY ); g.scale( 1.0001+scale, 1.0001+scale ); // The .0001 works round a bug on Windows where drawImage throws an ArrayIndexOutofBoundException if ( rotation != 0 ) g.rotate( rotate ); g.translate( -cx, -cy ); g.drawImage( dst, null, null ); g.dispose(); BufferedImage ti = dst; dst = tmp; tmp = ti; tsrc = dst; translateX *= 2; translateY *= 2; scale *= 2; rotate *= 2; } return dst; } @Override public String toString() { return "Blur/Faster Motion Blur..."; } }