/* ** Copyright 2005 Huxtable.com. All rights reserved. */ package com.jhlabs.image; import java.awt.Color; import java.awt.image.BufferedImage; import java.awt.image.Kernel; /** * A filter which applies Gaussian blur to an image. This is a subclass of ConvolveFilter * which simply creates a kernel with a Gaussian distribution for blurring. * * This is a copy and slightly modified version of the GaussianFilter written by Jerry Huxtable */ public class GaussianGlowFilter extends ConvolveFilter { static final long serialVersionUID = 5377089073023183684L; protected float radius; protected Kernel kernel; private Color glow = Color.white; /** * Construct a Gaussian filter */ public GaussianGlowFilter() { this(2); } /** * Construct a Gaussian filter * @param radius blur radius in pixels */ public GaussianGlowFilter(float radius) { setRadius(radius); } public GaussianGlowFilter(float radius, Color glow) { this(radius); this.glow = glow; } /** * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take. * @param radius the radius of the blur in pixels. */ public void setRadius(float radius) { this.radius = radius; kernel = makeKernel(radius); } /** * Get the radius of the kernel. * @return the radius */ public float getRadius() { return radius; } 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]; src.getRGB( 0, 0, width, height, inPixels, 0, width ); convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, CLAMP_EDGES, glow); convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, CLAMP_EDGES, glow); dst.setRGB( 0, 0, width, height, inPixels, 0, width ); return dst; } public static void convolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction, Color glow) { float[] matrix = kernel.getKernelData( null ); int cols = kernel.getWidth(); int cols2 = cols/2; for (int y = 0; y < height; y++) { int index = y; int ioffset = y*width; for (int x = 0; x < width; x++) { float r = 0, g = 0, b = 0, a = 0; int moffset = cols2; for (int col = -cols2; col <= cols2; col++) { float f = matrix[moffset+col]; if (f != 0) { int ix = x+col; if ( ix < 0 ) { if ( edgeAction == CLAMP_EDGES ) ix = 0; else if ( edgeAction == WRAP_EDGES ) ix = (x+width) % width; } else if ( ix >= width) { if ( edgeAction == CLAMP_EDGES ) ix = width-1; else if ( edgeAction == WRAP_EDGES ) ix = (x+width) % width; } int rgb = inPixels[ioffset+ix]; // only apply the matrix to the alpha channel. a += f * ((rgb >> 24) & 0xff); // set the glow color to get rid of the dark described on // http://www.jhlabs.com/ip/blurring.html under Alpha Channels r=glow.getRed(); g=glow.getGreen(); b=glow.getBlue(); } } // TODO not sure about this. Multiply by 4 so that we have a bigger glow. // There is probably a function to get a better glow effect. int ia=Math.min((int)(a*4), 255); int ir = PixelUtils.clamp((int)(r+0.5)); int ig = PixelUtils.clamp((int)(g+0.5)); int ib = PixelUtils.clamp((int)(b+0.5)); outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib; index += height; } } } /** * Make a Gaussian blur kernel. */ public static Kernel makeKernel(float radius) { int r = (int)Math.ceil(radius); int rows = r*2+1; float[] matrix = new float[rows]; float sigma = radius/3; float sigma22 = 2*sigma*sigma; float sigmaPi2 = 2*ImageMath.PI*sigma; float sqrtSigmaPi2 = (float)Math.sqrt(sigmaPi2); float radius2 = radius*radius; float total = 0; int index = 0; for (int row = -r; row <= r; row++) { float distance = row*row; if (distance > radius2) matrix[index] = 0; else matrix[index] = (float)Math.exp(-(distance)/sigma22) / sqrtSigmaPi2; total += matrix[index]; index++; } for (int i = 0; i < rows; i++) matrix[i] /= total; return new Kernel(rows, 1, matrix); } public String toString() { return "Blur/Gaussian Blur..."; } }