001 /* AreaAveragingScaleFilter.java -- Java class for filtering images 002 Copyright (C) 1999,2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath 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 for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.awt.image; 040 041 /** 042 * This filter should produce images which do not have image artifacts 043 * like broken lines which were originally unbroken. The cost is of 044 * course speed. Using bi-linear interpolation here against 4 pixel 045 * points should give the desired results although Sun does not 046 * specify what the exact algorithm should be. 047 * <br> 048 * 049 * @author C. Brian Jones (cbj@gnu.org) 050 */ 051 public class AreaAveragingScaleFilter extends ReplicateScaleFilter 052 { 053 /** 054 * Construct an instance of <code>AreaAveragingScaleFilter</code> which 055 * should be used in conjunction with a <code>FilteredImageSource</code> 056 * object. 057 * 058 * @param width the width of the destination image 059 * @param height the height of the destination image 060 */ 061 public AreaAveragingScaleFilter(int width, int height) { 062 super(width, height); 063 } 064 065 /** 066 * The <code>ImageProducer</code> should call this method with a 067 * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, 068 * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, 069 * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the 070 * <code>ImageConsumer</code> interface. 071 * <br> 072 * FIXME - more than likely Sun's implementation desires 073 * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here 074 * in order to assure that mask is part of the hints added to 075 * the consumer. 076 * 077 * @param flags a bit mask of hints 078 * @see ImageConsumer 079 */ 080 public void setHints(int flags) 081 { 082 if (consumer != null) 083 consumer.setHints(flags); 084 } 085 086 /** 087 * This function delivers a rectangle of pixels where any 088 * pixel(m,n) is stored in the array as a <code>byte</code> at 089 * index (n * scansize + m + offset). 090 * 091 * @param x the x coordinate of the rectangle 092 * @param y the y coordinate of the rectangle 093 * @param w the width of the rectangle 094 * @param h the height of the rectangle 095 * @param model the <code>ColorModel</code> used to translate the pixels 096 * @param pixels the array of pixel values 097 * @param offset the index of the first pixels in the <code>pixels</code> array 098 * @param scansize the width to use in extracting pixels from the <code>pixels</code> array 099 */ 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 }