/**
  * Stores the Raster data at the specified location. The transferType of the inputRaster must
  * match this raster. An ArrayIndexOutOfBoundsException will be thrown at runtime if the pixel
  * coordinates are out of bounds.
  *
  * @param x The X coordinate of the pixel location.
  * @param y The Y coordinate of the pixel location.
  * @param inRaster Raster of data to place at x,y location.
  */
 public void setDataElements(int x, int y, Raster inRaster) {
   int dstOffX = x + inRaster.getMinX();
   int dstOffY = y + inRaster.getMinY();
   int width = inRaster.getWidth();
   int height = inRaster.getHeight();
   if ((dstOffX < this.minX)
       || (dstOffY < this.minY)
       || (dstOffX + width > this.maxX)
       || (dstOffY + height > this.maxY)) {
     throw new ArrayIndexOutOfBoundsException("Coordinate out of bounds!");
   }
   setDataElements(dstOffX, dstOffY, width, height, inRaster);
 }
  /**
   * Stores the Raster data at the specified location.
   *
   * @param dstX The absolute X coordinate of the destination pixel that will receive a copy of the
   *     upper-left pixel of the inRaster
   * @param dstY The absolute Y coordinate of the destination pixel that will receive a copy of the
   *     upper-left pixel of the inRaster
   * @param width The number of pixels to store horizontally
   * @param height The number of pixels to store vertically
   * @param inRaster Raster of data to place at x,y location.
   */
  private void setDataElements(int dstX, int dstY, int width, int height, Raster inRaster) {
    // Assume bounds checking has been performed previously
    if (width <= 0 || height <= 0) {
      return;
    }

    // Write inRaster (minX, minY) to (dstX, dstY)

    int srcOffX = inRaster.getMinX();
    int srcOffY = inRaster.getMinY();
    int tdata[] = null;

    if (inRaster instanceof IntegerComponentRaster
        && (pixelStride == 1)
        && (numDataElements == 1)) {
      IntegerComponentRaster ict = (IntegerComponentRaster) inRaster;
      if (ict.getNumDataElements() != 1) {
        throw new ArrayIndexOutOfBoundsException("Number of bands" + " does not match");
      }

      // Extract the raster parameters
      tdata = ict.getDataStorage();
      int tss = ict.getScanlineStride();
      int toff = ict.getDataOffset(0);

      int srcOffset = toff;

      int dstOffset = dataOffsets[0] + (dstY - minY) * scanlineStride + (dstX - minX);

      // Fastest case.  We can copy scanlines
      if (ict.getPixelStride() == pixelStride) {
        width *= pixelStride;

        // Loop through all of the scanlines and copy the data
        for (int startY = 0; startY < height; startY++) {
          System.arraycopy(tdata, srcOffset, data, dstOffset, width);
          srcOffset += tss;
          dstOffset += scanlineStride;
        }
        markDirty();
        return;
      }
    }

    Object odata = null;
    for (int startY = 0; startY < height; startY++) {
      odata = inRaster.getDataElements(srcOffX, srcOffY + startY, width, 1, odata);
      setDataElements(dstX, dstY + startY, width, 1, odata);
    }
  }
  public void setPixels(
      int x, int y, int w, int h, ColorModel model, int pix[], int off, int scansize) {
    int lineOff = off;
    int poff;

    if (src != null) {
      src.checkSecurity(null, false);
    }

    // REMIND: What if the model doesn't fit in default color model?
    synchronized (this) {
      if (bimage == null) {
        if (cmodel == null) {
          cmodel = model;
        }
        createBufferedImage();
      }

      int[] storage = new int[w];
      int yoff;
      int pixel;

      if (cmodel instanceof IndexColorModel) {
        // REMIND: Right now we don't support writing back into ICM
        // images.
        convertToRGB();
      }

      if ((model == cmodel) && (biRaster instanceof IntegerComponentRaster)) {
        IntegerComponentRaster iraster = (IntegerComponentRaster) biRaster;

        if (off == 0 && scansize == w) {
          iraster.setDataElements(x, y, w, h, pix);
        } else {
          // Need to pack the data
          for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
            System.arraycopy(pix, lineOff, storage, 0, w);
            iraster.setDataElements(x, yoff, w, 1, storage);
          }
        }
      } else {
        if (model.getTransparency() != model.OPAQUE && cmodel.getTransparency() == cmodel.OPAQUE) {
          convertToRGB();
        }

        if (isDefaultBI) {
          IntegerComponentRaster iraster = (IntegerComponentRaster) biRaster;
          int[] data = iraster.getDataStorage();
          if (cmodel.equals(model)) {
            int sstride = iraster.getScanlineStride();
            int doff = y * sstride + x;
            for (yoff = 0; yoff < h; yoff++, lineOff += scansize) {
              System.arraycopy(pix, lineOff, data, doff, w);
              doff += sstride;
            }
            // Note: manual modification of pixels, mark the
            // raster as changed
            iraster.markDirty();
          } else {
            for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
              poff = lineOff;
              for (int i = 0; i < w; i++) {
                storage[i] = model.getRGB(pix[poff++]);
              }
              iraster.setDataElements(x, yoff, w, 1, storage);
            }
          }

          availinfo |= ImageObserver.SOMEBITS;
        } else {
          Object tmp = null;

          for (yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
            poff = lineOff;
            for (int xoff = x; xoff < x + w; xoff++) {
              pixel = model.getRGB(pix[poff++]);
              tmp = cmodel.getDataElements(pixel, tmp);
              biRaster.setDataElements(xoff, yoff, tmp);
            }
          }
          availinfo |= ImageObserver.SOMEBITS;
        }
      }
    }

    // Can't do this here since we might need to transform/clip
    // the region
    if (((availinfo & ImageObserver.FRAMEBITS) == 0)) {
      newInfo(image, ImageObserver.SOMEBITS, x, y, w, h);
    }
  }
  public void setPixels(
      int x, int y, int w, int h, ColorModel model, byte pix[], int off, int scansize) {
    int lineOff = off;
    int poff;
    int[] newLUT = null;

    if (src != null) {
      src.checkSecurity(null, false);
    }

    // REMIND: What if the model doesn't fit in default color model?
    synchronized (this) {
      if (bimage == null) {
        if (cmodel == null) {
          cmodel = model;
        }
        createBufferedImage();
      }

      if (w <= 0 || h <= 0) {
        return;
      }

      int biWidth = biRaster.getWidth();
      int biHeight = biRaster.getHeight();

      int x1 = x + w; // Overflow protection below
      int y1 = y + h; // Overflow protection below
      if (x < 0) {
        off -= x;
        x = 0;
      } else if (x1 < 0) {
        x1 = biWidth; // Must be overflow
      }
      if (y < 0) {
        off -= y * scansize;
        y = 0;
      } else if (y1 < 0) {
        y1 = biHeight; // Must be overflow
      }
      if (x1 > biWidth) {
        x1 = biWidth;
      }
      if (y1 > biHeight) {
        y1 = biHeight;
      }
      if (x >= x1 || y >= y1) {
        return;
      }
      // x,y,x1,y1 are all >= 0, so w,h must be >= 0
      w = x1 - x;
      h = y1 - y;
      // off is first pixel read so it must be in bounds
      if (off < 0 || off >= pix.length) {
        // They overflowed their own array
        throw new ArrayIndexOutOfBoundsException("Data offset out of bounds.");
      }
      // pix.length and off are >= 0 so remainder >= 0
      int remainder = pix.length - off;
      if (remainder < w) {
        // They overflowed their own array
        throw new ArrayIndexOutOfBoundsException("Data array is too short.");
      }
      int num;
      if (scansize < 0) {
        num = (off / -scansize) + 1;
      } else if (scansize > 0) {
        num = ((remainder - w) / scansize) + 1;
      } else {
        num = h;
      }
      if (h > num) {
        // They overflowed their own array.
        throw new ArrayIndexOutOfBoundsException("Data array is too short.");
      }

      if (isSameCM
          && (cmodel != model)
          && (srcLUT != null)
          && (model instanceof IndexColorModel)
          && (biRaster instanceof ByteComponentRaster)) {
        IndexColorModel icm = (IndexColorModel) model;
        ByteComponentRaster bct = (ByteComponentRaster) biRaster;
        int numlut = numSrcLUT;
        if (!setDiffICM(
            x,
            y,
            w,
            h,
            srcLUT,
            srcLUTtransIndex,
            numSrcLUT,
            icm,
            pix,
            off,
            scansize,
            bct,
            bct.getDataOffset(0))) {
          convertToRGB();
        } else {
          // Note that setDiffICM modified the raster directly
          // so we must mark it as changed
          bct.markDirty();
          if (numlut != numSrcLUT) {
            boolean hasAlpha = icm.hasAlpha();
            if (srcLUTtransIndex != -1) {
              hasAlpha = true;
            }
            int nbits = icm.getPixelSize();
            icm =
                new IndexColorModel(
                    nbits,
                    numSrcLUT,
                    srcLUT,
                    0,
                    hasAlpha,
                    srcLUTtransIndex,
                    (nbits > 8 ? DataBuffer.TYPE_USHORT : DataBuffer.TYPE_BYTE));
            cmodel = icm;
            bimage = createImage(icm, bct, false, null);
          }
          return;
        }
      }

      if (isDefaultBI) {
        int pixel;
        IntegerComponentRaster iraster = (IntegerComponentRaster) biRaster;
        if (srcLUT != null && model instanceof IndexColorModel) {
          if (model != srcModel) {
            // Fill in the new lut
            ((IndexColorModel) model).getRGBs(srcLUT);
            srcModel = model;
          }

          if (s_useNative) {
            // Note that setICMpixels modifies the raster directly
            // so we must mark it as changed afterwards
            if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, iraster)) {
              iraster.markDirty();
            } else {
              abort();
              return;
            }
          } else {
            int[] storage = new int[w * h];
            int soff = 0;
            // It is an IndexColorModel
            for (int yoff = 0; yoff < h; yoff++, lineOff += scansize) {
              poff = lineOff;
              for (int i = 0; i < w; i++) {
                storage[soff++] = srcLUT[pix[poff++] & 0xff];
              }
            }
            iraster.setDataElements(x, y, w, h, storage);
          }
        } else {
          int[] storage = new int[w];
          for (int yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
            poff = lineOff;
            for (int i = 0; i < w; i++) {
              storage[i] = model.getRGB(pix[poff++] & 0xff);
            }
            iraster.setDataElements(x, yoff, w, 1, storage);
          }
          availinfo |= ImageObserver.SOMEBITS;
        }
      } else if ((cmodel == model)
          && (biRaster instanceof ByteComponentRaster)
          && (biRaster.getNumDataElements() == 1)) {
        ByteComponentRaster bt = (ByteComponentRaster) biRaster;
        if (off == 0 && scansize == w) {
          bt.putByteData(x, y, w, h, pix);
        } else {
          byte[] bpix = new byte[w];
          poff = off;
          for (int yoff = y; yoff < y + h; yoff++) {
            System.arraycopy(pix, poff, bpix, 0, w);
            bt.putByteData(x, yoff, w, 1, bpix);
            poff += scansize;
          }
        }
      } else {
        for (int yoff = y; yoff < y + h; yoff++, lineOff += scansize) {
          poff = lineOff;
          for (int xoff = x; xoff < x + w; xoff++) {
            bimage.setRGB(xoff, yoff, model.getRGB(pix[poff++] & 0xff));
          }
        }
        availinfo |= ImageObserver.SOMEBITS;
      }
    }

    if ((availinfo & ImageObserver.FRAMEBITS) == 0) {
      newInfo(image, ImageObserver.SOMEBITS, x, y, w, h);
    }
  }