Source for javax.imageio.IIOParam

   1: /* IIOParam.java --
   2:    Copyright (C) 2004  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 javax.imageio;
  40: 
  41: import java.awt.Point;
  42: import java.awt.Rectangle;
  43: 
  44: /**
  45:  * An IIOParam stores parameters used when encoding or decoding image
  46:  * streams.  ImageReadParam and ImageWriteParam extend this abstract
  47:  * base class.
  48:  *
  49:  * IIOParams allow control over how source pixels converted into
  50:  * destination pixels.  This conversion can take place between a
  51:  * stream and in-memory image data, when an image reader is doing the
  52:  * conversion, or a writer can be doing the conversion from an
  53:  * in-memory source to a stream destination.
  54:  *
  55:  * An image reader can be restricted to only read from a given region;
  56:  * likewise a writer can be restricted to only write output to a given
  57:  * region.
  58:  *
  59:  * For image readers and writers, IIOParam supports image pixelation
  60:  * -- where the input image is approximated by the output image using
  61:  * larger-sized pixel blocks.  For example: FIXME
  62:  *
  63:  * IIOParams can control how pixels are combined into larger blocks
  64:  * using sub-sampling matrices.  For example: FIXME
  65:  *
  66:  * They can also control which source bands are read and written; this
  67:  * example reads the RGBA (red, green, blue, transparency) data from a
  68:  * PNG image and outputs just the red and transparency bands: FIXME
  69:  *
  70:  * @author Thomas Fitzsimmons (fitzsim@redhat.com)
  71:  * @author Michael Koch (konqueror@gmx.de)
  72:  */
  73: public abstract class IIOParam
  74: {
  75:   /**
  76:    * The controller called by this IIOParam to retrieve parameters.
  77:    */
  78:   protected IIOParamController controller = null;
  79: 
  80:   /**
  81:    * The default controller called by this IIOParam to retrieve
  82:    * parameters.
  83:    */
  84:   protected IIOParamController defaultController = null;
  85: 
  86:   /**
  87:    * The offset in the destination where the upper-left
  88:    * decoded/encoded pixel should be located.
  89:    */
  90:   protected Point destinationOffset = new Point(0, 0);
  91: 
  92:   /**
  93:    * Sets the output colour type when writing or the destination image
  94:    * type when reading.
  95:    */
  96:   protected ImageTypeSpecifier destinationType = null;
  97: 
  98:   /**
  99:    * An array indicating which source bands will be used or null.
 100:    */
 101:   protected int[] sourceBands = null;
 102: 
 103:   /**
 104:    * The source pixel region or null.
 105:    */
 106:   protected Rectangle sourceRegion = null;
 107: 
 108:   /**
 109:    * Sample every sourceXSubsampling'th pixel in the source image when
 110:    * pixelating the destination image in the horizontal direction.
 111:    */
 112:   protected int sourceXSubsampling = 1;
 113: 
 114:   /**
 115:    * Sample every sourceYSubsampling'th pixel in the source image when
 116:    * pixelating the destination image in the vertical direction.
 117:    */
 118:   protected int sourceYSubsampling = 1;
 119: 
 120:   /**
 121:    * Start sampling at this horizontal offset within the source region
 122:    * when pixelating the destination image in the horizontal
 123:    * direction.
 124:    */
 125:   protected int subsamplingXOffset = 0;
 126: 
 127:   /**
 128:    * Start sampling at this vertical offset within the source region
 129:    * when pixelating the destination image in the vertical direction.
 130:    */
 131:   protected int subsamplingYOffset = 0;
 132: 
 133:   /**
 134:    * Indicates whether or not the controller has been explicitly set
 135:    * to null.
 136:    */
 137:   private boolean no_controller = false;
 138: 
 139:   /**
 140:    * Constructs an IIOParam object.
 141:    */
 142:   protected IIOParam()
 143:   {
 144:   }
 145: 
 146:   /**
 147:    * Activates the parameter controller by calling its activate method
 148:    * and passing it this IIOParam.  A true return value indicates that
 149:    * this IIOParam's values are ready for the next read or write
 150:    * operation.  A return value of false means that this IIOParam's
 151:    * values have not been affected because the controller operations
 152:    * were cancelled.
 153:    *
 154:    * @return true if parameters were successfully set, false if
 155:    * parameters were not changed
 156:    */
 157:   public boolean activateController()
 158:   {
 159:     if (controller == null)
 160:       {
 161:     if (defaultController == null || no_controller)
 162:       return false;
 163:     else
 164:       return defaultController.activate (this);
 165:       }
 166:     else
 167:       return controller.activate(this);
 168:   }
 169: 
 170:   /**
 171:    * Retrieve the currently set controller if one has been set, or the
 172:    * default controller, or null if the controller has been explicitly
 173:    * set to null.
 174:    *
 175:    * @return the currently used controller or null
 176:    */  
 177:   public IIOParamController getController()
 178:   {
 179:     return controller == null ?
 180:       (no_controller ? null : defaultController) : controller;
 181:   }
 182: 
 183:   /**
 184:    * Retrieve the default controller regardless of whether or not a
 185:    * non-default controller has been set.  The default controller may
 186:    * be null.
 187:    *
 188:    * @return the default controller or null
 189:    */
 190:   public IIOParamController getDefaultController()
 191:   {
 192:     return defaultController;
 193:   }
 194: 
 195:   /**
 196:    * Retrieve the offset in the destination where the upper-left
 197:    * decoded/encoded pixel should be located. (0, 0) by default.
 198:    *
 199:    * @return the destination offset
 200:    */
 201:   public Point getDestinationOffset()
 202:   {
 203:     return destinationOffset;
 204:   }
 205: 
 206:   /**
 207:    * Retrieve the currently set image-type specifier or null if none
 208:    * has been set.
 209:    *
 210:    * @return the current image-type specifier or null
 211:    */
 212:   public ImageTypeSpecifier getDestinationType()
 213:   {
 214:     return destinationType;
 215:   }
 216: 
 217:   /**
 218:    * Retrieve the current source band values or null if source band
 219:    * values have not been set.
 220:    *
 221:    * The returned array is a copy of this IIOParam's source band
 222:    * array.
 223:    *
 224:    * @return the current set of source band values or null
 225:    */
 226:   public int[] getSourceBands()
 227:   {
 228:     if (sourceBands == null)
 229:       return null;
 230: 
 231:     int[] sourceBandsCopy = new int[sourceBands.length];
 232:     System.arraycopy (sourceBands, 0, sourceBandsCopy, 0, sourceBands.length);
 233:     return sourceBandsCopy;
 234:   }
 235: 
 236:   /**
 237:    * Retrieve the source rectangle from which pixels should be read or
 238:    * null if no source region has been set.
 239:    *
 240:    * @return the current source region or null
 241:    */
 242:   public Rectangle getSourceRegion()
 243:   {
 244:     return sourceRegion;
 245:   }
 246: 
 247:   /**
 248:    * Retrieve the number of pixel columns to advance before taking a
 249:    * pixel sample.
 250:    *
 251:    * @return the horizontal sub-sampling interval
 252:    */
 253:   public int getSourceXSubsampling()
 254:   {
 255:     return sourceXSubsampling;
 256:   }
 257:   
 258:   /**
 259:    * Retrieve the number of pixel rows to advance before taking a
 260:    * pixel sample.
 261:    *
 262:    * @return the vertical sub-sampling interval
 263:    */
 264:   public int getSourceYSubsampling()
 265:   {
 266:     return sourceYSubsampling;
 267:   }
 268: 
 269:   /**
 270:    * Retrieve the number of pixel columns to advance before taking any
 271:    * pixel samples.
 272:    *
 273:    * @return the horizontal sub-sampling offset
 274:    */
 275:   public int getSubsamplingXOffset()
 276:   {
 277:     return subsamplingXOffset;
 278:   }
 279: 
 280:   /**
 281:    * Retrieve the number of pixel rows to advance before taking any
 282:    * pixel samples.
 283:    *
 284:    * @return the vertical sub-sampling offset
 285:    */
 286:   public int getSubsamplingYOffset()
 287:   {
 288:     return subsamplingYOffset;
 289:   }
 290: 
 291:   /**
 292:    * Check if a non-null controller is currently available.
 293:    *
 294:    * @return true if getController returns a non-null value, false if
 295:    * getController returns null
 296:    */
 297:   public boolean hasController()
 298:   {
 299:     return getController() != null;
 300:   }
 301: 
 302:   /**
 303:    * Sets the controller for this IIOParam.  This is the controller
 304:    * that will be activated when activateController is called.  The
 305:    * argument controller overrides this IIOParam's default controller.
 306:    * If the argument is null then no controller will be set, not even
 307:    * the default one.  To reset the default controller call
 308:    * setController(getDefaultController()).
 309:    *
 310:    * @param controller the controller to set or null
 311:    */
 312:   public void setController(IIOParamController controller)
 313:   {
 314:     if (controller == defaultController)
 315:       {
 316:     this.controller = null;
 317:     no_controller = false;
 318:       }
 319:     else
 320:       {
 321:     no_controller = (controller == null);
 322:     this.controller = controller;
 323:       }
 324:   }
 325: 
 326:   /**
 327:    * Set the destination image type.
 328:    *
 329:    * If this value is set on an image reader then its read method will
 330:    * return a new BufferedImage of the specified destination type.  In
 331:    * this case any destination image set using setDestination() is
 332:    * ignored.
 333:    *
 334:    * If this is set on an image writer then the destination type
 335:    * affects only the colour model of the destination image.  The
 336:    * destination type's SampleModel is ignored.  The destination
 337:    * type's ColorModel will override the source image's colour model.
 338:    *
 339:    * @param destinationType the sample and colour models of the
 340:    * destination image
 341:    */
 342:   public void setDestinationType (ImageTypeSpecifier destinationType)
 343:   {
 344:     this.destinationType = destinationType;
 345:   }
 346: 
 347:   /**
 348:    * Specify the destination pixel offset.  Image writers are only
 349:    * affected by this setting when ImageWriter.replacePixels is called
 350:    * in which case the offset is into the region of pixels being
 351:    * changed.
 352:    *
 353:    * @param destinationOffset the offset where pixel writing should
 354:    * begin
 355:    */
 356:   public void setDestinationOffset(Point destinationOffset)
 357:   {
 358:     if (destinationOffset == null)
 359:       throw new IllegalArgumentException("destinationOffset is null");
 360: 
 361:     this.destinationOffset = destinationOffset;
 362:   }
 363: 
 364:   /**
 365:    * Set the indices of the source bands to be used.  Duplicate
 366:    * indices are not allowed.  A value of null means use all source
 367:    * bands.  The argument array is copied and stored, so subsequent
 368:    * updates to it will not be reflected in this IIOParam.
 369:    *
 370:    * @param sourceBands the array of source bands to use
 371:    */
 372:   public void setSourceBands(int[] sourceBands)
 373:   {
 374:     int[] sourceBandsCopy = new int[sourceBands.length];
 375:     System.arraycopy (sourceBands, 0, sourceBandsCopy, 0, sourceBands.length);
 376:     this.sourceBands = sourceBandsCopy;
 377:   }
 378: 
 379:   /**
 380:    * Set the source region from which to read.  The number of pixels
 381:    * sampled from the source region depends on the source sub-sampling
 382:    * settings.  If the combination of this sourceRegion and the
 383:    * current sub-sampling settings would result in no pixels being
 384:    * sampled then an IllegalStateException will be thrown.
 385:    *
 386:    * The source region is specified in the source image coordinate
 387:    * system which has point (0, 0) at the top-left and increases down
 388:    * and to the right.  The argument source region is clipped to the
 389:    * image boundaries at read-time.
 390:    *
 391:    * A null argument sets the source region to null meaning that the
 392:    * whole image should be read.
 393:    *
 394:    * @param sourceRegion the rectangular source region
 395:    *
 396:    * @exception IllegalArgumentException if sourceRegion has width or
 397:    * height <= 0 or x or y < 0
 398:    * @exception IllegalStateException if the given sourceRegion and
 399:    * the current sampling settings would produce zero samples
 400:    */
 401:   public void setSourceRegion(Rectangle sourceRegion)
 402:   {
 403:     if (sourceRegion != null
 404:     && (sourceRegion.x < 0
 405:         || sourceRegion.y < 0
 406:         || sourceRegion.width <= 0
 407:         || sourceRegion.height <= 0))
 408:       throw new IllegalArgumentException("illegal source region");
 409: 
 410:     if (sourceRegion != null)
 411:       {
 412:     int num_rows =
 413:       (sourceRegion.height - subsamplingYOffset + sourceYSubsampling - 1)
 414:       / sourceYSubsampling;
 415: 
 416:     int num_columns =
 417:       (sourceRegion.width - subsamplingXOffset + sourceXSubsampling - 1)
 418:       / sourceXSubsampling;
 419: 
 420:     if (num_rows <= 0 || num_columns <= 0)
 421:       throw new IllegalStateException("zero pixels in source region");
 422:       }
 423: 
 424:     this.sourceRegion = sourceRegion;
 425:   }
 426: 
 427:   /**
 428:    * Set the source sampling intervals and offsets.  Every
 429:    * sourceXSubsampling'th pixel horizontally and
 430:    * sourceYSubsampling'th pixel vertically will be sampled.  Sampling
 431:    * will being a the subsamplingXOffset'th column and the
 432:    * subsamplingYOffset'th row.
 433:    *
 434:    * Horizontally, the number of sampled pixels will be:
 435:    *
 436:    * floor((width - subsamplingXOffset + sourceXSubsampling - 1) / sourceXSubsampling)
 437:    *
 438:    * Vertically:
 439:    *
 440:    * floor((height - subsamplingYOffset + sourceYSubsampling - 1) / sourceYSubsampling)
 441:    *
 442:    * If the current source region setting is such that the given
 443:    * sub-sampling arguments would produce zero pixel samples, an
 444:    * IllegalStateException is thrown.
 445:    *
 446:    * The offset parameters can be used to make source regions overlap
 447:    * when tiling across an image.  This can eliminate seams and
 448:    * better-tile images whose width or height is not a multiple of the
 449:    * sampling interval.
 450:    *
 451:    * @param sourceXSubsampling the horizontal sampling interval
 452:    * @param sourceYSubsampling the vertical sampling interval
 453:    * @param subsamplingXOffset the horizontal offset of the initial
 454:    * sample
 455:    * @param subsamplingYOffset the vertical offset of the initial
 456:    * sample
 457:    *
 458:    * @exception IllegalArgumentException if either subsamplingXOffset
 459:    * or subsamplingYOffset is < 0
 460:    * @exception IllegalStateException if the current source region
 461:    * combined with the given sub-sampling parameters would produce
 462:    * zero pixel samples
 463:    */
 464:   public void setSourceSubsampling(int sourceXSubsampling, int sourceYSubsampling,
 465:                    int subsamplingXOffset, int subsamplingYOffset)
 466:   {
 467:     if (subsamplingXOffset < 0 || subsamplingYOffset < 0)
 468:       throw new IllegalArgumentException("subsampling offset < 0");
 469: 
 470:     if (sourceRegion != null)
 471:       {
 472:     int num_rows =
 473:       (sourceRegion.height - subsamplingYOffset + sourceYSubsampling - 1)
 474:       / sourceYSubsampling;
 475: 
 476:     int num_columns =
 477:       (sourceRegion.width - subsamplingXOffset + sourceXSubsampling - 1)
 478:       / sourceXSubsampling;
 479: 
 480:     if (num_rows <= 0 || num_columns <= 0)
 481:       throw new IllegalStateException("subsampling parameters would"
 482:                       + " produce zero pixel samples"
 483:                       + " in source region");
 484:       }
 485: 
 486:     this.sourceXSubsampling = sourceXSubsampling;
 487:     this.sourceYSubsampling = sourceYSubsampling;
 488:     this.subsamplingXOffset = subsamplingXOffset;
 489:     this.subsamplingYOffset = subsamplingYOffset;
 490:   }
 491: }