Frames | No Frames |
1: /* AreaAveragingScaleFilter.java -- Java class for filtering images 2: Copyright (C) 1999,2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt.image; 40: 41: /** 42: * This filter should produce images which do not have image artifacts 43: * like broken lines which were originally unbroken. The cost is of 44: * course speed. Using bi-linear interpolation here against 4 pixel 45: * points should give the desired results although Sun does not 46: * specify what the exact algorithm should be. 47: * <br> 48: * 49: * @author C. Brian Jones (cbj@gnu.org) 50: */ 51: public class AreaAveragingScaleFilter extends ReplicateScaleFilter 52: { 53: /** 54: * Construct an instance of <code>AreaAveragingScaleFilter</code> which 55: * should be used in conjunction with a <code>FilteredImageSource</code> 56: * object. 57: * 58: * @param width the width of the destination image 59: * @param height the height of the destination image 60: */ 61: public AreaAveragingScaleFilter(int width, int height) { 62: super(width, height); 63: } 64: 65: /** 66: * The <code>ImageProducer</code> should call this method with a 67: * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, 68: * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, 69: * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the 70: * <code>ImageConsumer</code> interface. 71: * <br> 72: * FIXME - more than likely Sun's implementation desires 73: * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here 74: * in order to assure that mask is part of the hints added to 75: * the consumer. 76: * 77: * @param flags a bit mask of hints 78: * @see ImageConsumer 79: */ 80: public void setHints(int flags) 81: { 82: if (consumer != null) 83: consumer.setHints(flags); 84: } 85: 86: /** 87: * This function delivers a rectangle of pixels where any 88: * pixel(m,n) is stored in the array as a <code>byte</code> at 89: * index (n * scansize + m + offset). 90: * 91: * @param x the x coordinate of the rectangle 92: * @param y the y coordinate of the rectangle 93: * @param w the width of the rectangle 94: * @param h the height of the rectangle 95: * @param model the <code>ColorModel</code> used to translate the pixels 96: * @param pixels the array of pixel values 97: * @param offset the index of the first pixels in the <code>pixels</code> array 98: * @param scansize the width to use in extracting pixels from the <code>pixels</code> array 99: */ 100: public void setPixels(int x, int y, int w, int h, 101: ColorModel model, byte[] pixels, int offset, int scansize) 102: { 103: double rx = ((double) srcWidth) / destWidth; 104: double ry = ((double) srcHeight) / destHeight; 105: 106: int destScansize = (int) Math.round(scansize / rx); 107: 108: byte[] destPixels = averagePixels(x, y, w, h, 109: model, pixels, offset, scansize, 110: rx, ry, destScansize); 111: 112: if (consumer != null) 113: consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), 114: (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), 115: model, destPixels, 0, destScansize); 116: } 117: 118: /** 119: * This function delivers a rectangle of pixels where any 120: * pixel(m,n) is stored in the array as an <code>int</code> at 121: * index (n * scansize + m + offset). 122: * 123: * @param x the x coordinate of the rectangle 124: * @param y the y coordinate of the rectangle 125: * @param w the width of the rectangle 126: * @param h the height of the rectangle 127: * @param model the <code>ColorModel</code> used to translate the pixels 128: * @param pixels the array of pixel values 129: * @param offset the index of the first pixels in the <code>pixels</code> array 130: * @param scansize the width to use in extracting pixels from the <code>pixels</code> array 131: */ 132: public void setPixels(int x, int y, int w, int h, 133: ColorModel model, int[] pixels, int offset, int scansize) 134: { 135: double rx = ((double) srcWidth) / destWidth; 136: double ry = ((double) srcHeight) / destHeight; 137: 138: int destScansize = (int) Math.round(scansize / rx); 139: 140: int[] destPixels = averagePixels(x, y, w, h, 141: model, pixels, offset, scansize, 142: rx, ry, destScansize); 143: 144: if (consumer != null) 145: consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), 146: (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), 147: model, destPixels, 0, destScansize); 148: } 149: 150: /** 151: * This is a really terrible implementation, 152: * since it uses the nearest-neighbor method. This filter is rarely used though. 153: * 154: * @param srcx, srcy - Source rectangle upper-left corner 155: * @param srcw, srch - Source rectangle width and height 156: * @param model - Pixel color model 157: * @param srcPixels - Source pixel data. 158: * @param srcOffset - Starting offset into the source pixel data array. 159: * @param srcScansize - Source array scanline size. 160: * @param rx,ry - Scaling factor. 161: * @param destScansize - Destination array scanline size. 162: */ 163: private byte[] averagePixels(int srcx, int srcy, int srcw, int srch, 164: ColorModel model, byte[] srcPixels, 165: int srcOffset, int srcScansize, 166: double rx, double ry, int destScansize) 167: { 168: int destW = (int) Math.ceil(srcw/rx); 169: int destH = (int) Math.ceil(srch/ry); 170: byte[] destPixels = new byte[ destW * destH ]; 171: int sx, sy; 172: 173: int w = (int)Math.ceil(rx); 174: int h = (int)Math.ceil(ry); 175: 176: for(int x = 0; x < destW; x++) 177: for(int y = 0; y < destH; y++) 178: { 179: sx = (int) (x * rx); 180: sy = (int) (y * ry); 181: 182: int r,g,b,a; 183: r = g = b = a = 0; 184: 185: for(int i = 0; i < w; i++) 186: { 187: for(int j = 0; j < h; j++) 188: { 189: int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; 190: r += model.getRed(srcPixels[ idx ]); 191: g += model.getGreen(srcPixels[ idx ]); 192: b += model.getBlue(srcPixels[ idx ]); 193: a += model.getAlpha(srcPixels[ idx ]); 194: } 195: } 196: 197: r = r / (w * h); 198: g = g / (w * h); 199: b = b / (w * h); 200: a = a / (w * h); 201: 202: // Does this really work? 203: destPixels[x + destScansize*y] = (byte)model.getDataElement 204: (new int[]{r, g, b, a}, 0); 205: } 206: 207: return destPixels; 208: } 209: 210: /** 211: * This is a really terrible implementation, 212: * since it uses the nearest-neighbor method. This filter is rarely used though. 213: * 214: * @param srcx, srcy - Source rectangle upper-left corner 215: * @param srcw, srch - Source rectangle width and height 216: * @param model - Pixel color model 217: * @param srcPixels - Source pixel data. 218: * @param srcOffset - Starting offset into the source pixel data array. 219: * @param srcScansize - Source array scanline size. 220: * @param rx,ry - Scaling factor. 221: * @param destScansize - Destination array scanline size. 222: */ 223: private int[] averagePixels(int srcx, int srcy, int srcw, int srch, 224: ColorModel model, int[] srcPixels, 225: int srcOffset, int srcScansize, 226: double rx, double ry, int destScansize) 227: { 228: int destW = (int) Math.ceil(srcw/rx); 229: int destH = (int) Math.ceil(srch/ry); 230: int[] destPixels = new int[ destW * destH ]; 231: int sx, sy; 232: 233: int w = (int)Math.ceil(rx); 234: int h = (int)Math.ceil(ry); 235: 236: for(int x = 0; x < destW; x++) 237: for(int y = 0; y < destH; y++) 238: { 239: sx = (int) (x * rx); 240: sy = (int) (y * ry); 241: 242: int r,g,b,a; 243: r = g = b = a = 0; 244: 245: for(int i = 0; i < w; i++) 246: { 247: for(int j = 0; j < h; j++) 248: { 249: int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; 250: r += model.getRed(srcPixels[ idx ]); 251: g += model.getGreen(srcPixels[ idx ]); 252: b += model.getBlue(srcPixels[ idx ]); 253: a += model.getAlpha(srcPixels[ idx ]); 254: } 255: } 256: 257: r = r / (w * h); 258: g = g / (w * h); 259: b = b / (w * h); 260: a = a / (w * h); 261: 262: destPixels[x + destScansize*y] = model.getDataElement 263: (new int[]{r, g, b, a}, 0); 264: } 265: 266: return destPixels; 267: } 268: }