FileDocCategorySizeDatePackage
AreaAveragingScaleFilter.javaAPI DocJava SE 5 API8696Fri Aug 26 14:56:52 BST 2005java.awt.image

AreaAveragingScaleFilter

public class AreaAveragingScaleFilter extends ReplicateScaleFilter
An ImageFilter class for scaling images using a simple area averaging algorithm that produces smoother results than the nearest neighbor algorithm.

This class extends the basic ImageFilter Class to scale an existing image and provide a source for a new image containing the resampled image. The pixels in the source image are blended to produce pixels for an image of the specified size. The blending process is analogous to scaling up the source image to a multiple of the destination size using pixel replication and then scaling it back down to the destination size by simply averaging all the pixels in the supersized image that fall within a given pixel of the destination image. If the data from the source is not delivered in TopDownLeftRight order then the filter will back off to a simple pixel replication behavior and utilize the requestTopDownLeftRightResend() method to refilter the pixels in a better way at the end.

It is meant to be used in conjunction with a FilteredImageSource object to produce scaled versions of existing images. Due to implementation dependencies, there may be differences in pixel values of an image filtered on different platforms.

see
FilteredImageSource
see
ReplicateScaleFilter
see
ImageFilter
version
1.15 12/19/03
author
Jim Graham

Fields Summary
private static final ColorModel
rgbmodel
private static final int
neededHints
private boolean
passthrough
private float[]
reds
private float[]
greens
private float[]
blues
private float[]
alphas
private int
savedy
private int
savedyrem
Constructors Summary
public AreaAveragingScaleFilter(int width, int height)
Constructs an AreaAveragingScaleFilter that scales the pixels from its source Image as specified by the width and height parameters.

param
width the target width to scale the image
param
height the target height to scale the image


                                              
         
	super(width, height);
    
Methods Summary
private voidaccumPixels(int x, int y, int w, int h, java.awt.image.ColorModel model, java.lang.Object pixels, int off, int scansize)

	if (reds == null) {
	    makeAccumBuffers();
	}
	int sy = y;
	int syrem = destHeight;
	int dy, dyrem;
	if (sy == 0) {
	    dy = 0;
	    dyrem = 0;
	} else {
	    dy = savedy;
	    dyrem = savedyrem;
	}
	while (sy < y + h) {
	    int amty;
	    if (dyrem == 0) {
		for (int i = 0; i < destWidth; i++) {
		    alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
		}
		dyrem = srcHeight;
	    }
	    if (syrem < dyrem) {
		amty = syrem;
	    } else {
		amty = dyrem;
	    }
	    int sx = 0;
	    int dx = 0;
	    int sxrem = 0;
	    int dxrem = srcWidth;
	    float a = 0f, r = 0f, g = 0f, b = 0f;
	    while (sx < w) {
		if (sxrem == 0) {
		    sxrem = destWidth;
		    int rgb;
		    if (pixels instanceof byte[]) {
			rgb = ((byte[]) pixels)[off + sx] & 0xff;
		    } else {
			rgb = ((int[]) pixels)[off + sx];
		    }
                    // getRGB() always returns non-premultiplied components
		    rgb = model.getRGB(rgb);
		    a = rgb >>> 24;
		    r = (rgb >> 16) & 0xff;
		    g = (rgb >>  8) & 0xff;
                    b = rgb & 0xff;
                    // premultiply the components if necessary
                    if (a != 255.0f) {
                        float ascale = a / 255.0f;
                        r *= ascale;
                        g *= ascale;
                        b *= ascale;
                    }
		}
		int amtx;
		if (sxrem < dxrem) {
		    amtx = sxrem;
		} else {
		    amtx = dxrem;
		}
		float mult = ((float) amtx) * amty;
		alphas[dx] += mult * a;
		reds[dx] += mult * r;
		greens[dx] += mult * g;
		blues[dx] += mult * b;
		if ((sxrem -= amtx) == 0) {
		    sx++;
		}
		if ((dxrem -= amtx) == 0) {
		    dx++;
		    dxrem = srcWidth;
		}
	    }
	    if ((dyrem -= amty) == 0) {
		int outpix[] = calcRow();
		do {
		    consumer.setPixels(0, dy, destWidth, 1,
				       rgbmodel, outpix, 0, destWidth);
		    dy++;
		} while ((syrem -= amty) >= amty && amty == srcHeight);
	    } else {
		syrem -= amty;
	    }
	    if (syrem == 0) {
		syrem = destHeight;
		sy++;
		off += scansize;
	    }
	}
	savedyrem = dyrem;
	savedy = dy;
    
