protected static void divide_BYTE_COMP_Data(WritableRaster wr) {
    // System.out.println("Multiply Int: " + wr);

    ComponentSampleModel csm;
    csm = (ComponentSampleModel) wr.getSampleModel();

    final int width = wr.getWidth();

    final int scanStride = csm.getScanlineStride();
    final int pixStride = csm.getPixelStride();
    final int[] bandOff = csm.getBandOffsets();

    DataBufferByte db = (DataBufferByte) wr.getDataBuffer();
    final int base =
        (db.getOffset()
            + csm.getOffset(
                wr.getMinX() - wr.getSampleModelTranslateX(),
                wr.getMinY() - wr.getSampleModelTranslateY()));

    int a = 0;
    int aOff = bandOff[bandOff.length - 1];
    int bands = bandOff.length - 1;
    int b, i;
    // Access the pixel data array
    final byte pixels[] = db.getBankData()[0];
    for (int y = 0; y < wr.getHeight(); y++) {
      int sp = base + y * scanStride;
      final int end = sp + width * pixStride;
      while (sp < end) {
        a = pixels[sp + aOff] & 0xFF;
        if (a == 0) {
          for (b = 0; b < bands; b++) pixels[sp + bandOff[b]] = (byte) 0xFF;
        } else if (a < 255) {
          int aFP = (0x00FF0000 / a);
          for (b = 0; b < bands; b++) {
            i = sp + bandOff[b];
            pixels[i] = (byte) (((pixels[i] & 0xFF) * aFP) >>> 16);
          }
        }
        sp += pixStride;
      }
    }
  }
  private Raster readSubsampledRaster(WritableRaster raster) throws IOException {
    if (raster == null)
      raster =
          Raster.createWritableRaster(
              sampleModel.createCompatibleSampleModel(
                  destinationRegion.x + destinationRegion.width,
                  destinationRegion.y + destinationRegion.height),
              new Point(destinationRegion.x, destinationRegion.y));

    int numBands = sourceBands.length;
    int dataType = sampleModel.getDataType();
    int sampleSizeBit = DataBuffer.getDataTypeSize(dataType);
    int sampleSizeByte = (sampleSizeBit + 7) / 8;

    Rectangle destRect = raster.getBounds().intersection(destinationRegion);

    int offx = destinationRegion.x;
    int offy = destinationRegion.y;

    int sourceSX = (destRect.x - offx) * scaleX + sourceOrigin.x;
    int sourceSY = (destRect.y - offy) * scaleY + sourceOrigin.y;
    int sourceEX = (destRect.width - 1) * scaleX + sourceSX;
    int sourceEY = (destRect.height - 1) * scaleY + sourceSY;
    int startXTile = sourceSX / tileWidth;
    int startYTile = sourceSY / tileHeight;
    int endXTile = sourceEX / tileWidth;
    int endYTile = sourceEY / tileHeight;

    startXTile = clip(startXTile, 0, maxXTile);
    startYTile = clip(startYTile, 0, maxYTile);
    endXTile = clip(endXTile, 0, maxXTile);
    endYTile = clip(endYTile, 0, maxYTile);

    int totalXTiles = getNumXTiles();
    int totalYTiles = getNumYTiles();
    int totalTiles = totalXTiles * totalYTiles;

    // The line buffer for the source
    byte[] pixbuf = null; // byte buffer for the decoded pixels.
    short[] spixbuf = null; // byte buffer for the decoded pixels.
    int[] ipixbuf = null; // byte buffer for the decoded pixels.
    float[] fpixbuf = null; // byte buffer for the decoded pixels.
    double[] dpixbuf = null; // byte buffer for the decoded pixels.

    // A flag to show the ComponentSampleModel has a single data bank
    boolean singleBank = true;
    int pixelStride = 0;
    int scanlineStride = 0;
    int bandStride = 0;
    int[] bandOffsets = null;
    int[] bankIndices = null;

    if (originalSampleModel instanceof ComponentSampleModel) {
      ComponentSampleModel csm = (ComponentSampleModel) originalSampleModel;
      bankIndices = csm.getBankIndices();
      int maxBank = 0;
      for (int i = 0; i < bankIndices.length; i++)
        if (maxBank > bankIndices[i]) maxBank = bankIndices[i];

      if (maxBank > 0) singleBank = false;
      pixelStride = csm.getPixelStride();

      scanlineStride = csm.getScanlineStride();
      bandOffsets = csm.getBandOffsets();
      for (int i = 0; i < bandOffsets.length; i++)
        if (bandStride < bandOffsets[i]) bandStride = bandOffsets[i];
    } else if (originalSampleModel instanceof MultiPixelPackedSampleModel) {
      scanlineStride = ((MultiPixelPackedSampleModel) originalSampleModel).getScanlineStride();
    } else if (originalSampleModel instanceof SinglePixelPackedSampleModel) {
      pixelStride = 1;
      scanlineStride = ((SinglePixelPackedSampleModel) originalSampleModel).getScanlineStride();
    }

    // The dstination buffer for the raster
    byte[] destPixbuf = null; // byte buffer for the decoded pixels.
    short[] destSPixbuf = null; // byte buffer for the decoded pixels.
    int[] destIPixbuf = null; // byte buffer for the decoded pixels.
    float[] destFPixbuf = null; // byte buffer for the decoded pixels.
    double[] destDPixbuf = null; // byte buffer for the decoded pixels.
    int[] destBandOffsets = null;
    int destPixelStride = 0;
    int destScanlineStride = 0;
    int destSX = 0; // The first pixel for the destionation

    if (raster.getSampleModel() instanceof ComponentSampleModel) {
      ComponentSampleModel csm = (ComponentSampleModel) raster.getSampleModel();
      bankIndices = csm.getBankIndices();
      destBandOffsets = csm.getBandOffsets();
      destPixelStride = csm.getPixelStride();
      destScanlineStride = csm.getScanlineStride();
      destSX =
          csm.getOffset(
                  raster.getMinX() - raster.getSampleModelTranslateX(),
                  raster.getMinY() - raster.getSampleModelTranslateY())
              - destBandOffsets[0];

      switch (dataType) {
        case DataBuffer.TYPE_BYTE:
          destPixbuf = ((DataBufferByte) raster.getDataBuffer()).getData();
          break;
        case DataBuffer.TYPE_SHORT:
          destSPixbuf = ((DataBufferShort) raster.getDataBuffer()).getData();
          break;

        case DataBuffer.TYPE_USHORT:
          destSPixbuf = ((DataBufferUShort) raster.getDataBuffer()).getData();
          break;

        case DataBuffer.TYPE_INT:
          destIPixbuf = ((DataBufferInt) raster.getDataBuffer()).getData();
          break;

        case DataBuffer.TYPE_FLOAT:
          destFPixbuf = ((DataBufferFloat) raster.getDataBuffer()).getData();
          break;

        case DataBuffer.TYPE_DOUBLE:
          destDPixbuf = ((DataBufferDouble) raster.getDataBuffer()).getData();
          break;
      }
    } else if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel) {
      numBands = 1;
      bankIndices = new int[] {0};
      destBandOffsets = new int[numBands];
      for (int i = 0; i < numBands; i++) destBandOffsets[i] = 0;
      destPixelStride = 1;
      destScanlineStride =
          ((SinglePixelPackedSampleModel) raster.getSampleModel()).getScanlineStride();
    }

    // Start the data delivery to the cached consumers tile by tile
    for (int y = startYTile; y <= endYTile; y++) {
      if (reader.getAbortRequest()) break;

      // Loop on horizontal tiles
      for (int x = startXTile; x <= endXTile; x++) {
        if (reader.getAbortRequest()) break;

        long tilePosition = position + (y * originalNumXTiles + x) * tileDataSize;
        iis.seek(tilePosition);
        float percentage = (x - startXTile + y * totalXTiles) / totalXTiles;

        int startX = x * tileWidth;
        int startY = y * tileHeight;

        int cTileHeight = tileHeight;
        int cTileWidth = tileWidth;

        if (startY + cTileHeight >= originalDimension.height)
          cTileHeight = originalDimension.height - startY;

        if (startX + cTileWidth >= originalDimension.width)
          cTileWidth = originalDimension.width - startX;

        int tx = startX;
        int ty = startY;

        // If source start position calculated by taking subsampling
        // into account is after the tile's start X position, adjust
        // the start position accordingly
        if (sourceSX > startX) {
          cTileWidth += startX - sourceSX;
          tx = sourceSX;
          startX = sourceSX;
        }

        if (sourceSY > startY) {
          cTileHeight += startY - sourceSY;
          ty = sourceSY;
          startY = sourceSY;
        }

        // If source end position calculated by taking subsampling
        // into account is prior to the tile's end X position, adjust
        // the tile width to read accordingly
        if (sourceEX < startX + cTileWidth - 1) {
          cTileWidth += sourceEX - startX - cTileWidth + 1;
        }

        if (sourceEY < startY + cTileHeight - 1) {
          cTileHeight += sourceEY - startY - cTileHeight + 1;
        }

        // The start X in the destination
        int x1 = (startX + scaleX - 1 - sourceOrigin.x) / scaleX;
        int x2 = (startX + scaleX - 1 + cTileWidth - sourceOrigin.x) / scaleX;
        int lineLength = x2 - x1;
        x2 = (x2 - 1) * scaleX + sourceOrigin.x;

        int y1 = (startY + scaleY - 1 - sourceOrigin.y) / scaleY;
        startX = x1 * scaleX + sourceOrigin.x;
        startY = y1 * scaleY + sourceOrigin.y;

        // offx is destination.x
        x1 += offx;
        y1 += offy;

        tx -= x * tileWidth;
        ty -= y * tileHeight;

        if (sampleModel instanceof MultiPixelPackedSampleModel) {
          MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) originalSampleModel;

          iis.skipBytes(mppsm.getOffset(tx, ty) * sampleSizeByte);

          int readBytes =
              (mppsm.getOffset(x2, 0) - mppsm.getOffset(startX, 0) + 1) * sampleSizeByte;

          int skipLength = (scanlineStride * scaleY - readBytes) * sampleSizeByte;
          readBytes *= sampleSizeByte;

          if (pixbuf == null || pixbuf.length < readBytes) pixbuf = new byte[readBytes];

          int bitoff = mppsm.getBitOffset(tx);

          for (int l = 0, m = y1; l < cTileHeight; l += scaleY, m++) {
            if (reader.getAbortRequest()) break;
            iis.readFully(pixbuf, 0, readBytes);
            if (scaleX == 1) {

              if (bitoff != 0) {
                int mask1 = (255 << bitoff) & 255;
                int mask2 = ~mask1 & 255;
                int shift = 8 - bitoff;

                int n = 0;
                for (; n < readBytes - 1; n++)
                  pixbuf[n] =
                      (byte) (((pixbuf[n] & mask2) << shift) | (pixbuf[n + 1] & mask1) >> bitoff);
                pixbuf[n] = (byte) ((pixbuf[n] & mask2) << shift);
              }
            } else {

              int bit = 7;
              int pos = 0;
              int mask = 128;

              for (int n = 0, n1 = startX & 7; n < lineLength; n++, n1 += scaleX) {
                pixbuf[pos] =
                    (byte)
                        ((pixbuf[pos] & ~(1 << bit))
                            | (((pixbuf[n1 >> 3] >> (7 - (n1 & 7))) & 1) << bit));
                bit--;
                if (bit == -1) {
                  bit = 7;
                  pos++;
                }
              }
            }

            ImageUtil.setPackedBinaryData(pixbuf, raster, new Rectangle(x1, m, lineLength, 1));
            iis.skipBytes(skipLength);
            if (destImage != null)
              reader.processImageUpdateWrapper(
                  destImage, x1, m, cTileWidth, 1, 1, 1, destinationBands);

            reader.processImageProgressWrapper(
                percentage + (l - startY + 1.0F) / cTileHeight / totalTiles);
          }
        } else {

          int readLength, skipLength;
          if (pixelStride < scanlineStride) {
            readLength = cTileWidth * pixelStride;
            skipLength = (scanlineStride * scaleY - readLength) * sampleSizeByte;
          } else {
            readLength = cTileHeight * scanlineStride;
            skipLength = (pixelStride * scaleX - readLength) * sampleSizeByte;
          }

          // Allocate buffer for all the types
          switch (sampleModel.getDataType()) {
            case DataBuffer.TYPE_BYTE:
              if (pixbuf == null || pixbuf.length < readLength) pixbuf = new byte[readLength];
              break;

            case DataBuffer.TYPE_SHORT:
            case DataBuffer.TYPE_USHORT:
              if (spixbuf == null || spixbuf.length < readLength) spixbuf = new short[readLength];
              break;

            case DataBuffer.TYPE_INT:
              if (ipixbuf == null || ipixbuf.length < readLength) ipixbuf = new int[readLength];
              break;

            case DataBuffer.TYPE_FLOAT:
              if (fpixbuf == null || fpixbuf.length < readLength) fpixbuf = new float[readLength];
              break;

            case DataBuffer.TYPE_DOUBLE:
              if (dpixbuf == null || dpixbuf.length < readLength) dpixbuf = new double[readLength];
              break;
          }

          if (sampleModel instanceof PixelInterleavedSampleModel) {
            iis.skipBytes((tx * pixelStride + ty * scanlineStride) * sampleSizeByte);

            // variables for ther loop
            int outerFirst, outerSecond, outerStep, outerBound;
            int innerStep, innerStep1, outerStep1;
            if (pixelStride < scanlineStride) {
              outerFirst = 0;
              outerSecond = y1;
              outerStep = scaleY;
              outerBound = cTileHeight;
              innerStep = scaleX * pixelStride;
              innerStep1 = destPixelStride;
              outerStep1 = destScanlineStride;
            } else {
              outerFirst = 0;
              outerSecond = x1;
              outerStep = scaleX;
              outerBound = cTileWidth;
              innerStep = scaleY * scanlineStride;
              innerStep1 = destScanlineStride;
              outerStep1 = destPixelStride;
            }

            int destPos =
                destSX
                    + (y1 - raster.getSampleModelTranslateY()) * destScanlineStride
                    + (x1 - raster.getSampleModelTranslateX()) * destPixelStride;

            for (int l = outerFirst, m = outerSecond; l < outerBound; l += outerStep, m++) {
              if (reader.getAbortRequest()) break;

              switch (dataType) {
                case DataBuffer.TYPE_BYTE:
                  if (innerStep == numBands && innerStep1 == numBands)
                    iis.readFully(destPixbuf, destPos, readLength);
                  else iis.readFully(pixbuf, 0, readLength);
                  break;
                case DataBuffer.TYPE_SHORT:
                case DataBuffer.TYPE_USHORT:
                  if (innerStep == numBands && innerStep1 == numBands) {
                    iis.readFully(destSPixbuf, destPos, readLength);
                  } else iis.readFully(spixbuf, 0, readLength);
                  break;
                case DataBuffer.TYPE_INT:
                  if (innerStep == numBands && innerStep1 == numBands)
                    iis.readFully(destIPixbuf, destPos, readLength);
                  else iis.readFully(ipixbuf, 0, readLength);
                  break;
                case DataBuffer.TYPE_FLOAT:
                  if (innerStep == numBands && innerStep1 == numBands)
                    iis.readFully(destFPixbuf, destPos, readLength);
                  else iis.readFully(fpixbuf, 0, readLength);
                  break;
                case DataBuffer.TYPE_DOUBLE:
                  if (innerStep == numBands && innerStep1 == numBands)
                    iis.readFully(destDPixbuf, destPos, readLength);
                  else iis.readFully(dpixbuf, 0, readLength);
                  break;
              }

              if (innerStep != numBands || innerStep1 != numBands)
                for (int b = 0; b < numBands; b++) {
                  int destBandOffset = destBandOffsets[destinationBands[b]];
                  destPos += destBandOffset;

                  int sourceBandOffset = bandOffsets[sourceBands[b]];

                  switch (dataType) {
                    case DataBuffer.TYPE_BYTE:
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destPixbuf[n] = pixbuf[m1 + sourceBandOffset];
                      }
                      break;
                    case DataBuffer.TYPE_SHORT:
                    case DataBuffer.TYPE_USHORT:
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destSPixbuf[n] = spixbuf[m1 + sourceBandOffset];
                      }
                      break;
                    case DataBuffer.TYPE_INT:
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destIPixbuf[n] = ipixbuf[m1 + sourceBandOffset];
                      }
                      break;
                    case DataBuffer.TYPE_FLOAT:
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destFPixbuf[n] = fpixbuf[m1 + sourceBandOffset];
                      }
                      break;
                    case DataBuffer.TYPE_DOUBLE:
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destDPixbuf[n] = dpixbuf[m1 + sourceBandOffset];
                      }
                      break;
                  }
                  destPos -= destBandOffset;
                }

              iis.skipBytes(skipLength);
              destPos += outerStep1;

              if (destImage != null)
                if (pixelStride < scanlineStride)
                  reader.processImageUpdateWrapper(
                      destImage, x1, m, outerBound, 1, 1, 1, destinationBands);
                else
                  reader.processImageUpdateWrapper(
                      destImage, m, y1, 1, outerBound, 1, 1, destinationBands);

              reader.processImageProgressWrapper(percentage + (l + 1.0F) / outerBound / totalTiles);
            }
          } else if (sampleModel instanceof BandedSampleModel
              || sampleModel instanceof SinglePixelPackedSampleModel
              || bandStride == 0) {
            boolean isBanded = sampleModel instanceof BandedSampleModel;

            int bandSize = (int) ImageUtil.getBandSize(originalSampleModel);

            for (int b = 0; b < numBands; b++) {
              iis.seek(tilePosition + bandSize * sourceBands[b] * sampleSizeByte);
              int destBandOffset = destBandOffsets[destinationBands[b]];

              iis.skipBytes((ty * scanlineStride + tx * pixelStride) * sampleSizeByte);

              // variables for ther loop
              int outerFirst, outerSecond, outerStep, outerBound;
              int innerStep, innerStep1, outerStep1;
              if (pixelStride < scanlineStride) {
                outerFirst = 0;
                outerSecond = y1;
                outerStep = scaleY;
                outerBound = cTileHeight;
                innerStep = scaleX * pixelStride;
                innerStep1 = destPixelStride;
                outerStep1 = destScanlineStride;
              } else {
                outerFirst = 0;
                outerSecond = x1;
                outerStep = scaleX;
                outerBound = cTileWidth;
                innerStep = scaleY * scanlineStride;
                innerStep1 = destScanlineStride;
                outerStep1 = destPixelStride;
              }

              int destPos =
                  destSX
                      + (y1 - raster.getSampleModelTranslateY()) * destScanlineStride
                      + (x1 - raster.getSampleModelTranslateX()) * destPixelStride
                      + destBandOffset;

              int bank = bankIndices[destinationBands[b]];

              switch (dataType) {
                case DataBuffer.TYPE_BYTE:
                  destPixbuf = ((DataBufferByte) raster.getDataBuffer()).getData(bank);
                  break;
                case DataBuffer.TYPE_SHORT:
                  destSPixbuf = ((DataBufferShort) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_USHORT:
                  destSPixbuf = ((DataBufferUShort) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_INT:
                  destIPixbuf = ((DataBufferInt) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_FLOAT:
                  destFPixbuf = ((DataBufferFloat) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_DOUBLE:
                  destDPixbuf = ((DataBufferDouble) raster.getDataBuffer()).getData(bank);
                  break;
              }

              for (int l = outerFirst, m = outerSecond; l < outerBound; l += outerStep, m++) {
                if (reader.getAbortRequest()) break;

                switch (dataType) {
                  case DataBuffer.TYPE_BYTE:
                    if (innerStep == 1 && innerStep1 == 1) {
                      iis.readFully(destPixbuf, destPos, readLength);
                    } else {
                      iis.readFully(pixbuf, 0, readLength);
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destPixbuf[n] = pixbuf[m1];
                      }
                    }
                    break;
                  case DataBuffer.TYPE_SHORT:
                  case DataBuffer.TYPE_USHORT:
                    if (innerStep == 1 && innerStep1 == 1) {
                      iis.readFully(destSPixbuf, destPos, readLength);
                    } else {
                      iis.readFully(spixbuf, 0, readLength);
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destSPixbuf[n] = spixbuf[m1];
                      }
                    }
                    break;
                  case DataBuffer.TYPE_INT:
                    if (innerStep == 1 && innerStep1 == 1) {
                      iis.readFully(destIPixbuf, destPos, readLength);
                    } else {
                      iis.readFully(ipixbuf, 0, readLength);
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destIPixbuf[n] = ipixbuf[m1];
                      }
                    }
                    break;
                  case DataBuffer.TYPE_FLOAT:
                    if (innerStep == 1 && innerStep1 == 1) {
                      iis.readFully(destFPixbuf, destPos, readLength);
                    } else {
                      iis.readFully(fpixbuf, 0, readLength);
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destFPixbuf[n] = fpixbuf[m1];
                      }
                    }
                    break;
                  case DataBuffer.TYPE_DOUBLE:
                    if (innerStep == 1 && innerStep1 == 1) {
                      iis.readFully(destDPixbuf, destPos, readLength);
                    } else {
                      iis.readFully(dpixbuf, 0, readLength);
                      for (int m1 = 0, n = destPos;
                          m1 < readLength;
                          m1 += innerStep, n += innerStep1) {
                        destDPixbuf[n] = dpixbuf[m1];
                      }
                    }
                    break;
                }

                iis.skipBytes(skipLength);
                destPos += outerStep1;

                if (destImage != null) {
                  int[] destBands = new int[] {destinationBands[b]};
                  if (pixelStride < scanlineStride)
                    reader.processImageUpdateWrapper(
                        destImage, x1, m, outerBound, 1, 1, 1, destBands);
                  else
                    reader.processImageUpdateWrapper(
                        destImage, m, y1, 1, outerBound, 1, 1, destBands);
                }

                reader.processImageProgressWrapper(
                    (percentage + (l + 1.0F) / outerBound / numBands / totalTiles) * 100.0F);
              }
            }
          } else if (sampleModel instanceof ComponentSampleModel) {
            // for the other case, may slow
            // Allocate buffer for all the types
            int bufferSize = (int) tileDataSize;

            switch (sampleModel.getDataType()) {
              case DataBuffer.TYPE_BYTE:
                if (pixbuf == null || pixbuf.length < tileDataSize)
                  pixbuf = new byte[(int) tileDataSize];
                iis.readFully(pixbuf, 0, (int) tileDataSize);
                break;

              case DataBuffer.TYPE_SHORT:
              case DataBuffer.TYPE_USHORT:
                bufferSize /= 2;
                if (spixbuf == null || spixbuf.length < bufferSize)
                  spixbuf = new short[(int) bufferSize];
                iis.readFully(spixbuf, 0, (int) bufferSize);
                break;

              case DataBuffer.TYPE_INT:
                bufferSize /= 4;
                if (ipixbuf == null || ipixbuf.length < bufferSize)
                  ipixbuf = new int[(int) bufferSize];
                iis.readFully(ipixbuf, 0, (int) bufferSize);
                break;

              case DataBuffer.TYPE_FLOAT:
                bufferSize /= 4;
                if (fpixbuf == null || fpixbuf.length < bufferSize)
                  fpixbuf = new float[(int) bufferSize];
                iis.readFully(fpixbuf, 0, (int) bufferSize);
                break;

              case DataBuffer.TYPE_DOUBLE:
                bufferSize /= 8;
                if (dpixbuf == null || dpixbuf.length < bufferSize)
                  dpixbuf = new double[(int) bufferSize];
                iis.readFully(dpixbuf, 0, (int) bufferSize);
                break;
            }

            for (int b = 0; b < numBands; b++) {
              int destBandOffset = destBandOffsets[destinationBands[b]];

              int destPos =
                  ((ComponentSampleModel) raster.getSampleModel())
                      .getOffset(
                          x1 - raster.getSampleModelTranslateX(),
                          y1 - raster.getSampleModelTranslateY(),
                          destinationBands[b]);

              int bank = bankIndices[destinationBands[b]];

              switch (dataType) {
                case DataBuffer.TYPE_BYTE:
                  destPixbuf = ((DataBufferByte) raster.getDataBuffer()).getData(bank);
                  break;
                case DataBuffer.TYPE_SHORT:
                  destSPixbuf = ((DataBufferShort) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_USHORT:
                  destSPixbuf = ((DataBufferUShort) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_INT:
                  destIPixbuf = ((DataBufferInt) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_FLOAT:
                  destFPixbuf = ((DataBufferFloat) raster.getDataBuffer()).getData(bank);
                  break;

                case DataBuffer.TYPE_DOUBLE:
                  destDPixbuf = ((DataBufferDouble) raster.getDataBuffer()).getData(bank);
                  break;
              }

              int srcPos =
                  ((ComponentSampleModel) originalSampleModel).getOffset(tx, ty, sourceBands[b]);
              int skipX = scaleX * pixelStride;
              ;
              for (int l = 0, m = y1; l < cTileHeight; l += scaleY, m++) {
                if (reader.getAbortRequest()) break;

                switch (dataType) {
                  case DataBuffer.TYPE_BYTE:
                    for (int n = 0, m1 = srcPos, m2 = destPos;
                        n < lineLength;
                        n++, m1 += skipX, m2 += destPixelStride) destPixbuf[m2] = pixbuf[m1];
                    break;
                  case DataBuffer.TYPE_SHORT:
                  case DataBuffer.TYPE_USHORT:
                    for (int n = 0, m1 = srcPos, m2 = destPos;
                        n < lineLength;
                        n++, m1 += skipX, m2 += destPixelStride) destSPixbuf[m2] = spixbuf[m1];
                    break;
                  case DataBuffer.TYPE_INT:
                    for (int n = 0, m1 = srcPos, m2 = destPos;
                        n < lineLength;
                        n++, m1 += skipX, m2 += destPixelStride) destIPixbuf[m2] = ipixbuf[m1];
                    break;
                  case DataBuffer.TYPE_FLOAT:
                    for (int n = 0, m1 = srcPos, m2 = destPos;
                        n < lineLength;
                        n++, m1 += skipX, m2 += destPixelStride) destFPixbuf[m2] = fpixbuf[m1];
                    break;
                  case DataBuffer.TYPE_DOUBLE:
                    for (int n = 0, m1 = srcPos, m2 = destPos;
                        n < lineLength;
                        n++, m1 += skipX, m2 += destPixelStride) destDPixbuf[m2] = dpixbuf[m1];
                    break;
                }

                destPos += destScanlineStride;
                srcPos += scanlineStride * scaleY;

                if (destImage != null) {
                  int[] destBands = new int[] {destinationBands[b]};
                  reader.processImageUpdateWrapper(
                      destImage, x1, m, cTileHeight, 1, 1, 1, destBands);
                }

                reader.processImageProgressWrapper(
                    percentage + (l + 1.0F) / cTileHeight / numBands / totalTiles);
              }
            }
          } else {
            throw new IllegalArgumentException(I18N.getString("RawRenderedImage1"));
          }
        }
      } // End loop on horizontal tiles
    } // End loop on vertical tiles

    return raster;
  }
  private void writeRasterData(
      RenderedImage image,
      Rectangle sourceBounds,
      Dimension destSize,
      ImageWriteParam param,
      boolean interlaceFlag)
      throws IOException {

    int sourceXOffset = sourceBounds.x;
    int sourceYOffset = sourceBounds.y;
    int sourceWidth = sourceBounds.width;
    int sourceHeight = sourceBounds.height;

    int destWidth = destSize.width;
    int destHeight = destSize.height;

    int periodX;
    int periodY;
    if (param == null) {
      periodX = 1;
      periodY = 1;
    } else {
      periodX = param.getSourceXSubsampling();
      periodY = param.getSourceYSubsampling();
    }

    SampleModel sampleModel = image.getSampleModel();
    int bitsPerPixel = sampleModel.getSampleSize()[0];

    int initCodeSize = bitsPerPixel;
    if (initCodeSize == 1) {
      initCodeSize++;
    }
    stream.write(initCodeSize);

    LZWCompressor compressor = new LZWCompressor(stream, initCodeSize, false);

    boolean isOptimizedCase =
        periodX == 1
            && periodY == 1
            && sampleModel instanceof ComponentSampleModel
            && image.getNumXTiles() == 1
            && image.getNumYTiles() == 1
            && image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte;

    int numRowsWritten = 0;

    int progressReportRowPeriod = Math.max(destHeight / 20, 1);

    processImageStarted(imageIndex);

    if (interlaceFlag) {
      if (DEBUG) System.out.println("Writing interlaced");

      if (isOptimizedCase) {
        Raster tile = image.getTile(0, 0);
        byte[] data = ((DataBufferByte) tile.getDataBuffer()).getData();
        ComponentSampleModel csm = (ComponentSampleModel) tile.getSampleModel();
        int offset =
            csm.getOffset(
                sourceXOffset - tile.getSampleModelTranslateX(),
                sourceYOffset - tile.getSampleModelTranslateY(),
                0);
        int lineStride = csm.getScanlineStride();

        writeRowsOpt(
            data,
            offset,
            lineStride,
            compressor,
            0,
            8,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += destHeight / 8;

        writeRowsOpt(
            data,
            offset,
            lineStride,
            compressor,
            4,
            8,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += (destHeight - 4) / 8;

        writeRowsOpt(
            data,
            offset,
            lineStride,
            compressor,
            2,
            4,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += (destHeight - 2) / 4;

        writeRowsOpt(
            data,
            offset,
            lineStride,
            compressor,
            1,
            2,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);
      } else {
        writeRows(
            image,
            compressor,
            sourceXOffset,
            periodX,
            sourceYOffset,
            8 * periodY,
            sourceWidth,
            0,
            8,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += destHeight / 8;

        writeRows(
            image,
            compressor,
            sourceXOffset,
            periodX,
            sourceYOffset + 4 * periodY,
            8 * periodY,
            sourceWidth,
            4,
            8,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += (destHeight - 4) / 8;

        writeRows(
            image,
            compressor,
            sourceXOffset,
            periodX,
            sourceYOffset + 2 * periodY,
            4 * periodY,
            sourceWidth,
            2,
            4,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);

        if (abortRequested()) {
          return;
        }

        numRowsWritten += (destHeight - 2) / 4;

        writeRows(
            image,
            compressor,
            sourceXOffset,
            periodX,
            sourceYOffset + periodY,
            2 * periodY,
            sourceWidth,
            1,
            2,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);
      }
    } else {
      if (DEBUG) System.out.println("Writing non-interlaced");

      if (isOptimizedCase) {
        Raster tile = image.getTile(0, 0);
        byte[] data = ((DataBufferByte) tile.getDataBuffer()).getData();
        ComponentSampleModel csm = (ComponentSampleModel) tile.getSampleModel();
        int offset =
            csm.getOffset(
                sourceXOffset - tile.getSampleModelTranslateX(),
                sourceYOffset - tile.getSampleModelTranslateY(),
                0);
        int lineStride = csm.getScanlineStride();

        writeRowsOpt(
            data,
            offset,
            lineStride,
            compressor,
            0,
            1,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);
      } else {
        writeRows(
            image,
            compressor,
            sourceXOffset,
            periodX,
            sourceYOffset,
            periodY,
            sourceWidth,
            0,
            1,
            destWidth,
            destHeight,
            numRowsWritten,
            progressReportRowPeriod);
      }
    }

    if (abortRequested()) {
      return;
    }

    processImageProgress(100.0F);

    compressor.flush();

    stream.write(0x00);

    processImageComplete();
  }