home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / image / BufferedImage.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  42.9 KB  |  1,198 lines

  1. /*
  2.  * @(#)BufferedImage.java    1.56 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.awt.image;
  16.  
  17. import java.awt.Transparency;
  18. import java.awt.color.ColorSpace;
  19. import java.awt.Graphics2D;
  20. import java.awt.GraphicsEnvironment;
  21. import java.awt.geom.Rectangle2D;
  22. import java.awt.geom.Point2D;
  23. import java.awt.Point;
  24. import java.awt.Rectangle;
  25. import java.util.Vector;
  26.  
  27. import sun.awt.image.BytePackedRaster;
  28. import sun.awt.image.ShortComponentRaster;
  29. import sun.awt.image.ByteComponentRaster;
  30. import sun.awt.image.IntegerComponentRaster;
  31.  
  32.  
  33. /**
  34.  *
  35.  * This subclass describes an Image with an accessible buffer of image data.
  36.  * A BufferedImage is comprised of a ColorModel and a Raster of image data.
  37.  * The number and types of bands in the SampleModel of the Raster must match
  38.  * the number and types required by the ColorModel to represent its color
  39.  * and alpha components.  All BufferedImages have an upper left corner
  40.  * coordinate of 0,0.  Any Raster used to construct a BufferedImage must
  41.  * therefore have minX=0 and minY=0.
  42.  * @see ColorModel
  43.  * @see Raster
  44.  * @see WritableRaster
  45.  * @version 10 Feb 1997
  46.  */
  47.  
  48. public class BufferedImage extends java.awt.Image
  49.                            implements WritableRenderedImage {
  50.     int        imageType = TYPE_CUSTOM;
  51.     ColorModel colorModel;
  52.     WritableRaster raster;
  53.     TileChangeMulticaster tcm = new TileChangeMulticaster();
  54.  
  55.     boolean    isAlphaPremultiplied;// If true, alpha has been premultiplied in
  56.     // color channels
  57.         
  58.     /**
  59.      * Image Type Constants
  60.      */
  61.  
  62.     /**
  63.      * Image type is not recognized so it must be a customized
  64.      * image.  This type is only used as a return value for the getType()
  65.      * method.
  66.      */
  67.     public static final int TYPE_CUSTOM = 0;
  68.  
  69.     /**
  70.      * Represents an image with 8-bit RGB color components packed into
  71.      * integer pixels.  The image has a DirectColorModel (without alpha).
  72.      */
  73.     public static final int TYPE_INT_RGB = 1;
  74.  
  75.     /**
  76.      * Represents an image with 8-bit RGBA color components packed into
  77.      * integer pixels.  The image has a DirectColorModel (with alpha).
  78.      * The color data in this image
  79.      * is considered not to be premultiplied with alpha.  When
  80.      * this type is used as the imageType argument to a BufferedImage
  81.      * constructor, the image created will be
  82.      * consistent with images created in the JDK1.1 and earlier releases.
  83.      */
  84.     public static final int TYPE_INT_ARGB = 2;
  85.  
  86.     /**
  87.      * Represents an image with 8-bit RGBA color components packed into
  88.      * integer pixels.  The image has a DirectColorModel (with alpha).
  89.      * The color data in this image is considered to be premultiplied
  90.      * with alpha.
  91.      */
  92.     public static final int TYPE_INT_ARGB_PRE = 3;
  93.  
  94.     /**
  95.      * Represents an image with 8-bit RGB color components (corresponds to
  96.      * a Windows- or Solaris- style BGR color model) with the colors
  97.      * Blue, Green, and Red packed into integer pixels.  There is no alpha.
  98.      * The image has a ComponentColorModel.
  99.      */
  100.     public static final int TYPE_INT_BGR = 4;
  101.  
  102.     /**
  103.      * Represents an image with 8-bit RGB color components (corresponds to
  104.      * a Windows-style BGR color model) with the colors Blue, Green,
  105.      * and Red stored in 3 bytes.  There is no alpha.  The image has a
  106.      * ComponentColorModel.
  107.      */
  108.     public static final int TYPE_3BYTE_BGR = 5;
  109.  
  110.     /**
  111.      * Represents an image with 8-bit RGBA color components with the colors
  112.      * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
  113.      * image has a
  114.      * ComponentColorModel (with alpha).  The color data in this image
  115.      * will be considered not to be premultiplied with alpha.  The byte
  116.      * data is interleaved in a single byte array in the order A, B, G, R
  117.      * from lower to higher byte addresses within each pixel.
  118.      */
  119.     public static final int TYPE_4BYTE_ABGR = 6;
  120.  
  121.     /**
  122.      * Represents an image with 8-bit RGBA color components with the colors
  123.      * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
  124.      * image has
  125.      * a ComponentColorModel (with alpha). The color
  126.      * data in this image will be considered to be premultiplied with alpha.
  127.      * The byte data is interleaved in a single byte array in the order
  128.      * A, B, G, R from lower to higher byte addresses within each pixel.
  129.      */
  130.     public static final int TYPE_4BYTE_ABGR_PRE = 7;
  131.  
  132.     /**
  133.      * Represents an image with 5-6-5 RGB color components (5-bits red,
  134.      * 6-bits green, 5-bits blue) with no alpha.  This image has
  135.      * a DirectColorModel.
  136.      */
  137.     public static final int TYPE_SHORT_565_RGB = 8;
  138.     
  139.     /**
  140.      * Represents an image with 5-5-5 RGB color components (5-bits red,
  141.      * 5-bits green, 5-bits blue) with no alpha.  This image has
  142.      * a DirectColorModel.
  143.      */
  144.     public static final int TYPE_SHORT_555_RGB = 9;
  145.  
  146.     /**
  147.      * Represents a grayscale image (non-indexed).  This image has a
  148.      * ComponentColorModel with a CS_GRAY ColorSpace.
  149.      */
  150.     public static final int TYPE_BYTE_GRAY = 10;
  151.     
  152.     /**
  153.      * Represents an opaque binary image.  The
  154.      * image has an IndexColorModel
  155.      * (without alpha).  When this type is used as the imageType argument
  156.      * to the BufferedImage constructor which takes an imageType argument
  157.      * but no ColorModel argument, an IndexColorModel will be created with
  158.      * two colors in the default sRGB ColorSpace:  {0, 0, 0} and
  159.      * {255, 255, 255}.
  160.      */
  161.     public static final int TYPE_BINARY = 11;
  162.  
  163.     /**
  164.      * Represents an indexed byte image 
  165.      * When this type is used as the imageType argument
  166.      * to the BufferedImage constructor which takes an imageType argument
  167.      * but no ColorModel argument, an IndexColorModel will be created with
  168.      * an 8-bit grayscale ramp in the default sRGB ColorSpace.
  169.      */
  170.     public static final int TYPE_BYTE_INDEXED = 12;
  171.     
  172.     public static final int DCM_RED_MASK   = 0x00ff0000;
  173.     public static final int DCM_GREEN_MASK = 0x0000ff00;
  174.     public static final int DCM_BLUE_MASK  = 0x000000ff;
  175.     public static final int DCM_ALPHA_MASK = 0xff000000;
  176.     public static final int DCM_565_RED_MASK = 0xf800;
  177.     public static final int DCM_565_GRN_MASK = 0x07E0;
  178.     public static final int DCM_565_BLU_MASK = 0x001F;
  179.     public static final int DCM_555_RED_MASK = 0x7C00;
  180.     public static final int DCM_555_GRN_MASK = 0x03E0;
  181.     public static final int DCM_555_BLU_MASK = 0x001F;
  182.     public static final int DCM_BGR_RED_MASK = 0x0000ff;
  183.     public static final int DCM_BGR_GRN_MASK = 0x00ff00;
  184.     public static final int DCM_BGR_BLU_MASK = 0xff0000;
  185.     
  186.     static private native void initIDs();
  187.     static {
  188.         ColorModel.loadLibraries();
  189.         initIDs();
  190.     }
  191.  
  192.     /**
  193.      * Constructs a BufferedImage of one of the predefined image types.
  194.      * The ColorSpace for the image will be the default sRGB space.
  195.      * @param width     Width of the created image.
  196.      * @param height    Height of the created image.
  197.      * @param imageType Type of the created image.
  198.      * @see ColorSpace
  199.      * @see TYPE_INT_RGB
  200.      * @see TYPE_INT_ARGB
  201.      * @see TYPE_INT_ARGB_PRE
  202.      * @see TYPE_INT_BGR
  203.      * @see TYPE_3BYTE_BGR
  204.      * @see TYPE_4BYTE_ABGR
  205.      * @see TYPE_4BYTE_ABGR_PRE
  206.      * @see TYPE_BYTE_GRAY
  207.      * @see TYPE_BINARY
  208.      * @see TYPE_BYTE_INDEXED
  209.      * @see TYPE_SHORT_565_RGB
  210.      * @see TYPE_SHORT_555_RGB
  211.      */
  212.     public BufferedImage (int width, 
  213.                           int height, 
  214.                           int imageType) {
  215.  
  216.         switch (imageType) {
  217.         case TYPE_INT_RGB:
  218.             {
  219.                 colorModel = new DirectColorModel(24,
  220.                                                   0x00ff0000,    // Red
  221.                                                   0x0000ff00,    // Green
  222.                                                   0x000000ff,    // Blue
  223.                                                   0x0           // Alpha
  224.                                                   );
  225.                   raster = colorModel.createCompatibleWritableRaster(width,
  226.                                                                       height);
  227.             }
  228.         break;
  229.             
  230.         case TYPE_INT_ARGB:
  231.             {
  232.                 colorModel = new DirectColorModel(32,
  233.                                                   0x00ff0000,    // Red
  234.                                                   0x0000ff00,    // Green
  235.                                                   0x000000ff,    // Blue
  236.                                                   0xff000000    // Alpha
  237.                                                   );
  238.                 
  239.                   raster = colorModel.createCompatibleWritableRaster(width,
  240.                                                                       height);
  241.             }
  242.         break;
  243.  
  244.         case TYPE_INT_ARGB_PRE:
  245.             {
  246.                 colorModel = new
  247.                     DirectColorModel(
  248.                                      ColorSpace.getInstance(ColorSpace.CS_sRGB),
  249.                                      32,
  250.                                      0x00ff0000,// Red
  251.                                      0x0000ff00,// Green
  252.                                      0x000000ff,// Blue
  253.                                      0xff000000,// Alpha
  254.                                      true       // Alpha Premultiplied
  255.                                      );
  256.  
  257.                   raster = colorModel.createCompatibleWritableRaster(width,
  258.                                                                       height);
  259.             }
  260.         break;
  261.  
  262.         case TYPE_INT_BGR:
  263.             {
  264.                 colorModel = new DirectColorModel(24,
  265.                                                   0x000000ff,    // Red
  266.                                                   0x0000ff00,    // Green
  267.                                                   0x00ff0000    // Blue
  268.                                                   );
  269.                   raster = colorModel.createCompatibleWritableRaster(width,
  270.                                                                       height);
  271.             }
  272.         break;
  273.  
  274.         case TYPE_3BYTE_BGR:
  275.             {
  276.                 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  277.                 int[] nBits = {8, 8, 8};
  278.                 int[] bOffs = {2, 1, 0};
  279.                 colorModel = new ComponentColorModel(cs, nBits, false, false,
  280.                                                      Transparency.OPAQUE);
  281.                 raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
  282.                                                       width, height, width*3,
  283.                                                       3, bOffs, null);
  284.             }
  285.         break;
  286.             
  287.         case TYPE_4BYTE_ABGR:
  288.             {
  289.                 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  290.                 int[] nBits = {8, 8, 8, 8};
  291.                 int[] bOffs = {3, 2, 1, 0};
  292.                 colorModel = new ComponentColorModel(cs, nBits, true, false,
  293.                                                      Transparency.TRANSLUCENT);
  294.                 raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
  295.                                                       width, height, width*4,
  296.                                                       4, bOffs, null);
  297.             }
  298.         break;
  299.  
  300.         case TYPE_4BYTE_ABGR_PRE:
  301.             {
  302.                 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  303.                 int[] nBits = {8, 8, 8, 8};
  304.                 int[] bOffs = {3, 2, 1, 0};
  305.                 colorModel = new ComponentColorModel(cs, nBits, true, true,
  306.                                                      Transparency.TRANSLUCENT);
  307.                 raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
  308.                                                       width, height, width*4,
  309.                                                       4, bOffs, null);
  310.             }
  311.         break;
  312.  
  313.         case TYPE_BYTE_GRAY:
  314.             {
  315.                 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
  316.                 int[] nBits = {8};
  317.                 colorModel = new ComponentColorModel(cs, nBits, false, true,
  318.                                                      Transparency.OPAQUE);
  319.                 raster = colorModel.createCompatibleWritableRaster(width,
  320.                                                                    height);
  321.             }
  322.         break;
  323.                 
  324.         case TYPE_BINARY:
  325.             {
  326.                 byte[] arr = {(byte)0, (byte)0xff};
  327.                 
  328.                 colorModel = new IndexColorModel(1, 2, arr, arr, arr);
  329.                 raster = Raster.createPackedRaster(DataBuffer.BYTE_DATA,
  330.                                                    width, height, 1, 1, null);
  331.             }
  332.         break;
  333.             
  334.         case TYPE_BYTE_INDEXED:
  335.             {
  336.                 // Create a grayscale ramp
  337.                 int[] cmap = new int[256];
  338.                 for (int i=0; i < 256; i++) {
  339.                     cmap[i] = (i<<16)|(i<<8)|i;
  340.                 }
  341.                 colorModel = new IndexColorModel (8, 256, cmap, 0, false,
  342.                                                   -1, true);
  343.                 raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
  344.                                                       width, height, 1, null);
  345.             }
  346.         break;
  347.  
  348.         case TYPE_SHORT_565_RGB:
  349.             {
  350.                 colorModel = new DirectColorModel(16,
  351.                                                   DCM_565_RED_MASK,
  352.                                                   DCM_565_GRN_MASK,
  353.                                                   DCM_565_BLU_MASK
  354.                                                   );
  355.                 raster = colorModel.createCompatibleWritableRaster(width,
  356.                                                                    height);
  357.             }
  358.             break;
  359.  
  360.         case TYPE_SHORT_555_RGB:
  361.             {
  362.                 colorModel = new DirectColorModel(15,
  363.                                                   DCM_555_RED_MASK,
  364.                                                   DCM_555_GRN_MASK,
  365.                                                   DCM_555_BLU_MASK
  366.                                                   );
  367.                 raster = colorModel.createCompatibleWritableRaster(width,
  368.                                                                    height);
  369.             }
  370.             break;
  371.  
  372.         default:
  373.             throw new IllegalArgumentException ("Unknown image type " +
  374.                                                 imageType);
  375.         }
  376.  
  377.         this.imageType = imageType;
  378.     }
  379.  
  380.     /**
  381.      * Constructs a BufferedImage of one of the predefined image types:
  382.      * TYPE_BINARY or TYPE_BYTE_INDEXED
  383.      * @param width     Width of the created image.
  384.      * @param height    Height of the created image.
  385.      * @param imageType Type of the created image.
  386.      * @param cm        IndexColorModel of the created image.
  387.      * @throws IllegalArgumentException   if the imageType is not
  388.      * TYPE_BINARY or TYPE_BYTE_INDEXED
  389.      * @see TYPE_BINARY
  390.      * @see TYPE_BYTE_INDEXED
  391.      */
  392.     public BufferedImage (int width, 
  393.                           int height,
  394.                           int imageType,
  395.                           IndexColorModel cm) {
  396.         if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
  397.             throw new IllegalArgumentException("This image types do not have "+
  398.                                                "premultiplied alpha.");
  399.         }
  400.  
  401.         switch(imageType) {
  402.         case TYPE_BINARY:
  403.             raster = Raster.createPackedRaster(DataBuffer.BYTE_DATA,
  404.                                                 width, height, 1, 1, null);
  405.             break;
  406.             
  407.         case TYPE_BYTE_INDEXED:
  408.             raster = Raster.createComponentRaster(DataBuffer.BYTE_DATA,
  409.                                                   width, height, 1, null);
  410.             break;
  411.         default:
  412.             throw new IllegalArgumentException("Unknown image type " +
  413.                                                imageType);
  414.         }
  415.  
  416.         if (!cm.isCompatibleRaster(raster)) {
  417.             throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
  418.         }
  419.  
  420.         colorModel = cm;
  421.         this.imageType = imageType;
  422.     }
  423.  
  424.     /**
  425.      * Constructs a new BufferedImage with a given ColorModel
  426.      * and Raster.  If the number and types of bands in the SampleModel
  427.      * of the Raster do not match the number and types required by the
  428.      * ColorModel to represent its color and alpha components,
  429.      * an exception will be thrown.  This method may multiply or divide
  430.      * the color Raster data by alpha to match the alphaPremultiplied state
  431.      * in the ColorModel.
  432.      * @param ColorModel ColorModel for the new image
  433.      * @param raster     Raster for the image data
  434.      * @param isRasterPremultiplied   If true, the data in the raster has been
  435.      *                   premultiplied with alpha.
  436.      * @see ColorModel
  437.      * @see Raster
  438.      * @see WritableRaster
  439.      */
  440.  
  441.  
  442. /*
  443.  *
  444.  *  FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
  445.  *  SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
  446.  *
  447.  */
  448.     public BufferedImage (ColorModel cm,
  449.                           WritableRaster raster,
  450.                           boolean isRasterPremultiplied) {
  451.  
  452.         if (!cm.isCompatibleRaster(raster)) {
  453.             throw new
  454.                 IllegalArgumentException("Raster "+raster+
  455.                                          " is incompatible with ColorModel "+
  456.                                          cm);
  457.         }
  458.  
  459.     if ((raster.minX != 0) || (raster.minY != 0)) {
  460.             throw new
  461.                 IllegalArgumentException("Raster "+raster+
  462.                                          " has minX or minY not equal to zero: "
  463.                                          + raster.minX + " " + raster.minY);
  464.     }
  465.  
  466.         colorModel = cm;
  467.         this.raster  = raster;
  468.         int numBands = raster.getNumBands();
  469.         boolean isAlphaPre = cm.isAlphaPremultiplied();
  470.         ColorSpace cs;
  471.         
  472.         // Force the raster data alpha state to match the premultiplied 
  473.         // state in the color model
  474.         coerceData(isRasterPremultiplied);
  475.  
  476.         cs = cm.getColorSpace();
  477.         int csType = cs.getType();
  478.         if (csType != ColorSpace.TYPE_RGB) {
  479.             if (csType == ColorSpace.TYPE_GRAY
  480.                 && raster instanceof ByteComponentRaster
  481.                 && cm instanceof ComponentColorModel) {
  482.                 imageType = TYPE_BYTE_GRAY;
  483.             }
  484.             else {
  485.                 imageType = TYPE_CUSTOM;
  486.             }
  487.             return;
  488.         }
  489.  
  490.         if ((raster instanceof IntegerComponentRaster) &&
  491.             (numBands == 3 || numBands == 4)) {
  492.             IntegerComponentRaster iraster =
  493.                 (IntegerComponentRaster) raster;
  494.             // Check if the raster params and the color model
  495.             // are correct
  496.             int pixSize = cm.getPixelSize();
  497.             if (iraster.getPixelStride() == 1 &&
  498.                 cm instanceof DirectColorModel  &&
  499.                 (pixSize == 32 || pixSize == 24))
  500.             {
  501.                 // Now check on the DirectColorModel params
  502.                 DirectColorModel dcm = (DirectColorModel) cm;
  503.                 int rmask = dcm.getRedMask();
  504.                 int gmask = dcm.getGreenMask();
  505.                 int bmask = dcm.getBlueMask();
  506.                 if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
  507.                     bmask == DCM_BLUE_MASK)
  508.                 {
  509.                     if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
  510.                         imageType = (isAlphaPre
  511.                                      ? TYPE_INT_ARGB_PRE
  512.                                      : TYPE_INT_ARGB);
  513.                     }
  514.                     else {
  515.                         // No Alpha
  516.                         if (!dcm.hasAlpha()) {
  517.                             imageType = TYPE_INT_RGB;
  518.                         }
  519.                     } 
  520.                 }   // if (dcm.getRedMask() == DCM_RED_MASK &&
  521.                 else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
  522.                          && bmask == DCM_BGR_BLU_MASK) {
  523.                     if (!dcm.hasAlpha()) {
  524.                         imageType = TYPE_INT_BGR;
  525.                     }
  526.                 }  // if (rmask == DCM_BGR_RED_MASK &&
  527.             }   // if (iraster.getPixelStride() == 1 
  528.         }   // ((raster instanceof IntegerComponentRaster) &&
  529.         else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
  530.                  (!cm.hasAlpha() || !isAlphaPre))
  531.         {
  532.             IndexColorModel icm = (IndexColorModel) cm;
  533.             int pixSize = icm.getPixelSize();
  534.  
  535.             if (raster instanceof BytePackedRaster) {
  536.                 BytePackedRaster braster = (BytePackedRaster) raster;
  537.  
  538.                 if (braster.getNumberOfBits() == 1 &&
  539.                     braster.getPixelBitStride() == 1 &&
  540.                     pixSize == 1 &&
  541.                     icm.getMapSize() == 2)
  542.                 {
  543.                     imageType = TYPE_BINARY;
  544.                 }   
  545.             }   // if (raster instanceof BytePackedRaster)
  546.             else if (raster instanceof ByteComponentRaster) {
  547.                 ByteComponentRaster braster = (ByteComponentRaster) raster;
  548.                 if (braster.getPixelStride() == 1 && pixSize <= 8) {
  549.                     imageType = TYPE_BYTE_INDEXED;
  550.                 }   
  551.             }
  552.         }   // else if (cm instanceof IndexColorModel) && (numBands == 1))
  553.         else if ((raster instanceof ShortComponentRaster)
  554.                  && (cm instanceof DirectColorModel)
  555.                  && (numBands == 3)
  556.                  && !cm.hasAlpha())
  557.         {
  558.             DirectColorModel dcm = (DirectColorModel) cm;
  559.             if (dcm.getRedMask() == DCM_565_RED_MASK) {
  560.                 if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
  561.                     dcm.getBlueMask()  == DCM_565_BLU_MASK) {
  562.                     imageType = TYPE_SHORT_565_RGB;
  563.                 }
  564.             }
  565.             else if (dcm.getRedMask() == DCM_555_RED_MASK) {
  566.                 if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
  567.                     dcm.getBlueMask() == DCM_555_BLU_MASK) {
  568.                     imageType = TYPE_SHORT_555_RGB;
  569.                 }
  570.             }
  571.         }   // else if ((cm instanceof IndexColorModel) && (numBands == 1))
  572.         else if ((raster instanceof ByteComponentRaster) 
  573.                  && (cm instanceof ComponentColorModel)
  574.                  && (numBands == 3 || numBands == 4))
  575.         {
  576.             ComponentColorModel ccm = (ComponentColorModel) cm;
  577.             ByteComponentRaster braster = (ByteComponentRaster) raster;
  578.             int[] offs = braster.getDataOffsets();
  579.             if (ccm.getNumComponents() != numBands) {
  580.                 throw new RasterFormatException("Number of components in "+
  581.                                                 "ColorModel ("+
  582.                                                 ccm.getNumComponents()+
  583.                                                 ") does not match # in "+
  584.                                                 " Raster ("+numBands+")");
  585.             }
  586.  
  587.             if (braster.getPixelStride() == 1 &&
  588.                 offs[0] == numBands-1 &&
  589.                 offs[1] == numBands-2 &&
  590.                 offs[2] == numBands-3)
  591.             {
  592.                 if (numBands == 3) {
  593.                     imageType = TYPE_3BYTE_BGR;
  594.                 }
  595.                 else if (offs[3] == 0) {
  596.                     imageType = (isAlphaPre
  597.                                  ? TYPE_4BYTE_ABGR_PRE
  598.                                  : TYPE_4BYTE_ABGR);
  599.                 }
  600.             }
  601.         }   // else if ((raster instanceof ByteComponentRaster) &&
  602.     }
  603.  
  604.     /**
  605.      * Returns the image type.  If it is not one of the known types,
  606.      * TYPE_CUSTOM is returned.
  607.      * @see TYPE_INT_RGB
  608.      * @see TYPE_INT_ARGB
  609.      * @see TYPE_INT_ARGB_PRE
  610.      * @see TYPE_3BYTE_BGR
  611.      * @see TYPE_4BYTE_ABGR
  612.      * @see TYPE_4BYTE_ABGR_PRE
  613.      * @see TYPE_SHORT_565_RGB
  614.      * @see TYPE_SHORT_555_RGB
  615.      * @see TYPE_BYTE_GRAY
  616.      * @see TYPE_BINARY
  617.      * @see TYPE_BYTE_INDEXED
  618.      * @see TYPE_CUSTOM
  619.      */
  620.     public int getType() {
  621.         return imageType;
  622.     }
  623.     
  624.     /**
  625.      * Returns the ColorModel.
  626.      */
  627.     public ColorModel getColorModel() {
  628.         return colorModel;
  629.     }
  630.  
  631.     /**
  632.      * Returns the Raster.
  633.      */
  634.     public WritableRaster getRaster() {
  635.     return raster;
  636.     }
  637.     
  638.     
  639.     /**
  640.      * Returns a Raster representing the alpha channel for BufferedImages
  641.      * with ColorModels that support a separate spatial alpha channel
  642.      * (such as ComponentColorModel and DirectColorModel).
  643.      * Returns null if there is no alpha
  644.      * channel associated with the ColorModel in this image.
  645.      * This method assumes that for all ColorModels other than IndexColorModel,
  646.      * if the ColorModel supports alpha, there is a separate alpha channel
  647.      * which is stored as the last band of image data.
  648.      * If the image uses an IndexColorModel which
  649.      * has alpha in the lookup table, this method will return null since
  650.      * there is no spatially discrete alpha channel.
  651.      * This method will create a new Raster (but will share the data
  652.      * array).
  653.      */
  654.     public WritableRaster getAlphaRaster() {
  655.         // No Alpha
  656.         if (colorModel.hasAlpha() == false) {
  657.             return null;
  658.         }
  659.  
  660.         // IndexColorModel -- so no spatially discrete alpha
  661.         if (colorModel instanceof IndexColorModel) {
  662.             return null;
  663.         }
  664.         
  665.         // For now, assume the alpha channel is the last band in the raster.
  666.         int x = raster.getMinX();
  667.         int y = raster.getMinY();
  668.         int[] band = new int[1];
  669.         band[0] = raster.getNumBands() - 1;
  670.         return raster.createWritableSubRaster(x, y, raster.getWidth(),
  671.                                                raster.getHeight(), x, y,
  672.                                                band);
  673.     }
  674.  
  675.     /**
  676.      * Returns an integer pixel in the default RGB color model
  677.      * (TYPE_INT_ARGB) and default sRGB colorspace.  Color
  678.      * conversion will take place if this default model does not match
  679.      * the image ColorModel.  There are only 8-bits of precision
  680.      * for each color component in the returned data when using this method.
  681.      */
  682.     public int getRGB(int x, int y) {
  683.         return colorModel.getRGB(raster.getPixelData(x, y, null));
  684.     }
  685.  
  686.     /**
  687.      * Returns an array of integer pixels in the default RGB color model
  688.      * (TYPE_INT_ARGB) and default sRGB color space,
  689.      * from a portion of the image data.  Color conversion will take place
  690.      * if the default model does not match the image ColorModel.  There
  691.      * are only 8-bits of precision for each color component in
  692.      * the returned data when
  693.      * using this method.  Given a coordinate (x,y) in the image, the
  694.      * ARGB pixel can be accessed using the following:
  695.      * <pre>
  696.      *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)];
  697.      * </pre>
  698.      * @param startX      Starting x Coordinate
  699.      * @param startY      Starting y Coordinate
  700.      * @param w           Width of region
  701.      * @param h           Height of region
  702.      * @param rgbArray    If non-null, the rgb pixels will be written here
  703.      * @param offset      Offset into the rgbArray
  704.      * @param scansize    Scanline stride for the rgbArray
  705.      * @return            Array of RGB pixels.
  706.      */
  707.     public int[] getRGB(int startX, int startY, int w, int h,
  708.                         int[] rgbArray, int offset, int scansize) {
  709.         int yoff  = offset;
  710.         int off;
  711.         Object data;
  712.         int nbands = raster.getNumBands();
  713.         int dataType = raster.getDataBuffer().getDataType();
  714.         switch (dataType) {
  715.         case DataBuffer.BYTE_DATA:
  716.             data = new byte[nbands];
  717.             break;
  718.         case DataBuffer.SHORT_DATA:
  719.             data = new short[nbands];
  720.             break;
  721.         case DataBuffer.INT_DATA:
  722.             data = new int[nbands];
  723.             break;
  724.         case DataBuffer.LONG_DATA:
  725.             data = new long[nbands];
  726.             break;
  727.         case DataBuffer.FLOAT_DATA:
  728.             data = new float[nbands];
  729.             break;
  730.         case DataBuffer.DOUBLE_DATA:
  731.             data = new double[nbands];
  732.             break;
  733.         default:
  734.             throw new IllegalArgumentException("Unknown data buffer type: "+
  735.                                                dataType);
  736.         }
  737.  
  738.         if (rgbArray == null) {
  739.             rgbArray = new int[offset+h*scansize];
  740.         }
  741.  
  742.         for (int y = startY; y < startY+h; y++, yoff+=scansize) {
  743.             off = yoff;
  744.             for (int x = startX; x < startX+w; x++) {
  745.                 rgbArray[off++] = colorModel.getRGB(raster.getPixelData(x,
  746.                                     y,
  747.                                     data));
  748.             }
  749.         }
  750.  
  751.         return rgbArray;
  752.     }
  753.  
  754.     
  755.     /**
  756.      * Set a pixel in a BufferedImage.  The pixel is assumed
  757.      * to be in the default RGB color model (TYPE_INT_ARGB) and
  758.      * default sRGB color space.  For images with an
  759.      * IndexColorModel, the index with the nearest color will be
  760.      * chosen.
  761.      */
  762.     public synchronized void setRGB(int x, int y, int rgb) {
  763.         raster.setPixelData(x, y, colorModel.getPixelData(rgb, null));
  764.     }
  765.  
  766.     /**
  767.      * Sets an array of integer pixels in the default RGB color model
  768.      * (TYPE_INT_ARGB) and default sRGB color space,
  769.      * into a portion of the image data.  Color conversion will take place
  770.      * if the default model does not match the image ColorModel.  There
  771.      * are only 8-bits of precision for each color component in
  772.      * the returned data when
  773.      * using this method.  Given a coordinate (x,y) in the image, the
  774.      * ARGB pixel can be accessed using the following:
  775.      * <pre>
  776.      *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)];
  777.      * </pre>
  778.      * WARNING: No dithering will take place.
  779.      *
  780.      * @param startX      Starting x Coordinate
  781.      * @param startY      Starting y Coordinate
  782.      * @param w           Width of region
  783.      * @param h           Height of region
  784.      * @param rgbArray    The rgb pixels
  785.      * @param offset      Offset into the rgbArray
  786.      * @param scansize    Scanline stride for the rgbArray
  787.      */
  788.     public void setRGB(int startX, int startY, int w, int h,
  789.                         int[] rgbArray, int offset, int scansize) {
  790.         int yoff  = offset;
  791.         int off;
  792.         Object pixel = null;
  793.  
  794.         for (int y = startY; y < startY+h; y++, yoff+=scansize) {
  795.             off = yoff;
  796.             for (int x = startX; x < startX+w; x++) {
  797.                 pixel = colorModel.getPixelData(rgbArray[off], pixel);
  798.                 raster.setPixelData(x, y, pixel);
  799.             }
  800.         }
  801.     }
  802.  
  803.     
  804.     /**
  805.      * Returns the width of the BufferedImage.
  806.      */
  807.     public int getWidth() {
  808.         return raster.getWidth();
  809.     }
  810.  
  811.     /**
  812.      * Returns the height of the BufferedImage.
  813.      */
  814.     public int getHeight() {
  815.         return raster.getHeight();
  816.     }
  817.  
  818.     /**
  819.      * Returns the actual width of the image.  If the width is not known
  820.      * yet, then the ImageObserver will be notified later and -1 will
  821.      * be returned.
  822.      * @see java.awt.Image#getHeight
  823.      * @see java.awt.ImageObserver
  824.      */
  825.     public int getWidth(ImageObserver observer) {
  826.         return raster.getWidth();
  827.     }
  828.  
  829.     /**
  830.      * Returns the actual height of the image.  If the height is not known
  831.      * yet, then the ImageObserver will be notified later and -1 will
  832.      * be returned.
  833.      * @see java.awt.Image#getWidth
  834.      * @see ImageObserver
  835.      */
  836.     public int getHeight(ImageObserver observer) {
  837.         return raster.getHeight();
  838.     }
  839.  
  840.     /**
  841.      * Returns the object that produces the pixels for the image.  This
  842.      * returns null.
  843.      * @see ImageProducer
  844.      */
  845.     public ImageProducer getSource() {
  846.         return null;
  847.     }
  848.  
  849.  
  850.     /**
  851.      * Returns a property of the image by name.  Individual property names
  852.      * are defined by the various image formats.  If a property is not
  853.      * defined for a particular image, this method will return the
  854.      * UndefinedProperty object.  If the properties for this image are
  855.      * not yet known, then this method will return null and the ImageObserver
  856.      * object will be notified later.  The property name "comment" should
  857.      * be used to store an optional comment which can be presented to
  858.      * the user as a description of the image, its source, or its author.
  859.      * @see ImageObserver
  860.      * @see java.awt.Image#UndefinedProperty
  861.      */
  862.     public Object getProperty(String name, ImageObserver observer) {
  863.         return null;
  864.     }
  865.  
  866.     /**
  867.      * Returns a property of the image by name.
  868.      */
  869.     public Object getProperty(String name) {
  870.         return null;
  871.     }
  872.  
  873.     /**
  874.      * Flushes all resources being used to cache optimization information.
  875.      * The underlying pixel data is unaffected.
  876.      */
  877.     public void flush() {
  878.     }
  879.  
  880.  
  881.     /**
  882.      * This method will actually return a Graphics2D but is here
  883.      * for backwards compatibility.
  884.      * @deprecated
  885.      */
  886.     public java.awt.Graphics getGraphics() {
  887.     return createGraphics();
  888.     }
  889.  
  890.     /**
  891.      * Creates a Graphics2D, which can be used to draw into this
  892.      * BufferedImage.
  893.      */
  894.     public Graphics2D createGraphics() {
  895.     GraphicsEnvironment env =
  896.         GraphicsEnvironment.getLocalGraphicsEnvironment();
  897.     return env.createGraphics(this);
  898.     }
  899.  
  900.     /**
  901.      * Returns a subimage given a rectangular region.
  902.      * The returned BufferedImage will share the same
  903.      * data array as the original image.
  904.      */
  905.     public BufferedImage getSubimage (int x, int y, int w, int h) {
  906.         return new BufferedImage (colorModel,
  907.                                   raster.createWritableSubRaster(x, y, w, h,
  908.                                                                  0, 0, null),
  909.                                   colorModel.isAlphaPremultiplied());
  910.     }
  911.  
  912.     /**
  913.      * Returns whether or not the alpha has been premultiplied.  It
  914.      * will return true if there is no alpha since the default alpha
  915.      * is OPAQUE.
  916.      */
  917.     public boolean isAlphaPremultiplied() {
  918.         return colorModel.isAlphaPremultiplied();
  919.     }
  920.  
  921.     /**
  922.      * Forces the data to match the state specified in the
  923.      * isAlphaPremultiplied variable.  It may multiply or divide the
  924.      * color Raster data by alpha, or do nothing if the data is
  925.      * in the correct state.
  926.      */
  927.     public void coerceData (boolean isAlphaPremultiplied) {
  928.         if (colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
  929.             // Make the color model do the conversion
  930.             colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
  931.         }
  932.     }
  933.  
  934.     public String toString() {
  935.         return new String("BufferedImage@"+Integer.toHexString(hashCode())
  936.                           +": type = "+imageType
  937.                           +" "+colorModel+" "+raster);
  938.     }
  939.  
  940.     /** 
  941.      * Return a vector of RenderedImages that are the sources of 
  942.      * Image data for this RenderedImage.  Note that this method 
  943.      * will often return null.
  944.      */
  945.     public Vector getSources() {
  946.         return null;
  947.     }
  948.  
  949.     /** 
  950.      * Return a list of names recognized by getProperty(String). 
  951.      */
  952.     public String[] getPropertyNames() {
  953.          return null;
  954.     }
  955.  
  956.     /** 
  957.      * Return the minimum x coordinate of the rendered image. For some 
  958.      * image with infinite extent, it could be int.MIN_VALUE.
  959.      */
  960.     public int getMinXCoord() {
  961.         return raster.getMinX();
  962.     }
  963.  
  964.     /** 
  965.      * Return the maximum x coordinate of the rendered image. For some 
  966.      * image with infinite extent, it could be int.MAX_VALUE.
  967.      */
  968.     public int getMaxXCoord() {
  969.         return raster.getMinX() + raster.getWidth();
  970.     }
  971.  
  972.     /** 
  973.      * Return the minimum y coordinate of the rendered image. For some 
  974.      * image with infinite extent, it could be int.MIN_VALUE.
  975.      */
  976.     public int getMinYCoord() {
  977.         return raster.getMinY();
  978.     }
  979.  
  980.     /** 
  981.      * Return the minimum y coordinate of the rendered image. For some 
  982.      * image with infinite extent, it could be int.MAX_VALUE.
  983.      */
  984.     public int getMaxYCoord() {
  985.         return raster.getMinY() + raster.getHeight();
  986.     }
  987.  
  988.     /** Return the sample model associated with this image */
  989.     public SampleModel getSampleModel() {
  990.         return raster.getSampleModel();
  991.     }
  992.  
  993.     /** Return the number of tiles across the image */
  994.     public int tilesAcross() {
  995.         return 1;
  996.     }
  997.  
  998.     /** Return the number of tiles down the image */
  999.     public int tilesDown() {
  1000.         return 1;
  1001.     }
  1002.  
  1003.     /** Return the index of the min tile in the x direction of the image */
  1004.     public int getMinTileX() {
  1005.         return 0;
  1006.     }
  1007.  
  1008.     /** Return the index of the max tile in the x direction of the image */
  1009.     public int getMaxTileX() {
  1010.         return 0;
  1011.     }
  1012.  
  1013.     /** Return the index of the min tile in the y direction of the image */
  1014.     public int getMinTileY() {
  1015.         return 0;
  1016.     }
  1017.  
  1018.     /** Return the index of the max tile in the y direction of the image */ 
  1019.     public int getMaxTileY(){
  1020.         return 0;
  1021.     }
  1022.  
  1023.     /** Return the width of tile in pixel */
  1024.     public int getTileWidth() {
  1025.        return raster.getSampleModel().getWidth();
  1026.     }
  1027.  
  1028.     /** Return the height of the tile in pixel */
  1029.     public int getTileHeight() {
  1030.        return raster.getSampleModel().getHeight();
  1031.     }
  1032.  
  1033.     /** Return the X offset of tile grid relative to the origin */
  1034.     public int getTileGridXOffset() {
  1035.         return raster.getBaseRasterOriginX();
  1036.     }
  1037.     
  1038.     /** Return the Y offset of tile grid relative to the origin */
  1039.     public int getTileGridYOffset() {
  1040.         return raster.getBaseRasterOriginY();
  1041.     }
  1042.     
  1043.     /** 
  1044.      * Return tile# x, y.  Note that x and y are indexes into the
  1045.      * tile array not pixel locations.  The Raster that is returned
  1046.      * is live and will be updated if the image is changed.
  1047.      * @param x the x index of the requested tile in the tile array
  1048.      * @param y the y index of the requested tile in the tile array
  1049.      */
  1050.     public Raster getTile(int x, int y) {
  1051.         if (x == 0 && y == 0) {
  1052.             return raster;
  1053.         }
  1054.         throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
  1055.              " one tile with index 0,0");
  1056.     }
  1057.  
  1058.     /** 
  1059.      * Return the image as one large tile (for tile based 
  1060.      * images this will require fetching the whole image 
  1061.      * and copying the image data over).  The Raster returned is
  1062.      * semantically a copy.  
  1063.      */
  1064.     public Raster getData() {
  1065.  
  1066.         // REMIND : this allocates a whole new tile if raster is a
  1067.         // subtile.  (It only copies in the requested area)
  1068.         // We should do something smarter.
  1069.         int width = raster.getWidth();
  1070.         int height = raster.getHeight();
  1071.         int startX = raster.getMinX();
  1072.         int startY = raster.getMinY();
  1073.         WritableRaster wr = 
  1074.            Raster.createWritableRaster(raster.getSampleModel(),
  1075.                              new Point(raster.getBaseRasterOriginX(),
  1076.                                        raster.getBaseRasterOriginY()));
  1077.  
  1078.         Object tdata = null;
  1079.  
  1080.         for (int i = startY; i < startY+height; i++)  {
  1081.             tdata = raster.getPixelData(startX,i,width,1,tdata);
  1082.             wr.setPixelData(startX,i,width,1, tdata);
  1083.         }
  1084.         return wr;
  1085.     }
  1086.     
  1087.     /** 
  1088.      * Compute and return an arbitrary region of the RenderedImage. 
  1089.      * Note that in general this may involve copying image data.
  1090.      * The Raster returned is semantically a copy.
  1091.      * @param rect the region of the RenderedImage to be returned.
  1092.      */
  1093.     public Raster getRect(Rectangle rect) {
  1094.         SampleModel sm = raster.getSampleModel();
  1095.         SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
  1096.                                                          rect.height);
  1097.         WritableRaster wr = Raster.createWritableRaster(nsm,
  1098.                                                   rect.getLocation());
  1099.         int width = rect.width;
  1100.         int height = rect.height;
  1101.         int startX = rect.x;
  1102.         int startY = rect.y;
  1103.  
  1104.         Object tdata = null;
  1105.  
  1106.         for (int i = startY; i < startY+height; i++)  {
  1107.             tdata = raster.getPixelData(startX,i,width,1,tdata);
  1108.             wr.setPixelData(startX,i,width,1, tdata);
  1109.         }
  1110.         return wr;
  1111.     }
  1112.  
  1113.     /** 
  1114.      * Compute an arbitrary rectangular region of the RenderedImage
  1115.      * and copy it into a caller-supplied WritableRaster.  The region
  1116.      * to be computed is determined from the bounds of the supplied
  1117.      * WritableRaster.  The supplied WritableRaster must have a ColorModel
  1118.      * and SampleModel that are compatible with those of this image.
  1119.      * @param raster a WritableRaster to hold the returned part of the image.
  1120.      * @return a reference to the supplied WritableRaster.
  1121.      */
  1122.     public WritableRaster getRect(WritableRaster outRaster) {
  1123.         int width = outRaster.getWidth();
  1124.         int height = outRaster.getHeight();
  1125.         int startX = outRaster.getMinX();
  1126.         int startY = outRaster.getMinY();
  1127.  
  1128.         Object tdata = null;
  1129.  
  1130.         for (int i = startY; i < startY+height; i++)  {
  1131.             tdata = raster.getPixelData(startX,i,width,1,tdata);
  1132.             outRaster.setPixelData(startX,i,width,1, tdata);
  1133.         }
  1134.  
  1135.         return outRaster;
  1136.     }
  1137.  
  1138.     /**
  1139.      * Set a rect of the image to the contents of rb.
  1140.      */
  1141.     public void setRect(Raster rb) {
  1142.         int width = rb.getWidth();
  1143.         int height = rb.getHeight();
  1144.         int startX = rb.getMinX();
  1145.         int startY = rb.getMinY();
  1146.  
  1147.         int[] tdata = null;
  1148.  
  1149.         // remind use get/setPixelPixelData for speed if Rasters are
  1150.         // compatible
  1151.         for (int i = startY; i < startY+height; i++)  {
  1152.             tdata = rb.getPixel(startX,i,width,1,tdata);
  1153.             raster.setPixel(startX,i,width,1, tdata);
  1154.         }
  1155.     }
  1156.  
  1157.     /** Forward work to a TileChangeMulticaster. */
  1158.     public void addTileChangeListener (TileChangeListener tcl) {
  1159.         tcm.addTileChangeListener(tcl);
  1160.     }
  1161.     
  1162.     /** Forward work to a TileChangeMulticaster. */
  1163.     public void removeTileChangeListener (TileChangeListener tcl) {
  1164.         tcm.removeTileChangeListener(tcl);
  1165.     }
  1166.    
  1167.     /** Forward work to a TileChangeMulticaster. */
  1168.     public TileChangeListener[] getTileChangeListeners () {
  1169.         return tcm.getTileChangeListeners();
  1170.     }
  1171.    
  1172.     /** Forward work to a TileChangeMulticaster. */
  1173.     public boolean isTileWritable (int tileX, int tileY) {
  1174.         return tcm.isTileWritable(tileX, tileY);
  1175.     }
  1176.     
  1177.     /** Forward work to a TileChangeMulticaster. */
  1178.     public Point[] getWritableTiles () {
  1179.         return tcm.getWritableTiles();
  1180.     }
  1181.     
  1182.     /** Forward work to a TileChangeMulticaster. */
  1183.     public boolean hasTileWriters () {
  1184.         return tcm.hasTileWriters();
  1185.     }
  1186.  
  1187.     public WritableRaster getWritableTile (int tileX, int tileY) {
  1188.         tcm.addTileWriter(this, tileX, tileY);
  1189.         return raster;
  1190.     }
  1191.   
  1192.     public void releaseWritableTile (int tileX, int tileY) {
  1193.         tcm.removeTileWriter(this, tileX, tileY);
  1194.     }
  1195. }
  1196.  
  1197.  
  1198.