001/* 002 * $Id: StackBlurFilter.java 4082 2011-11-15 18:39:43Z kschaefe $ 003 * 004 * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). 005 * 006 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, 007 * Santa Clara, California 95054, U.S.A. All rights reserved. 008 * 009 * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> 010 * All rights reserved. 011 * 012 * Redistribution and use in source and binary forms, with or without 013 * modification, are permitted provided that the following conditions 014 * are met: 015 * 1. Redistributions of source code must retain the above copyright 016 * notice, this list of conditions and the following disclaimer. 017 * 2. Redistributions in binary form must reproduce the above copyright 018 * notice, this list of conditions and the following disclaimer in the 019 * documentation and/or other materials provided with the distribution. 020 * 3. The name of the author may not be used to endorse or promote products 021 * derived from this software without specific prior written permission. 022 * 023 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 024 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 025 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 026 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 028 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 032 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 033 */ 034 035package org.jdesktop.swingx.image; 036 037import java.awt.image.BufferedImage; 038 039import org.jdesktop.swingx.util.GraphicsUtilities; 040 041/** 042 * <p>A stack blur filter can be used to create an approximation of a 043 * Gaussian blur. The approximation is controlled by the number of times the 044 * {@link org.jdesktop.swingx.image.FastBlurFilter} is applied onto the source 045 * picture. The default number of iterations, 3, provides a decent compromise 046 * between speed and rendering quality.</p> 047 * <p>The force of the blur can be controlled with a radius and the 048 * default radius is 3. Since the blur clamps values on the edges of the 049 * source picture, you might need to provide a picture with empty borders 050 * to avoid artifacts at the edges. The performance of this filter are 051 * independent from the radius.</p> 052 * 053 * @author Romain Guy <romain.guy@mac.com> 054*/ 055public class StackBlurFilter extends AbstractFilter { 056 private final int radius; 057 private final int iterations; 058 059 /** 060 * <p>Creates a new blur filter with a default radius of 3 and 3 iterations.</p> 061 */ 062 public StackBlurFilter() { 063 this(3, 3); 064 } 065 066 /** 067 * <p>Creates a new blur filter with the specified radius and 3 iterations. 068 * If the radius is lower than 1, a radius of 1 will be used automatically.</p> 069 * 070 * @param radius the radius, in pixels, of the blur 071 */ 072 public StackBlurFilter(int radius) { 073 this(radius, 3); 074 } 075 076 /** 077 * <p>Creates a new blur filter with the specified radius. If the radius 078 * is lower than 1, a radius of 1 will be used automatically. The number 079 * of iterations controls the approximation to a Gaussian blur. If the 080 * number of iterations is lower than 1, one iteration will be used 081 * automatically.</p> 082 * 083 * @param radius the radius, in pixels, of the blur 084 * @param iterations the number of iterations to approximate a Gaussian blur 085 */ 086 public StackBlurFilter(int radius, int iterations) { 087 if (radius < 1) { 088 radius = 1; 089 } 090 if (iterations < 1) { 091 iterations = 1; 092 } 093 094 this.radius = radius; 095 this.iterations = iterations; 096 } 097 098 /** 099 * <p>Returns the effective radius of the stack blur. If the radius of the 100 * blur is 1 and the stack iterations count is 3, then the effective blur 101 * radius is 1 * 3 = 3.</p> 102 * @return the number of iterations times the blur radius 103 */ 104 public int getEffectiveRadius() { 105 return getIterations() * getRadius(); 106 } 107 108 /** 109 * <p>Returns the radius used by this filter, in pixels.</p> 110 * 111 * @return the radius of the blur 112 */ 113 public int getRadius() { 114 return radius; 115 } 116 117 /** 118 * <p>Returns the number of iterations used to approximate a Gaussian 119 * blur.</p> 120 * 121 * @return the number of iterations used by this blur 122 */ 123 public int getIterations() { 124 return iterations; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 public BufferedImage filter(BufferedImage src, BufferedImage dst) { 132 int width = src.getWidth(); 133 int height = src.getHeight(); 134 135 if (dst == null) { 136 dst = createCompatibleDestImage(src, null); 137 } 138 139 int[] srcPixels = new int[width * height]; 140 int[] dstPixels = new int[width * height]; 141 142 GraphicsUtilities.getPixels(src, 0, 0, width, height, srcPixels); 143 for (int i = 0; i < iterations; i++) { 144 // horizontal pass 145 FastBlurFilter.blur(srcPixels, dstPixels, width, height, radius); 146 // vertical pass 147 FastBlurFilter.blur(dstPixels, srcPixels, height, width, radius); 148 } 149 // the result is now stored in srcPixels due to the 2nd pass 150 GraphicsUtilities.setPixels(dst, 0, 0, width, height, srcPixels); 151 152 return dst; 153 } 154}