diff options
author | Sven de Marothy <sven@physto.se> | 2006-05-03 19:31:45 +0000 |
---|---|---|
committer | Sven de Marothy <sven@physto.se> | 2006-05-03 19:31:45 +0000 |
commit | ec589bc27900b16dfbaedb4a5ee06a182a511b2b (patch) | |
tree | 921c2704e085a31d0959f36996fa6a5c6d6585de /java | |
parent | caadf15c1007cc40bcee332871592a358e284deb (diff) | |
download | classpath-ec589bc27900b16dfbaedb4a5ee06a182a511b2b.tar.gz |
2006-05-03 Sven de Marothy <sven@physto.se>
PR 24023, 24701
* java/awt/Image.java:
(getScaledInstance): Default to AreaAveraging for "smooth",
don't thrown an error on illegal flag values.
* java/awt/image/AreaAveragingScaleFilter.java: Implement.
Diffstat (limited to 'java')
-rw-r--r-- | java/awt/Image.java | 15 | ||||
-rw-r--r-- | java/awt/image/AreaAveragingScaleFilter.java | 291 |
2 files changed, 222 insertions, 84 deletions
diff --git a/java/awt/Image.java b/java/awt/Image.java index 93c2c4790..6ade302a1 100644 --- a/java/awt/Image.java +++ b/java/awt/Image.java @@ -166,6 +166,8 @@ public abstract class Image * loading will be produced according to the hints of the algorithm * requested. If either the width or height is non-positive, it is adjusted * to preserve the original aspect ratio. + * If an illegal value of <code>flags</code> is passed, + * the default algorithm is used. * * @param width the width of the scaled image * @param height the height of the scaled image @@ -183,18 +185,15 @@ public abstract class Image ImageFilter filter; switch (flags) { - case SCALE_DEFAULT: - case SCALE_FAST: - case SCALE_REPLICATE: - filter = new ReplicateScaleFilter(width, height); - break; case SCALE_AREA_AVERAGING: + case SCALE_SMOOTH: filter = new AreaAveragingScaleFilter(width, height); break; - case SCALE_SMOOTH: - throw new Error("SCALE_SMOOTH: not implemented"); + case SCALE_DEFAULT: + case SCALE_FAST: + case SCALE_REPLICATE: default: - throw new Error("Unknown flag or not implemented: " + flags); + filter = new ReplicateScaleFilter(width, height); } ImageProducer producer = new FilteredImageSource(getSource(), filter); diff --git a/java/awt/image/AreaAveragingScaleFilter.java b/java/awt/image/AreaAveragingScaleFilter.java index 6333ce9e7..44d5cec9d 100644 --- a/java/awt/image/AreaAveragingScaleFilter.java +++ b/java/awt/image/AreaAveragingScaleFilter.java @@ -1,5 +1,5 @@ /* AreaAveragingScaleFilter.java -- Java class for filtering images - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,86 +45,225 @@ package java.awt.image; * points should give the desired results although Sun does not * specify what the exact algorithm should be. * <br> - * FIXME: Currently this filter does nothing and needs to be implemented. * * @author C. Brian Jones (cbj@gnu.org) */ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { - /** - * Construct an instance of <code>AreaAveragingScaleFilter</code> which - * should be used in conjunction with a <code>FilteredImageSource</code> - * object. - * - * @param width the width of the destination image - * @param height the height of the destination image - */ - public AreaAveragingScaleFilter(int width, int height) { - super(width, height); - } - - /** - * The <code>ImageProducer</code> should call this method with a - * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, - * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, - * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the - * <code>ImageConsumer</code> interface. - * <br> - * FIXME - more than likely Sun's implementation desires - * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here - * in order to assure that mask is part of the hints added to - * the consumer. - * - * @param flags a bit mask of hints - * @see ImageConsumer - */ - public void setHints(int flags) - { - if (consumer != null) - consumer.setHints(flags); - } - - /** - * This function delivers a rectangle of pixels where any - * pixel(m,n) is stored in the array as a <code>byte</code> at - * index (n * scansize + m + offset). - * - * @param x the x coordinate of the rectangle - * @param y the y coordinate of the rectangle - * @param w the width of the rectangle - * @param h the height of the rectangle - * @param model the <code>ColorModel</code> used to translate the pixels - * @param pixels the array of pixel values - * @param offset the index of the first pixels in the <code>pixels</code> array - * @param scansize the width to use in extracting pixels from the <code>pixels</code> array - */ - public void setPixels(int x, int y, int w, int h, - ColorModel model, byte[] pixels, int offset, int scansize) - { - if (consumer != null) - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); - } - - /** - * This function delivers a rectangle of pixels where any - * pixel(m,n) is stored in the array as an <code>int</code> at - * index (n * scansize + m + offset). - * - * @param x the x coordinate of the rectangle - * @param y the y coordinate of the rectangle - * @param w the width of the rectangle - * @param h the height of the rectangle - * @param model the <code>ColorModel</code> used to translate the pixels - * @param pixels the array of pixel values - * @param offset the index of the first pixels in the <code>pixels</code> array - * @param scansize the width to use in extracting pixels from the <code>pixels</code> array - */ - public void setPixels(int x, int y, int w, int h, - ColorModel model, int[] pixels, int offset, int scansize) - { - if (consumer != null) - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); - } + /** + * Construct an instance of <code>AreaAveragingScaleFilter</code> which + * should be used in conjunction with a <code>FilteredImageSource</code> + * object. + * + * @param width the width of the destination image + * @param height the height of the destination image + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + /** + * The <code>ImageProducer</code> should call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the + * <code>ImageConsumer</code> interface. + * <br> + * FIXME - more than likely Sun's implementation desires + * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here + * in order to assure that mask is part of the hints added to + * the consumer. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + if (consumer != null) + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + byte[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + int[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param dstScansize - Destination array scanline size. + */ + private byte[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, byte[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + byte[] destPixels = new byte[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + // Does this really work? + destPixels[x + destScansize*y] = (byte)model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param dstScansize - Destination array scanline size. + */ + private int[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, int[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + int[] destPixels = new int[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + destPixels[x + destScansize*y] = model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } } |