public TIFFRenderedImage(
      TIFFImageReader reader, int imageIndex, ImageReadParam readParam, int width, int height)
      throws IOException {
    this.reader = reader;
    this.imageIndex = imageIndex;
    this.tileParam = cloneImageReadParam(readParam, false);

    this.subsampleX = tileParam.getSourceXSubsampling();
    this.subsampleY = tileParam.getSourceYSubsampling();

    this.isSubsampling = this.subsampleX != 1 || this.subsampleY != 1;

    this.width = width / subsampleX;
    this.height = height / subsampleY;

    // If subsampling is being used, we may not match the
    // true tile grid exactly, but everything should still work
    this.tileWidth = reader.getTileWidth(imageIndex) / subsampleX;
    this.tileHeight = reader.getTileHeight(imageIndex) / subsampleY;

    Iterator iter = reader.getImageTypes(imageIndex);
    this.its = (ImageTypeSpecifier) iter.next();
    tileParam.setDestinationType(its);
  }
  // This method needs to be synchronized as it updates the instance
  // variable 'tileParam'.
  public synchronized WritableRaster read(Rectangle rect) {
    // XXX Does this need to consider the subsampling offsets or is
    // that handled implicitly by the reader?
    tileParam.setSourceRegion(
        isSubsampling
            ? new Rectangle(
                subsampleX * rect.x,
                subsampleY * rect.y,
                subsampleX * rect.width,
                subsampleY * rect.height)
            : rect);

    try {
      BufferedImage bi = reader.read(imageIndex, tileParam);
      WritableRaster ras = bi.getRaster();
      return ras.createWritableChild(0, 0, ras.getWidth(), ras.getHeight(), rect.x, rect.y, null);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
 // Forward warning message to reader
 private void warning(String msg) {
   if (this.reader instanceof TIFFImageReader) {
     ((TIFFImageReader) reader).forwardWarningMessage(msg);
   }
 }