private int[]calcRow()

	float origmult = ((float) srcWidth) * srcHeight;
	if (outpixbuf == null || !(outpixbuf instanceof int[])) {
	    outpixbuf = new int[destWidth];
	}
	int[] outpix = (int[]) outpixbuf;
	for (int x = 0; x < destWidth; x++) {
            float mult = origmult;
	    int a = Math.round(alphas[x] / mult);
            if (a <= 0) {
                a = 0;
            } else if (a >= 255) {
                a = 255;
            } else {
                // un-premultiply the components (by modifying mult here, we
                // are effectively doing the divide by mult and divide by
                // alpha in the same step)
                mult = alphas[x] / 255;
            }
	    int r = Math.round(reds[x] / mult);
	    int g = Math.round(greens[x] / mult);
	    int b = Math.round(blues[x] / mult);
	    if (r < 0) {r = 0;} else if (r > 255) {r = 255;}
	    if (g < 0) {g = 0;} else if (g > 255) {g = 255;}
	    if (b < 0) {b = 0;} else if (b > 255) {b = 255;}
	    outpix[x] = (a << 24 | r << 16 | g << 8 | b);
	}
	return outpix;
    
private voidmakeAccumBuffers()

	reds = new float[destWidth];
	greens = new float[destWidth];
	blues = new float[destWidth];
	alphas = new float[destWidth];
    
public voidsetHints(int hints)
Detect if the data is being delivered with the necessary hints to allow the averaging algorithm to do its work.

Note: This method is intended to be called by the ImageProducer of the Image whose pixels are being filtered. Developers using this class to filter pixels from an image should avoid calling this method directly since that operation could interfere with the filtering operation.

see
ImageConsumer#setHints

	passthrough = ((hints & neededHints) != neededHints);
	super.setHints(hints);
    
public voidsetPixels(int x, int y, int w, int h, java.awt.image.ColorModel model, byte[] pixels, int off, int scansize)
Combine the components for the delivered byte pixels into the accumulation arrays and send on any averaged data for rows of pixels that are complete. If the correct hints were not specified in the setHints call then relay the work to our superclass which is capable of scaling pixels regardless of the delivery hints.

Note: This method is intended to be called by the ImageProducer of the Image whose pixels are being filtered. Developers using this class to filter pixels from an image should avoid calling this method directly since that operation could interfere with the filtering operation.

see
ReplicateScaleFilter

	if (passthrough) {
	    super.setPixels(x, y, w, h, model, pixels, off, scansize);
	} else {
	    accumPixels(x, y, w, h, model, pixels, off, scansize);
	}
    
public voidsetPixels(int x, int y, int w, int h, java.awt.image.ColorModel model, int[] pixels, int off, int scansize)
Combine the components for the delivered int pixels into the accumulation arrays and send on any averaged data for rows of pixels that are complete. If the correct hints were not specified in the setHints call then relay the work to our superclass which is capable of scaling pixels regardless of the delivery hints.

Note: This method is intended to be called by the ImageProducer of the Image whose pixels are being filtered. Developers using this class to filter pixels from an image should avoid calling this method directly since that operation could interfere with the filtering operation.

see
ReplicateScaleFilter

	if (passthrough) {
	    super.setPixels(x, y, w, h, model, pixels, off, scansize);
	} else {
	    accumPixels(x, y, w, h, model, pixels, off, scansize);
	}