001: /*
002: * @(#)AreaAveragingScaleFilter.java 1.12 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt.image;
029:
030: import java.awt.image.ImageConsumer;
031: import java.awt.image.ColorModel;
032: import java.util.Hashtable;
033: import java.awt.Rectangle;
034:
035: /**
036: * An ImageFilter class for scaling images using a simple area averaging
037: * algorithm that produces smoother results than the nearest neighbor
038: * algorithm.
039: * This class extends the basic ImageFilter Class to scale an existing
040: * image and provide a source for a new image containing the resampled
041: * image. The pixels in the source image are blended to produce pixels
042: * for an image of the specified size. The blending process is analogous
043: * to scaling up the source image to a multiple of the destination size
044: * using pixel replication and then scaling it back down to the destination
045: * size by simply averaging all the pixels in the supersized image that
046: * fall within a given pixel of the destination image. If the data from
047: * the source is not delivered in TopDownLeftRight order then the filter
048: * will back off to a simple pixel replication behavior and utilize the
049: * requestTopDownLeftRightResend() method to refilter the pixels in a
050: * better way at the end.
051: * It is meant to be used in conjunction with a FilteredImageSource
052: * object to produce scaled versions of existing images.
053: *
054: * @see FilteredImageSource
055: * @see ReplicateImageFilter
056: * @see ImageFilter
057: *
058: * @version 1.8 08/19/02
059: * @author Jim Graham
060: */
061: public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
062: private static final ColorModel rgbmodel = ColorModel
063: .getRGBdefault();
064: private static final int neededHints = (TOPDOWNLEFTRIGHT | COMPLETESCANLINES);
065: private boolean passthrough;
066: private float reds[], greens[], blues[], alphas[];
067: private int savedy;
068: private int savedyrem;
069:
070: /**
071: * Constructs an AreaAveragingScaleFilter that scales the pixels from
072: * its source Image as specified by the width and height parameters.
073: * @param width the target width to scale the image
074: * @param height the target height to scale the image
075: */
076: public AreaAveragingScaleFilter(int width, int height) {
077: super (width, height);
078: }
079:
080: /**
081: * Detect if the data is being delivered with the necessary hints
082: * to allow the averaging algorithm to do its work.
083: * @see ImageConsumer#setHints
084: */
085: public void setHints(int hints) {
086: passthrough = ((hints & neededHints) != neededHints);
087: super .setHints(hints);
088: }
089:
090: private void makeAccumBuffers() {
091: reds = new float[destWidth];
092: greens = new float[destWidth];
093: blues = new float[destWidth];
094: alphas = new float[destWidth];
095: }
096:
097: private int[] calcRow() {
098: float mult = ((float) srcWidth) * srcHeight;
099: if (outpixbuf == null || !(outpixbuf instanceof int[])) {
100: outpixbuf = new int[destWidth];
101: }
102: int[] outpix = (int[]) outpixbuf;
103: for (int x = 0; x < destWidth; x++) {
104: int a = Math.round(alphas[x] / mult);
105: int r = Math.round(reds[x] / mult);
106: int g = Math.round(greens[x] / mult);
107: int b = Math.round(blues[x] / mult);
108: if (a < 0) {
109: a = 0;
110: } else if (a > 255) {
111: a = 255;
112: }
113: if (r < 0) {
114: r = 0;
115: } else if (r > 255) {
116: r = 255;
117: }
118: if (g < 0) {
119: g = 0;
120: } else if (g > 255) {
121: g = 255;
122: }
123: if (b < 0) {
124: b = 0;
125: } else if (b > 255) {
126: b = 255;
127: }
128: outpix[x] = (a << 24 | r << 16 | g << 8 | b);
129: }
130: return outpix;
131: }
132:
133: private void accumPixels(int x, int y, int w, int h,
134: ColorModel model, Object pixels, int off, int scansize) {
135: if (reds == null) {
136: makeAccumBuffers();
137: }
138: int sy = y;
139: int syrem = destHeight;
140: int dy, dyrem;
141: if (sy == 0) {
142: dy = 0;
143: dyrem = 0;
144: } else {
145: dy = savedy;
146: dyrem = savedyrem;
147: }
148: while (sy < y + h) {
149: int amty;
150: if (dyrem == 0) {
151: for (int i = 0; i < destWidth; i++) {
152: alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
153: }
154: dyrem = srcHeight;
155: }
156: if (syrem < dyrem) {
157: amty = syrem;
158: } else {
159: amty = dyrem;
160: }
161: int sx = 0;
162: int dx = 0;
163: int sxrem = 0;
164: int dxrem = srcWidth;
165: float a = 0f, r = 0f, g = 0f, b = 0f;
166: while (sx < w) {
167: if (sxrem == 0) {
168: sxrem = destWidth;
169: int rgb;
170: if (pixels instanceof byte[]) {
171: rgb = ((byte[]) pixels)[off + sx] & 0xff;
172: } else {
173: rgb = ((int[]) pixels)[off + sx];
174: }
175: rgb = model.getRGB(rgb);
176: a = rgb >>> 24;
177: r = (rgb >> 16) & 0xff;
178: g = (rgb >> 8) & 0xff;
179: b = rgb & 0xff;
180: }
181: int amtx;
182: if (sxrem < dxrem) {
183: amtx = sxrem;
184: } else {
185: amtx = dxrem;
186: }
187: float mult = ((float) amtx) * amty;
188: alphas[dx] += mult * a;
189: reds[dx] += mult * r;
190: greens[dx] += mult * g;
191: blues[dx] += mult * b;
192: if ((sxrem -= amtx) == 0) {
193: sx++;
194: }
195: if ((dxrem -= amtx) == 0) {
196: dx++;
197: dxrem = srcWidth;
198: }
199: }
200: if ((dyrem -= amty) == 0) {
201: int outpix[] = calcRow();
202: do {
203: consumer.setPixels(0, dy, destWidth, 1, rgbmodel,
204: outpix, 0, destWidth);
205: dy++;
206: } while ((syrem -= amty) >= amty && amty == srcHeight);
207: } else {
208: syrem -= amty;
209: }
210: if (syrem == 0) {
211: syrem = destHeight;
212: sy++;
213: off += scansize;
214: }
215: }
216: savedyrem = dyrem;
217: savedy = dy;
218: }
219:
220: /**
221: * Combine the components for the delivered byte pixels into the
222: * accumulation arrays and send on any averaged data for rows of
223: * pixels that are complete. If the correct hints were not
224: * specified in the setHints call then relay the work to our
225: * superclass which is capable of scaling pixels regardless of
226: * the delivery hints.
227: * @see ReplicateScaleFilter
228: */
229: public void setPixels(int x, int y, int w, int h, ColorModel model,
230: byte pixels[], int off, int scansize) {
231: if (passthrough) {
232: super .setPixels(x, y, w, h, model, pixels, off, scansize);
233: } else {
234: accumPixels(x, y, w, h, model, pixels, off, scansize);
235: }
236: }
237:
238: /**
239: * Combine the components for the delivered int pixels into the
240: * accumulation arrays and send on any averaged data for rows of
241: * pixels that are complete. If the correct hints were not
242: * specified in the setHints call then relay the work to our
243: * superclass which is capable of scaling pixels regardless of
244: * the delivery hints.
245: * @see ReplicateScaleFilter
246: */
247: public void setPixels(int x, int y, int w, int h, ColorModel model,
248: int pixels[], int off, int scansize) {
249: if (passthrough) {
250: super.setPixels(x, y, w, h, model, pixels, off, scansize);
251: } else {
252: accumPixels(x, y, w, h, model, pixels, off, scansize);
253: }
254: }
255: }
|