Source for java.awt.image.RescaleOp

   1: /* Copyright (C) 2004  Free Software Foundation
   2: 
   3: This file is part of GNU Classpath.
   4: 
   5: GNU Classpath is free software; you can redistribute it and/or modify
   6: it under the terms of the GNU General Public License as published by
   7: the Free Software Foundation; either version 2, or (at your option)
   8: any later version.
   9: 
  10: GNU Classpath is distributed in the hope that it will be useful, but
  11: WITHOUT ANY WARRANTY; without even the implied warranty of
  12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13: General Public License for more details.
  14: 
  15: You should have received a copy of the GNU General Public License
  16: along with GNU Classpath; see the file COPYING.  If not, write to the
  17: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18: 02110-1301 USA.
  19: 
  20: Linking this library statically or dynamically with other modules is
  21: making a combined work based on this library.  Thus, the terms and
  22: conditions of the GNU General Public License cover the whole
  23: combination.
  24: 
  25: As a special exception, the copyright holders of this library give you
  26: permission to link this library with independent modules to produce an
  27: executable, regardless of the license terms of these independent
  28: modules, and to copy and distribute the resulting executable under
  29: terms of your choice, provided that you also meet, for each linked
  30: independent module, the terms and conditions of the license of that
  31: module.  An independent module is a module which is not derived from
  32: or based on this library.  If you modify this library, you may extend
  33: this exception to your version of the library, but you are not
  34: obligated to do so.  If you do not wish to do so, delete this
  35: exception statement from your version. */
  36: 
  37: 
  38: package java.awt.image;
  39: 
  40: import java.awt.RenderingHints;
  41: import java.awt.geom.Point2D;
  42: import java.awt.geom.Rectangle2D;
  43: import java.util.Arrays;
  44: 
  45: /**
  46:  * @author Jerry Quinn (jlquinn@optonline.net)
  47:  */
  48: public class RescaleOp implements BufferedImageOp, RasterOp
  49: {
  50:   private float[] scale;
  51:   private float[] offsets;
  52:   private RenderingHints hints = null;
  53:   
  54:   public RescaleOp(float[] scaleFactors,
  55:            float[] offsets,
  56:            RenderingHints hints)
  57:   {
  58:     this.scale = scaleFactors;
  59:     this.offsets = offsets;
  60:     this.hints = hints;
  61:   }
  62:   
  63:   public RescaleOp(float scaleFactor,
  64:            float offset,
  65:            RenderingHints hints)
  66:   {
  67:     scale = new float[]{ scaleFactor };
  68:     offsets = new float[]{offset};
  69:     this.hints = hints;
  70:   }
  71: 
  72:   public final float[] getScaleFactors(float[] scaleFactors)
  73:   {
  74:     if (scaleFactors == null)
  75:       scaleFactors = new float[scale.length];
  76:     System.arraycopy(scale, 0, scaleFactors, 0, scale.length);
  77:     return scaleFactors;
  78:   }
  79: 
  80:   public final float[] getOffsets(float[] offsets)
  81:   {
  82:     if (offsets == null)
  83:       offsets = new float[this.offsets.length];
  84:     System.arraycopy(this.offsets, 0, offsets, 0, this.offsets.length);
  85:     return offsets;
  86:   }
  87: 
  88:   public final int getNumFactors()
  89:   {
  90:     return scale.length;
  91:   }
  92: 
  93:   /* (non-Javadoc)
  94:    * @see java.awt.image.BufferedImageOp#getRenderingHints()
  95:    */
  96:   public RenderingHints getRenderingHints()
  97:   {
  98:     return hints;
  99:   }
 100: 
 101:   /* (non-Javadoc)
 102:    * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage)
 103:    */
 104:   public final BufferedImage filter(BufferedImage src, BufferedImage dst)
 105:   {
 106:     // TODO Make sure premultiplied alpha is handled correctly.
 107:     // TODO See that color conversion is handled.
 108:     // TODO figure out how to use rendering hints.
 109:     if (scale.length != offsets.length)
 110:       throw new IllegalArgumentException();
 111: 
 112:     ColorModel scm = src.getColorModel();
 113:     if (dst == null) dst = createCompatibleDestImage(src, null);
 114: 
 115:     WritableRaster wsrc = src.getRaster();
 116:     WritableRaster wdst = dst.getRaster();
 117:     
 118:     // Share constant across colors except alpha
 119:     if (scale.length == 1 || scale.length == scm.getNumColorComponents())
 120:       {
 121:     // Construct a raster that doesn't include an alpha band.
 122:     int[] subbands = new int[scm.getNumColorComponents()];
 123:     for (int i=0; i < subbands.length; i++) subbands[i] = i;
 124:     wsrc = 
 125:       wsrc.createWritableChild(wsrc.minX, wsrc.minY, wsrc.width, wsrc.height,
 126:                    wsrc.minX, wsrc.minY, subbands);
 127:       }
 128:     // else all color bands
 129: 
 130:     filter(wsrc, wdst);
 131:     return dst;
 132:   }
 133: 
 134:   /* (non-Javadoc)
 135:    * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster)
 136:    */
 137:   public final WritableRaster filter(Raster src, WritableRaster dest)
 138:   {
 139:     if (dest == null) dest = src.createCompatibleWritableRaster();
 140: 
 141:     // Required sanity checks
 142:     if (src.numBands != dest.numBands || scale.length != offsets.length)
 143:       throw new IllegalArgumentException();
 144:     if (scale.length != 1 && scale.length != src.numBands)
 145:       throw new IllegalArgumentException();
 146: 
 147:     // Create scaling arrays if needed
 148:     float[] lscale = scale;
 149:     float[] loff = offsets;
 150:     if (scale.length == 1)
 151:       {
 152:     lscale = new float[src.numBands];
 153:     Arrays.fill(lscale, scale[0]);
 154:     loff = new float[src.numBands];
 155:     Arrays.fill(loff, offsets[0]);
 156:       }
 157: 
 158:     // TODO The efficiency here can be improved for various data storage
 159:     // patterns, aka SampleModels.
 160:     float[] pixel = new float[src.numBands];
 161:     for (int y = src.minY; y < src.height + src.minY; y++)
 162:       for (int x = src.minX; x < src.width + src.minX; x++)
 163:     {
 164:       src.getPixel(x, y, pixel);
 165:       for (int b = 0; b < src.numBands; b++)
 166:         pixel[b] = pixel[b] * lscale[b] + loff[b];
 167:       dest.setPixel(x, y, pixel);
 168:     }
 169:     return dest;
 170:   }
 171: 
 172:   /* (non-Javadoc)
 173:    * @see java.awt.image.BufferedImageOp#createCompatibleDestImage(java.awt.image.BufferedImage, java.awt.image.ColorModel)
 174:    */
 175:   public BufferedImage createCompatibleDestImage(BufferedImage src,
 176:                          ColorModel dstCM)
 177:   {
 178:     if (dstCM == null) dstCM = src.getColorModel();
 179:     WritableRaster wr = src.getRaster().createCompatibleWritableRaster();
 180:     BufferedImage image
 181:       = new BufferedImage(dstCM, wr, src.isPremultiplied, null);
 182:     return image;
 183:   }
 184: 
 185:   /* (non-Javadoc)
 186:    * @see java.awt.image.RasterOp#createCompatibleDestRaster(java.awt.image.Raster)
 187:    */
 188:   public WritableRaster createCompatibleDestRaster(Raster src)
 189:   {
 190:     return src.createCompatibleWritableRaster();
 191:   }
 192:   
 193:   /* (non-Javadoc)
 194:    * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage)
 195:    */
 196:   public final Rectangle2D getBounds2D(BufferedImage src)
 197:   {
 198:     return src.getRaster().getBounds();
 199:   }
 200: 
 201:   /* (non-Javadoc)
 202:    * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster)
 203:    */
 204:   public final Rectangle2D getBounds2D(Raster src)
 205:   {
 206:     return src.getBounds();
 207:   }
 208: 
 209:   /* (non-Javadoc)
 210:    * @see java.awt.image.BufferedImageOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D)
 211:    */
 212:   public final Point2D getPoint2D(Point2D src, Point2D dst) {
 213:     if (dst == null) dst = (Point2D) src.clone();
 214:     else dst.setLocation(src);
 215:     return dst;
 216:   }
 217: 
 218: }