This is the mail archive of the java-patches@sources.redhat.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: java.awt.image (revised)


I'm checking this in, (unless anybody has any objections). It's
basically the same patch that I posted earlier, except that I've
followed Tom's suggestions concerning the utility classes. Also, a
compiler workaround that was part of the previous patch has been
removed, as it's no longer needed.


2000-07-25  Rolf W. Rasmussen  <rolfwr@ii.uib.no>

        * libjava/java/awt/image/ColorModel.java: New file, replaces the
        stub libjava/java/awt/ColorModel.java which was located in the
        wrong package.
        * libjava/java/awt/image/ComponentColorModel.java: New file.
        * libjava/java/awt/image/ComponentSampleModel.java: New file.
        * libjava/java/awt/image/DataBuffer.java: New file.
        * libjava/java/awt/image/DataBufferByte.java: New file.
        * libjava/java/awt/image/DataBufferInt.java: New file.
        * libjava/java/awt/image/DataBufferUShort.java: New file.
        * libjava/java/awt/image/DirectColorModel.java: New file.
        * libjava/java/awt/image/PackedColorModel.java: New file.
        * libjava/java/awt/image/Raster.java: New file.
        * libjava/java/awt/image/SampleModel.java: New file.
        * libjava/java/awt/image/SinglePixelPackedSampleModel.java: New
        file.
        * libjava/java/awt/image/IndexColorModel.java: New file.
        * libjava/java/awt/image/ImageConsumer.java: Removed import of
        java.awt.ColorModel stub.

        * gnu/gcj/util/BitMaskExtent.java: New file, utility class.
        * gnu/gcj/util/Buffers.java: New file, utility class.

        * libjava/Makefile.am: Updated to include new files.
        * libjava/Makefile.in: Rebuilt.


Index: libjava/Makefile.am
===================================================================
RCS file: /cvs/java/libgcj/libjava/Makefile.am,v
retrieving revision 1.71
diff -u -r1.71 Makefile.am
--- Makefile.am	2000/07/23 00:24:14	1.71
+++ Makefile.am	2000/07/25 15:34:23
@@ -486,6 +486,8 @@
 special_java_source_files = java/lang/Class.java java/lang/Object.java
 
 awt_java_source_files =	\
+gnu/gcj/awt/BitMaskExtent.java \
+gnu/gcj/awt/Buffers.java \
 java/awt/AWTError.java \
 java/awt/AWTEvent.java \
 java/awt/AWTEventMulticaster.java \
@@ -495,7 +497,6 @@
 java/awt/BorderLayout.java \
 java/awt/CheckboxGroup.java \
 java/awt/Color.java \
-java/awt/ColorModel.java \
 java/awt/Component.java	\
 java/awt/ComponentOrientation.java \
 java/awt/Container.java	\
@@ -535,6 +536,9 @@
 java/awt/Toolkit.java \
 java/awt/Transparency.java \
 java/awt/Window.java \
+java/awt/color/ColorSpace.java \
+java/awt/color/ICC_ColorSpace.java \
+java/awt/color/ICC_Profile.java \
 java/awt/event/AWTEventListener.java \
 java/awt/event/ActionEvent.java	\
 java/awt/event/ActionListener.java \
@@ -582,9 +586,23 @@
 java/awt/geom/Point2D.java \
 java/awt/geom/Rectangle2D.java \
 java/awt/geom/RectangularShape.java \
+java/awt/image/ColorModel.java \
+java/awt/image/ComponentColorModel.java \
+java/awt/image/ComponentSampleModel.java \
+java/awt/image/DataBuffer.java \
+java/awt/image/DataBufferByte.java \
+java/awt/image/DataBufferInt.java \
+java/awt/image/DataBufferUShort.java \
+java/awt/image/DirectColorModel.java \
 java/awt/image/ImageConsumer.java \
 java/awt/image/ImageObserver.java \
 java/awt/image/ImageProducer.java \
+java/awt/image/IndexColorModel.java \
+java/awt/image/PackedColorModel.java \
+java/awt/image/Raster.java \
+java/awt/image/SampleModel.java \
+java/awt/image/SinglePixelPackedSampleModel.java \
+java/awt/image/WritableRaster.java \
 java/awt/peer/ButtonPeer.java \
 java/awt/peer/CanvasPeer.java \
 java/awt/peer/CheckboxMenuItemPeer.java	\
Index: libjava/gnu/gcj/awt/BitMaskExtent.java
===================================================================
RCS file: BitMaskExtent.java
diff -N BitMaskExtent.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ BitMaskExtent.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,51 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package gnu.gcj.awt;
+
+/** 
+ * Simple transparent utility class that can be used to perform bit
+ * mask extent calculations.
+ */
+public final class BitMaskExtent
+{
+  /** The number of the least significant bit of the bit mask extent. */
+  public byte leastSignificantBit;
+
+  /** The number of bits in the bit mask extent. */
+  public byte bitWidth;
+  
+  /**
+   * Set the bit mask. This will calculate and set the leastSignificantBit
+   * and bitWidth fields.
+   *
+   * @see #leastSignificantBit
+   * @see #bitWidth
+   */
+  public void setMask(long mask)
+  {
+    leastSignificantBit = 0;
+    bitWidth = 0;
+    if (mask == 0) return;
+    long shiftMask = mask;
+    for (; (shiftMask&1) == 0; shiftMask >>>=1) leastSignificantBit++;
+    for (; (shiftMask&1) != 0; shiftMask >>>=1) bitWidth++;
+    
+    if (shiftMask != 0)
+      throw new IllegalArgumentException("mask must be continuous");
+  }
+  
+  /** 
+   * Calculate the bit mask based on the values of the
+   * leastSignificantBit and bitWidth fields.
+   */
+  public long toMask()
+  {
+    return ((1<<bitWidth)-1) << leastSignificantBit;
+  }  
+}
Index: libjava/gnu/gcj/awt/Buffers.java
===================================================================
RCS file: Buffers.java
diff -N Buffers.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ Buffers.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,168 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package gnu.gcj.awt;
+
+import java.awt.image.*;
+
+/** 
+ * Utility class for creating and accessing data buffers of arbitrary
+ * data types.
+ */
+public final class Buffers
+{
+  /**
+   * Create a data buffer of a particular type.
+   *
+   * @param dataType the desired data type of the buffer.
+   * @param data an array containing data, or null
+   * @param size the size of the data buffer bank
+   */
+  public static DataBuffer createBuffer(int dataType, Object data,
+					int size)
+  {
+    if (data == null) return createBuffer(dataType, size, 1);
+
+    return createBufferFromData(dataType, data, size);
+  }
+
+
+  /**
+   * Create a data buffer of a particular type.
+   *
+   * @param dataType the desired data type of the buffer.
+   * @param size the size of the data buffer bank
+   */
+  public static DataBuffer createBuffer(int dataType, int size) {
+    return createBuffer(dataType, size, 1);
+  }
+
+  /**
+   * Create a data buffer of a particular type.
+   *
+   * @param dataType the desired data type of the buffer.
+   * @param size the size of the data buffer bank
+   * @param numBanks the number of banks the buffer should have
+   */
+  public static DataBuffer createBuffer(int dataType, int size, int numBanks)
+  {
+    switch (dataType)
+      {
+      case DataBuffer.TYPE_BYTE:
+	return new DataBufferByte(size, numBanks);
+      case DataBuffer.TYPE_USHORT:
+	return new DataBufferUShort(size, numBanks);
+      case DataBuffer.TYPE_INT:
+	return new DataBufferInt(size, numBanks);
+      default:
+	throw new UnsupportedOperationException();
+      }
+  }
+  
+  /**
+   * Create a data buffer of a particular type.
+   *
+   * @param dataType the desired data type of the buffer
+   * @param data an array containing the data
+   * @param size the size of the data buffer bank
+   */
+  public static DataBuffer createBufferFromData(int dataType, Object data,
+						int size)
+  {
+    switch (dataType)
+      {
+      case DataBuffer.TYPE_BYTE:
+	return new DataBufferByte((byte[]) data, size);
+      case DataBuffer.TYPE_USHORT:
+	return new DataBufferUShort((short[]) data, size);
+      case DataBuffer.TYPE_INT:
+	return new DataBufferInt((int[]) data, size);
+      default:
+	throw new UnsupportedOperationException();
+      }
+  }
+
+  /** 
+   * Return the data array of a data buffer, regardless of the data
+   * type.
+   *
+   * @return an array of primitive values. The actual array type
+   * depends on the data type of the buffer.
+   */
+  public static Object getData(DataBuffer buffer)
+  {
+    if (buffer instanceof DataBufferByte)
+      return ((DataBufferByte) buffer).getData();
+    if (buffer instanceof DataBufferUShort)
+      return ((DataBufferUShort) buffer).getData();
+    if (buffer instanceof DataBufferInt)
+      return ((DataBufferInt) buffer).getData();
+    throw new ClassCastException("Unknown data buffer type");
+  }
+
+    
+  /**
+   * Copy data from array contained in data buffer, much like
+   * System.arraycopy. Create a suitable destination array if the
+   * given destination array is null.
+   */
+  public static Object getData(DataBuffer src, int srcOffset,
+			       Object dest,  int destOffset,
+			       int length)
+  {
+    Object from;
+    if (src instanceof DataBufferByte)
+      {
+	from = ((DataBufferByte) src).getData();
+	if (dest == null) dest = new byte[length+destOffset];
+      }
+    else if (src instanceof DataBufferUShort)
+      {
+	from = ((DataBufferUShort) src).getData();
+	if (dest == null) dest = new short[length+destOffset];
+      }
+    else if (src instanceof DataBufferInt)
+      {
+	from = ((DataBufferInt) src).getData();
+	if (dest == null) dest = new int[length+destOffset];
+      }
+    else
+      {
+	throw new ClassCastException("Unknown data buffer type");
+      }
+    
+    System.arraycopy(from, srcOffset, dest, destOffset, length);
+    return dest;
+  }
+  
+  /**
+   * @param bits the width of a data element measured in bits
+   *
+   * @return the smallest data type that can store data elements of
+   * the given number of bits, without any truncation.
+   */
+  public static int smallestAppropriateTransferType(int bits)
+  {
+    if (bits <= 8)
+      {
+	return DataBuffer.TYPE_BYTE;
+      }
+    else if (bits <= 16)
+      {
+	return DataBuffer.TYPE_USHORT;
+      } 
+    else if (bits <= 32)
+      {
+	return DataBuffer.TYPE_INT;
+      }
+    else
+      {
+	return DataBuffer.TYPE_UNDEFINED;
+      }
+  }
+}
Index: libjava/java/awt/ColorModel.java
===================================================================
RCS file: ColorModel.java
diff -N ColorModel.java
--- /sourceware/cvs-tmp/cvsO9xcfB	Tue Jul 25 08:34:29 2000
+++ /dev/null	Tue May  5 13:32:27 1998
@@ -1,20 +0,0 @@
-/* Copyright (C) 2000  Free Software Foundation
-
-   This file is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
-details.  */
-
-package java.awt;
-
-/* Status: Just a placeholder. */
-
-public class ColorModel implements Transparency
-{
-  public int getTransparency()
-  {
-    // FIXME
-    return 0;  
-  }
-}
Index: libjava/java/awt/color/ColorSpace.java
===================================================================
RCS file: ColorSpace.java
diff -N ColorSpace.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ColorSpace.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,111 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.color;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public abstract class ColorSpace
+{
+  public static final int TYPE_XYZ   = 0;
+  public static final int TYPE_Lab   = 1;
+  public static final int TYPE_Luv   = 2;
+  public static final int TYPE_YCbCr = 3;
+  public static final int TYPE_Yxy   = 4;
+  public static final int TYPE_RGB   = 5;
+  public static final int TYPE_GRAY  = 6;
+  public static final int TYPE_HSV   = 7;
+  public static final int TYPE_HLS   = 8;
+  public static final int TYPE_CMYK  = 9;
+  // mysterious gap in the enumeration sequenece
+  public static final int TYPE_CMY  = 11;
+  public static final int TYPE_2CLR = 12;
+  public static final int TYPE_3CLR = 13;
+  public static final int TYPE_4CLR = 14;
+  public static final int TYPE_5CLR = 15;
+  public static final int TYPE_6CLR = 16;
+  public static final int TYPE_7CLR = 17;
+  public static final int TYPE_8CLR = 18;
+  public static final int TYPE_9CLR = 19;
+  public static final int TYPE_ACLR = 20;
+  public static final int TYPE_BCLR = 21;
+  public static final int TYPE_CCLR = 22;
+  public static final int TYPE_DCLR = 23;
+  public static final int TYPE_ECLR = 24;
+  public static final int TYPE_FCLR = 25;
+  
+  public static final int CS_sRGB       = 1000;
+  public static final int CS_CIEXYZ     = 1001;
+  public static final int CS_PYCC       = 1002;
+  public static final int CS_GRAY       = 1003;
+  public static final int CS_LINEAR_RGB = 1004;
+  
+  private static final int CS_BASE  = CS_sRGB;
+  private static final int CS_END   = CS_LINEAR_RGB+1;
+  private static final int CS_COUNT = CS_END - CS_BASE;
+  
+  // Instances are lazily instantiated
+  private static final ColorSpace[] INSTANCES = new ColorSpace[CS_COUNT];
+
+  private int type;
+  private int numcomponents;
+  protected ColorSpace(int type, int numcomponents)
+  {
+    this.type = type;
+    this.numcomponents = numcomponents;
+  }
+	
+  public static ColorSpace getInstance(int colorspace)
+  {
+    if ((colorspace >= CS_BASE) && (colorspace < CS_END))
+      {
+	int instanceIndex = colorspace - CS_BASE;
+	if (INSTANCES[instanceIndex] == null)
+	  {
+	    ICC_Profile profile = new ICC_Profile(colorspace);
+	    INSTANCES[instanceIndex] = new ICC_ColorSpace(profile);
+	  }
+	return INSTANCES[instanceIndex];
+      }
+    throw new IllegalArgumentException("unknown/unsupported colorspace");
+  }
+  
+  public boolean isCS_sRGB()
+  {
+    return false;
+  }
+
+  public abstract float[] toRGB(float[] colorvalue);
+  
+  public abstract float[] fromRGB(float[] rgbvalue);
+  
+  public abstract float[] toCIEXYZ(float[] colorvalue);
+  
+  public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+  public int getType()
+  {
+    return type;
+  }
+
+  public int getNumComponents()
+  {
+    return numcomponents;
+  }
+  
+  public String getName(int idx)
+  {
+    return "type " + type;
+  }
+  
+  public String toString()
+  {
+    return getClass().getName() + "[type=" + type + "]";
+  }
+}
Index: libjava/java/awt/color/ICC_ColorSpace.java
===================================================================
RCS file: ICC_ColorSpace.java
diff -N ICC_ColorSpace.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ICC_ColorSpace.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,53 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.color;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class ICC_ColorSpace extends ColorSpace
+{
+  private ICC_Profile profile;
+
+  public ICC_ColorSpace(ICC_Profile profile)
+  {
+    super(CS_sRGB, profile.getNumComponents());
+    
+    this.profile = profile;
+  }
+
+  public ICC_Profile getProfile()
+  {
+    return profile;
+  }
+
+  public float[] toRGB(float[] colorvalue)
+  {
+    // FIXME: Always assumes sRGB:
+    return colorvalue;
+  }
+
+  public float[] fromRGB(float[] rgbvalue)
+  {
+    // FIXME: Always assumes sRGB:
+    return rgbvalue;
+  }
+
+  public float[] toCIEXYZ(float[] colorvalue)
+  {
+    // FIXME: Not implemented
+    throw new UnsupportedOperationException();
+  }
+
+  public float[] fromCIEXYZ(float[] colorvalue)
+  {
+    // FIXME: Not implemented
+    throw new UnsupportedOperationException();
+  }
+}
Index: libjava/java/awt/color/ICC_Profile.java
===================================================================
RCS file: ICC_Profile.java
diff -N ICC_Profile.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ICC_Profile.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,40 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.color;
+
+// Currently just a stub.
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class ICC_Profile
+{
+  long profileID; // why long?
+  
+  ICC_Profile(long profileID)
+  {
+    this.profileID = profileID;
+  }
+
+  public int getNumComponents()
+  {
+    switch (profileID)
+      {
+      case ColorSpace.CS_sRGB:
+      case ColorSpace.CS_LINEAR_RGB:
+      case ColorSpace.CS_CIEXYZ:
+	return 3;
+      case ColorSpace.CS_GRAY:
+	return 1;
+      case ColorSpace.CS_PYCC:    // have no clue about this one
+      default:
+	throw new UnsupportedOperationException("profile not implemented");
+      }
+  }
+}
Index: libjava/java/awt/image/ColorModel.java
===================================================================
RCS file: ColorModel.java
diff -N ColorModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ColorModel.java	Tue Jul 25 08:34:24 2000
@@ -0,0 +1,575 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import gnu.gcj.awt.Buffers;
+
+/**
+ * A color model operates with colors in several formats:
+ *
+ * <ul>
+ * <li>normalized: component samples are in range [0.0, 1.0].</li>
+ *
+ * <li>color model pixel value: all the color component samples for a
+ * sigle pixel packed/encoded in a way natural for the color
+ * model.</li>
+ *
+ * <li>color model pixel int value: only makes sense if the natural
+ * encoding of a single pixel can fit in a single int value.</li>
+ *
+ * <li>array of transferType containing a single pixel: the pixel is
+ * encoded in the natural way of the color model, taking up as many
+ * array elements as needed.</li>
+ *
+ * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in
+ * default 0xAARRGGBB format, assumed not alpha premultiplied.</li>
+ * 
+ * <li>single [0, 255] scaled int samples from default sRGB color
+ * space. These are always assumed to be alpha non-premultiplied.</li>
+ *
+ * <li>arrays of unnormalized component samples of single pixel: these
+ * samples are scaled and multiplied according to the color model, but
+ * is otherwise not packed or encoded. Each element of the array is one
+ * seperate component sample. The color model only operate on the
+ * components from one pixel at a time, but using offsets, allows
+ * manipulation of arrays that contain the components of more than one
+ * pixel.</li>
+ *
+ * </ul>
+ *
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+
+public abstract class ColorModel implements Transparency
+{
+  protected int pixel_bits;
+  protected int transferType;
+
+  private int[] bits;
+  private ColorSpace cspace;
+  private int transparency;
+  private boolean hasAlpha;
+  private boolean isAlphaPremultiplied;
+    
+  static int[] nArray(int value, int times)
+  {
+    int[] array = new int[times];
+    java.util.Arrays.fill(array, value);
+    return array;
+  }
+
+  static byte[] nArray(byte value, int times)
+  {
+    byte[] array = new byte[times];
+    java.util.Arrays.fill(array, value);
+    return array;
+  } 
+
+  public ColorModel(int bits)
+  {
+    this(bits * 4, // total bits, sRGB, four channels
+	 nArray(bits, 4), // bits for each channel
+	 null, // FIXME: should be sRGB
+	 true, // has alpha
+	 false, // not premultiplied
+	 TRANSLUCENT,
+	 Buffers.smallestAppropriateTransferType(bits * 4));
+  }
+
+  protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
+		       boolean hasAlpha, boolean isAlphaPremultiplied,
+		       int transparency, int transferType)
+  {
+    this.pixel_bits = pixel_bits;
+    this.bits = bits;
+    this.cspace = cspace;
+    this.hasAlpha = hasAlpha;
+    this.isAlphaPremultiplied = isAlphaPremultiplied;
+    this.transparency = transparency;
+    this.transferType = transferType;
+  }
+
+  public static ColorModel getRGBdefault()
+  {
+    return new DirectColorModel(8, 0xff0000, 0xff00, 0xff, 0xff000000);
+  }
+
+  public final boolean hasAlpha()
+  {
+    return hasAlpha;
+  }
+
+  public final boolean isAlphaPremultiplied()
+  {
+    return isAlphaPremultiplied;
+  }
+
+  public int getPixelSize()
+  {
+    return pixel_bits;
+  }
+    
+  public int getComponentSize(int componentIdx)
+  {
+    return bits[componentIdx];
+  }
+    
+  public int[] getComponentSize()
+  {
+    return bits;
+  }
+
+  public int getTransparency()
+  {
+    return transparency;
+  }
+
+  public int getNumComponents()
+  {
+    return getNumColorComponents() + (hasAlpha ? 1 : 0);
+  }
+
+  public int getNumColorComponents()
+  {
+    return cspace.getNumComponents();
+  }
+
+  /**
+   * Converts pixel value to sRGB and extract red int sample scaled
+   * to range [0, 255].
+   *
+   * @param pixel pixel value that will be interpreted according to
+   * the color model, (assumed alpha premultiplied if color model says
+   * so.)
+   *
+   * @return red sample scaled to range [0, 255], from default color
+   * space sRGB, alpha non-premultiplied.
+   */
+  public abstract int getRed(int pixel);
+
+  /**
+   * Converts pixel value to sRGB and extract green int sample
+   * scaled to range [0, 255].
+   *
+   * @see #getRed(int)
+   */
+    public abstract int getGreen(int pixel);
+    
+  /**
+   * Converts pixel value to sRGB and extract blue int sample
+   * scaled to range [0, 255].
+   *
+   * @see #getRed(int)
+   */
+  public abstract int getBlue(int pixel);
+
+  /**
+   * Extract alpha int sample from pixel value, scaled to [0, 255].
+   *
+   * @param pixel pixel value that will be interpreted according to
+   * the color model.
+   *
+   * @return alpha sample, scaled to range [0, 255].
+   */
+  public abstract int getAlpha(int pixel);
+
+  /**
+   * Converts a pixel int value of the color space of the color
+   * model to a sRGB pixel int value.
+   *
+   * This method is typically overriden in subclasses to provide a
+   * more efficient implementation.
+   * 
+   * @param pixel pixel value that will be interpreted according to
+   * the color model.
+   *
+   * @return a pixel in sRGB color space, encoded in default
+   * 0xAARRGGBB format.  */
+  public int getRGB(int pixel)
+  {
+    return 
+      ((getAlpha(pixel) & 0xff) << 24) |
+      ((  getRed(pixel) & 0xff) << 16) |
+      ((getGreen(pixel) & 0xff) <<  8) |
+      (( getBlue(pixel) & 0xff) <<  0);
+  }
+  
+
+  /**
+   * In this color model we know that the whole pixel value will
+   * always be contained within the first element of the pixel
+   * array.
+   */
+  final int getPixelFromArray(Object inData) {
+    DataBuffer data =
+      Buffers.createBufferFromData(transferType, inData, 1);
+    Object da = Buffers.getData(data);
+
+    return data.getElem(0);
+  }
+
+  /** 
+   * Converts pixel in the given array to sRGB and extract blue int
+   * sample scaled to range [0-255].
+   *
+   * This method is typically overriden in subclasses to provide a
+   * more efficient implementation.
+   * 
+   * @param array of transferType containing a single pixel.  The
+   * pixel should be encoded in the natural way of the color model.
+   */
+  public int getRed(Object inData)
+  {
+    return getRed(getPixelFromArray(inData));
+  }
+
+  /**
+   * @see #getRed(Object)
+   */
+  public int getGreen(Object inData)
+  {
+    return getGreen(getPixelFromArray(inData));
+  }
+
+  /**
+   * @see #getRed(Object)
+   */
+  public int getBlue(Object inData) {
+    return getBlue(getPixelFromArray(inData));
+  }
+
+  /**
+   * @see #getRed(Object)
+   */
+  public int getAlpha(Object inData) {
+    return getBlue(getPixelFromArray(inData));
+  }
+
+  /**
+   * Converts a pixel in the given array of the color space of the
+   * color model to an sRGB pixel int value.
+   *
+   * <p>This method performs the inverse function of
+   * <code>getDataElements(int rgb, Object pixel)</code>.
+   * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb,
+   * null)))</code>.
+   *
+   * @param inData array of transferType containing a single pixel. The
+   * pixel should be encoded in the natural way of the color model.
+   *
+   * @return a pixel in sRGB color space, encoded in default
+   * 0xAARRGGBB format.
+   *
+   * @see #getDataElements(int, Object)
+   */
+  public int getRGB(Object inData)
+  {
+    return 
+      ((getAlpha(inData) & 0xff) << 24) |
+      ((  getRed(inData) & 0xff) << 16) |
+      ((getGreen(inData) & 0xff) <<  8) |
+      (( getBlue(inData) & 0xff) <<  0);
+  }
+
+  /**
+   * Converts an sRGB pixel int value to an array containing a
+   * single pixel of the color space of the color model.
+   * 
+   * <p>This method performs the inverse function of
+   * <code>getRGB(Object inData)</code>.
+   *
+   * Outline of conversion process:
+   *
+   * <ol>
+   *
+   * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li>
+   *
+   * <li>Convert to color space components using fromRGB in
+   * ColorSpace.</li>
+   *
+   * <li>If color model has alpha and should be premultiplied,
+   * multiply color space components with alpha value</li>
+   *
+   * <li>Scale the components to the correct number of bits.</li>
+   *
+   * <li>Arrange the components in the output array</li>
+   * 
+   * </ol>
+   *
+   * @param rgb The color to be converted to dataElements.  A pixel
+   * in sRGB color space, encoded in default 0xAARRGGBB format,
+   * assumed not alpha premultiplied.
+   *
+   * @param pixel to avoid needless creation of arrays, an array to
+   * use to return the pixel can be given. If null, a suitable array
+   * will be created.
+   *
+   * @return An array of transferType values representing the color,
+   * in the color model format. The color model defines whether the
+   *  
+   * @see #getRGB(Object)
+   */
+  public Object getDataElements(int rgb, Object pixel)
+  {
+    // FIXME: implement
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Fills an array with the unnormalized component samples from a
+   * pixel value. I.e. decompose the pixel, but not perform any
+   * color conversion. 
+   *
+   * This method is typically overriden in subclasses to provide a
+   * more efficient implementation.
+   * 
+   * @param pixel pixel value encoded according to the color model.
+   *
+   * @return arrays of unnormalized component samples of single
+   * pixel.  The scale and multiplication state of the samples are
+   * according to the color model. Each component sample is stored
+   * as a seperate element in the array.
+   */
+  public int[] getComponents(int pixel, int[] components, int offset) {
+    // FIXME: implement
+    throw new UnsupportedOperationException();
+  }
+  
+  /**
+   * Fills an array with the unnormalized component samples from an
+   * array of transferType containing a single pixel. I.e. decompose
+   * the pixel, but not perform any color conversion.
+   *
+   * This method is typically overriden in subclasses to provide a
+   * more efficient implementation.
+   *
+   * @param array of transferType containing a single pixel.  The
+   * pixel should be encoded in the natural way of the color model.
+   * 
+   * @return arrays of unnormalized component samples of single
+   * pixel.  The scale and multiplication state of the samples are
+   * according to the color model. Each component sample is stored
+   * as a seperate element in the array.
+   */
+  public int[] getComponents(Object pixel, int[] components, int offset)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * Convert normalized components to unnormalized components.
+   */
+  public int[] getUnnormalizedComponents(float[] normComponents,
+					 int normOffset,
+					 int[] components,
+					 int offset)
+  {
+    int numComponents = getNumComponents();
+    if (components == null)
+    {
+      components = new int[offset + numComponents];
+    }
+    
+    for (int i=0; i<numComponents; i++)
+    {
+      float in = normComponents[normOffset++];
+      int out = (int) (in * ((2<<getComponentSize(i)) - 1));
+      components[offset++] = out;
+    }
+    return components;
+  }
+
+  /**
+   * Convert unnormalized components to normalized components.
+   */
+  public float[] getNormalizedComponents(int[] components,
+					 int offset,
+					 float[] normComponents,
+					 int normOffset)
+  {
+    int numComponents = getNumComponents();
+    if (normComponents == null)
+    {
+      normComponents = new float[normOffset + numComponents];
+    }
+
+    for (int i=0; i<numComponents; i++)
+    {
+      float in = components[offset++];
+      float out = in / ((2<<getComponentSize(i)) - 1);
+      normComponents[normOffset++] = out;
+    }
+    return normComponents;
+  }
+
+  /**
+   * Converts the unnormalized component samples from an array to a
+   * pixel value. I.e. composes the pixel from component samples, but
+   * does not perform any color conversion or scaling of the samples.
+   * 
+   * This method performs the inverse function of
+   * <code>getComponents(int pixel, int[] components,
+   *			       int offset)</code>. I.e.
+   *
+   * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null,
+   * 0), 0))</code>.
+   *
+   * This method is typically overriden in subclasses to provide a
+   * more efficient implementation.
+   *
+   * @param arrays of unnormalized component samples of single
+   * pixel.  The scale and multiplication state of the samples are
+   * according to the color model. Each component sample is stored
+   * as a seperate element in the array.
+   *
+   * @return pixel value encoded according to the color model.
+   */
+  public int getDataElement(int[] components, int offset)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public Object getDataElements(int[] components, int offset, Object obj)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof ColorModel)) return false;
+
+    ColorModel o = (ColorModel) obj;
+    return 
+      (pixel_bits == o.pixel_bits) &&
+      (transferType == o.transferType) &&
+      (transparency == o.transparency) &&
+      (hasAlpha == o.hasAlpha) &&
+      (isAlphaPremultiplied == isAlphaPremultiplied) &&
+      (bits.equals(o.bits)) &&
+      (cspace.equals(o.cspace));
+  }
+
+  public final ColorSpace getColorSpace()
+  {
+    return cspace;
+  }
+
+  // Typically overridden
+  public ColorModel coerceData(WritableRaster raster,
+			       boolean isAlphaPremultiplied)
+  {
+    if (this.isAlphaPremultiplied == isAlphaPremultiplied)
+      return this;
+
+    int w = raster.getWidth();
+    int h = raster.getHeight();
+    int x = raster.getMinX();
+    int y = raster.getMinY();
+    int size = w*h;
+    int numColors = getNumColorComponents();
+    int numComponents = getNumComponents();
+    int alphaScale = (1<<getComponentSize(numColors)) - 1;
+    double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
+
+    for (int i=0; i<size; i++)
+      {
+	double alpha = pixels[i*numComponents+numColors]*alphaScale;
+	for (int c=0; c<numColors; c++)
+	  {
+	    int offset = i*numComponents+c;
+	    if (isAlphaPremultiplied)
+		pixels[offset] = pixels[offset]/alpha;
+	    else
+	      pixels[offset] = pixels[offset]*alpha;
+	  }
+      }
+    
+    raster.setPixels(0, 0, w, h, pixels);
+
+    // FIXME: what can we return?
+    return null;
+  }
+    
+  // Typically overridden
+  public boolean isCompatibleRaster(Raster raster)
+  {
+    SampleModel sampleModel = raster.getSampleModel();
+    return isCompatibleSampleModel(sampleModel);
+  }
+
+  // Typically overridden
+  public WritableRaster createCompatibleWritableRaster(int w, int h)
+  {
+    return new WritableRaster(createCompatibleSampleModel(w, h),
+			      new Point(0, 0));
+  }
+
+  // Typically overridden
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    throw new UnsupportedOperationException();
+  }
+
+  // Typically overridden
+  public boolean isCompatibleSampleModel(SampleModel sm)
+  {
+    return sm.getTransferType() == transferType;
+  }
+
+  public void finalize() {
+  }
+
+  /**
+   * Subclasses must override this method if it is possible for the
+   * color model to have an alpha channel.
+   *
+   * @return null, as per JDK 1.3 doc. Subclasses will only return
+   * null if no alpha raster exists.
+   */
+  public WritableRaster getAlphaRaster(WritableRaster raster)
+  {
+    return null;
+    
+    /* It is a mystery to me why we couldn't use the following code...
+       
+       
+       if (!hasAlpha()) return null;
+       
+       SampleModel sm = raster.getSampleModel();
+       int[] alphaBand = { sm.getNumBands() - 1 };
+       SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
+       DataBuffer buffer = raster.getDataBuffer();
+       Point origin = new Point(0, 0);
+       return Raster.createWritableRaster(alphaModel, buffer, origin);
+       
+
+       ...here, and avoided overriding the method in subclasses,
+       but the Sun docs state that this method always will return
+       null, and that overriding is required. Oh, well.
+    */
+  }
+
+  String stringParam()
+  {
+    return "pixel_bits=" + pixel_bits +
+      ", cspace=" + cspace +
+      ", transferType=" + transferType +
+      ", transparency=" + transparency +
+      ", hasAlpha=" + hasAlpha +
+      ", isAlphaPremultiplied=" + isAlphaPremultiplied;
+  }
+
+  public String toString()
+  {
+    return getClass().getName() + "[" + stringParam() + "]";
+  }
+}
Index: libjava/java/awt/image/ComponentColorModel.java
===================================================================
RCS file: ComponentColorModel.java
diff -N ComponentColorModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ComponentColorModel.java	Tue Jul 25 08:34:25 2000
@@ -0,0 +1,303 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.color.*;
+import java.awt.Point;
+import gnu.gcj.awt.Buffers;
+
+public class ComponentColorModel extends ColorModel
+{
+  private static int sum(int[] values)
+  {
+    int sum = 0;
+    for (int i=0; i<values.length; i++)
+      sum += values[i];
+    return sum;
+  }
+
+  public ComponentColorModel(ColorSpace colorSpace, int[] bits,
+			     boolean hasAlpha,
+			     boolean isAlphaPremultiplied,
+			     int transparency, int transferType)
+  {
+    super(sum(bits), bits, colorSpace, hasAlpha, isAlphaPremultiplied,
+	  transparency, transferType);
+  }
+
+  public int getRed(int pixel)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    return (int) getRGBFloat(pixel)[0];
+  }
+
+  public int getGreen(int pixel)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    return (int) getRGBFloat(pixel)[0];
+  }
+  
+  public int getBlue(int pixel)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    return (int) getRGBFloat(pixel)[0];
+  }
+
+  public int getAlpha(int pixel)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    int shift = 8 - getComponentSize(getNumColorComponents());
+    if (shift >= 0) return pixel << shift;
+    return pixel >> (-shift);
+  }
+   
+  public int getRGB(int pixel)
+  {
+    float[] rgb = getRGBFloat(pixel);
+    int ret = getRGB(rgb);
+    if (hasAlpha()) ret |= getAlpha(pixel) << 24;
+    return ret;
+  }
+
+
+  /* FIXME: Is the values returned from toRGB() in the [0.0, 1.0] or the
+     [0.0, 256) range? 
+     
+     we assume it is in the [0.0, 1.0] range along with the
+     other color spaces. */
+  
+  /* Note, it's OK to pass a to large array to toRGB(). Extra
+     elements are ignored. */
+  
+  private float[] getRGBFloat(int pixel)
+  {
+    float[] data = { pixel };
+    return cspace.toRGB(data);
+  }
+
+  private float[] getRGBFloat(Object inData)
+  {
+    DataBuffer buffer =
+    Buffers.createBufferFromData(transferType, inData,
+				 getNumComponents());
+    int colors = getNumColorComponents();
+    float[] data = new float[colors];
+    
+    // FIXME: unpremultiply data that is premultiplied
+    for (int i=0; i<colors; i++)
+      {
+	float maxValue = (1<<getComponentSize(i))-1;
+	data[i] = buffer.getElemFloat(i)/maxValue; 
+      }
+    float[] rgb = cspace.toRGB(data);
+    return rgb;
+  }
+  
+  public int getRed(Object inData)
+  {
+    return (int) getRGBFloat(inData)[0]*255;
+  }
+
+  public int getGreen(Object inData)
+  {
+    return (int) getRGBFloat(inData)[1]*255;
+  }
+
+  public int getBlue(Object inData)
+  {
+    return (int) getRGBFloat(inData)[2]*255;
+  }
+
+  public int getAlpha(Object inData)
+  {
+    DataBuffer buffer =
+      Buffers.createBufferFromData(transferType, inData,
+				   getNumComponents());
+    int shift = 8 - getComponentSize(getNumColorComponents());
+    int alpha = buffer.getElem(getNumColorComponents());
+    if (shift >= 0) return alpha << shift;
+    return alpha >> (-shift);
+  }
+
+  private int getRGB(float[] rgb)
+  {
+    /* NOTE: We could cast to byte instead of int here. This would
+       avoid bits spilling over from one bit field to
+       another. But, if we assume that floats are in the [0.0,
+       1.0] range, this will never happen anyway. */
+    
+    /* Remember to multiply BEFORE casting to int, otherwise, decimal
+       point data will be lost. */
+    int ret =
+      (((int) (rgb[0]*255F)) << 16) |
+      (((int) (rgb[1]*255F)) <<  8) |
+      (((int) (rgb[2]*255F)) <<  0);
+    return ret;
+  }
+
+  /**
+   * @param inData pixel data of transferType, as returned by the
+   * getDataElements method in SampleModel.
+   */
+  public int getRGB(Object inData)
+  {
+    float[] rgb = getRGBFloat(inData);
+    int ret = getRGB(rgb);
+    if (hasAlpha()) ret |= getAlpha(inData) << 24;
+    return ret;
+  }
+
+  public Object getDataElements(int rgb, Object pixel)
+  {
+    // Convert rgb to [0.0, 1.0] sRGB values.
+    float[] rgbFloats = {
+      ((rgb >> 16)&0xff)/255.0F,
+      ((rgb >>  8)&0xff)/255.0F,
+      ((rgb >>  0)&0xff)/255.0F
+    };
+
+    // Convert from rgb to color space components.
+    float[] data = cspace.fromRGB(rgbFloats);
+    DataBuffer buffer = Buffers.createBuffer(transferType, pixel,
+					     getNumComponents());
+    int numColors = getNumColorComponents();
+    
+    if (hasAlpha())
+      {
+	float alpha = ((rgb >> 24)&0xff)/255.0F;
+	
+	/* If color model has alpha and should be premultiplied, multiply
+	   color space components with alpha value. */
+	if (isAlphaPremultiplied()) {
+	  for (int i=0; i<numColors; i++)
+	    data[i] *= alpha;
+	}
+	// Scale the alpha sample to the correct number of bits.
+	alpha *= (1<<(bits[numColors]-1));
+	// Arrange the alpha sample in the output array.
+	buffer.setElemFloat(numColors, alpha);
+      }
+    for (int i=0; i<numColors; i++)
+      {
+	// Scale the color samples to the correct number of bits.
+	float value = data[i]*(1<<(bits[i]-1));
+	// Arrange the color samples in the output array.
+	buffer.setElemFloat(i, value);
+      }
+    return Buffers.getData(buffer);
+  }
+
+  public int[] getComponents(int pixel, int[] components, int offset)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    if (components == null)
+    components = new int[getNumComponents() + offset];
+    components[offset] = pixel;
+    return components;
+  }
+
+  public int[] getComponents(Object pixel, int[] components, int offset)
+  {
+    DataBuffer buffer = Buffers.createBuffer(transferType, pixel,
+					     getNumComponents());
+    int numComponents = getNumComponents();
+
+    if (components == null)
+      components = new int[numComponents + offset];
+
+    for (int i=0; i<numComponents; i++)
+      components[offset++] = buffer.getElem(i);
+
+    return components;
+  }
+
+  public int getDataElement(int[] components, int offset)
+  {
+    if (getNumComponents()>1) throw new IllegalArgumentException();
+    return components[offset];
+  }
+
+  public Object getDataElements(int[] components, int offset, Object obj)
+  {
+    DataBuffer buffer = Buffers.createBuffer(transferType, obj,
+					     getNumComponents());
+    int numComponents = getNumComponents();
+
+    for (int i=0; i<numComponents; i++)
+      buffer.setElem(i, components[offset++]);
+
+    return Buffers.getData(buffer);
+  }
+
+  public ColorModel coerceData(WritableRaster raster,
+			       boolean isAlphaPremultiplied) {
+    if (this.isAlphaPremultiplied == isAlphaPremultiplied)
+      return this;
+
+    /* TODO: provide better implementation based on the
+       assumptions we can make due to the specific type of the
+       color model. */
+    super.coerceData(raster, isAlphaPremultiplied);
+    
+    return new ComponentColorModel(cspace, bits, hasAlpha(),
+				   isAlphaPremultiplied, // argument
+				   transparency, transferType);
+  }
+
+  public boolean isCompatibleRaster(Raster raster)
+  {
+    return super.isCompatibleRaster(raster);
+    // FIXME: Should we test something more here? (Why override?)
+  }
+
+  public WritableRaster createCompatibleWritableRaster(int w, int h)
+  {
+    SampleModel sm = createCompatibleSampleModel(w, h);
+    Point origin = new Point(0, 0);
+    return Raster.createWritableRaster(sm, origin);
+  }
+
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    int pixelStride = getNumComponents();
+    
+    /* TODO: Maybe we don't need to create a new offset array each
+       time, but rather use the same array every time. */
+    int[] bandOffsets = new int[pixelStride];
+    for (int i=0; i<pixelStride; i++) bandOffsets[i] = i;
+    return new ComponentSampleModel(transferType, w, h,
+				    pixelStride, pixelStride*w,
+				    bandOffsets);
+  }
+
+  public boolean isCompatibleSampleModel(SampleModel sm)
+  {
+    return 
+      (sm instanceof ComponentSampleModel) &&
+      super.isCompatibleSampleModel(sm);
+  }
+
+  public WritableRaster getAlphaRaster(WritableRaster raster)
+  {
+    if (!hasAlpha()) return null;
+    
+    SampleModel sm = raster.getSampleModel();
+    int[] alphaBand = { sm.getNumBands() - 1 };
+    SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
+    DataBuffer buffer = raster.getDataBuffer();
+    Point origin = new Point(0, 0);
+    return Raster.createWritableRaster(alphaModel, buffer, origin);
+  }
+    
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof ComponentColorModel)) return false;
+    return super.equals(obj);
+  }
+}
Index: libjava/java/awt/image/ComponentSampleModel.java
===================================================================
RCS file: ComponentSampleModel.java
diff -N ComponentSampleModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ ComponentSampleModel.java	Tue Jul 25 08:34:25 2000
@@ -0,0 +1,435 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import gnu.gcj.awt.Buffers;
+
+/* FIXME: This class does not yet support data type TYPE_SHORT */
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class ComponentSampleModel extends SampleModel
+{
+  protected int[] bandOffsets;
+  protected int[] bankIndices;
+  
+  // FIXME: Should we really shadow the numBands in the superclass?
+  //protected int numBands;
+  
+  /** Used when creating data buffers. */
+  protected int numBanks;
+
+  protected int scanlineStride;
+  
+  protected int pixelStride;
+  
+  private boolean tightPixelPacking = false;
+  
+  public ComponentSampleModel(int dataType,
+			      int w, int h,
+			      int pixelStride,
+			      int scanlineStride,
+			      int[] bandOffsets)
+  {
+    this(dataType, w, h, pixelStride, scanlineStride,
+	 new int[bandOffsets.length], bandOffsets);
+  }
+    
+  public ComponentSampleModel(int dataType,
+			      int w, int h,
+			      int pixelStride,
+			      int scanlineStride,
+			      int[] bankIndices,
+			      int[] bandOffsets)
+  {
+    super(dataType, w, h, bandOffsets.length);
+    if ((pixelStride<0) || (scanlineStride<0) || 
+	(bandOffsets.length<1) ||
+	(bandOffsets.length != bankIndices.length))
+      throw new IllegalArgumentException();
+    
+    this.bandOffsets = bandOffsets;
+    this.bankIndices = bankIndices;
+
+    for (int b=0; b<bankIndices.length; b++)
+      this.numBanks = Math.max(this.numBanks, bankIndices[b]+1);
+
+    this.scanlineStride = scanlineStride;
+    this.pixelStride = pixelStride;
+
+    // See if we can use some speedups
+
+    /* FIXME: May these checks should be reserved for the
+       PixelInterleavedSampleModel? */
+	
+    if (pixelStride == numBands)
+      {
+	tightPixelPacking = true;
+	for (int b=0; b<numBands; b++) {
+	  if ((bandOffsets[b] != b) || (bankIndices[b] !=0))
+	    {
+	      tightPixelPacking = false;
+	      break;
+	    }
+	}
+      }
+  }		
+
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    return new ComponentSampleModel(dataType, w, h, pixelStride,
+				    scanlineStride, bankIndices,
+				    bandOffsets);
+  }
+
+  public SampleModel createSubsetSampleModel(int[] bands)
+  {
+    int numBands = bands.length;
+    
+    int[] bankIndices = new int[numBands];
+    int[] bandOffsets = new int[numBands];
+    for (int b=0; b<numBands; b++)
+      {
+	bankIndices[b] = this.bankIndices[bands[b]];
+	bandOffsets[b] = this.bandOffsets[bands[b]];
+      }
+
+    return new ComponentSampleModel(dataType, width, height, pixelStride,
+				    scanlineStride, bankIndices,
+				    bandOffsets);
+  }
+
+  public DataBuffer createDataBuffer()
+  {
+    // Maybe this value should be precalculated in the constructor?
+    int highestOffset = 0;
+    for (int b=0; b<numBands; b++)
+      {
+	highestOffset = Math.max(highestOffset, bandOffsets[b]);
+      }
+    int size = pixelStride*(width-1) + scanlineStride*(height-1) +
+      highestOffset + 1;
+    
+    return Buffers.createBuffer(getDataType(), size, numBanks);
+  }
+
+  public int getOffset(int x, int y)
+  {
+    return getOffset(x, y, 0);
+  }
+
+  public int getOffset(int x, int y, int b)
+  {
+    return bandOffsets[b] + pixelStride*x + scanlineStride*y;
+  }
+
+  public final int[] getSampleSize()
+  {
+    int size = DataBuffer.getDataTypeSize(getDataType());
+    int[] sizes = new int[numBands];
+
+    java.util.Arrays.fill(sizes, size);
+    return sizes;
+  }
+
+  public final int getSampleSize(int band)
+  {
+    return DataBuffer.getDataTypeSize(getDataType());
+  }
+
+  public final int[] getBankIndices()
+  {
+    return bankIndices;
+  }
+
+  public final int[] getBandOffsets()
+  {
+    return bandOffsets;
+  }
+
+  public final int getScanlineStride()
+  {
+    return scanlineStride;
+  }
+
+  public final int getPixelStride()
+  {
+    return pixelStride;
+  }
+
+  public final int getNumDataElements()
+  {
+    return numBands;
+  }
+
+  public Object getDataElements(int x, int y, Object obj, DataBuffer data)
+  {
+    int xyOffset = pixelStride*x + scanlineStride*y;
+    
+    int[] totalBandDataOffsets = new int[numBands];
+    
+    /* Notice that band and bank offsets are different. Band offsets
+       are managed by the sample model, and bank offsets are managed
+       by the data buffer. Both must be accounted for. */
+    
+    /* FIXME: For single pixels, it is probably easier to simple
+       call getElem instead of calculating the bank offset ourself.
+       
+       On the other hand, then we need to push the value through
+       the int type returned by the getElem method.  */
+    
+    int[] bankOffsets = data.getOffsets();
+    
+    for (int b=0; b<numBands; b++)
+      {
+	totalBandDataOffsets[b] = 
+	  bandOffsets[b]+bankOffsets[bankIndices[b]] + xyOffset;
+      }
+	
+    try
+      {
+	switch (getTransferType())
+	  {
+	  case DataBuffer.TYPE_BYTE:
+	    DataBufferByte inByte = (DataBufferByte) data;
+	    byte[] outByte = (byte[]) obj;
+	    if (outByte == null) outByte = new byte[numBands];
+		
+	    for (int b=0; b<numBands; b++)
+	      {
+		int dOffset = totalBandDataOffsets[b];
+		outByte[b] = inByte.getData(bankIndices[b])[dOffset];
+	      }
+	    return outByte;
+		
+	  case DataBuffer.TYPE_USHORT:
+	    DataBufferUShort inUShort = (DataBufferUShort) data;
+	    short[] outUShort = (short[]) obj;
+	    if (outUShort == null) outUShort = new short[numBands];
+		
+	    for (int b=0; b<numBands; b++)
+	      {
+		int dOffset = totalBandDataOffsets[b];
+		outUShort[b] = inUShort.getData(bankIndices[b])[dOffset];
+	      }
+	    return outUShort;
+
+	  case DataBuffer.TYPE_INT:
+	    DataBufferInt inInt = (DataBufferInt) data;
+	    int[] outInt = (int[]) obj;
+	    if (outInt == null) outInt = new int[numBands];
+		
+	    for (int b=0; b<numBands; b++)
+	      {
+		int dOffset = totalBandDataOffsets[b];
+		outInt[b] = inInt.getData(bankIndices[b])[dOffset];
+	      }
+	    return outInt;
+		
+	    // FIXME: Fill in the other possible types.
+	  default:
+	      throw new IllegalStateException("unknown transfer type " +
+					      getTransferType());
+	  }
+      }
+    catch (ArrayIndexOutOfBoundsException aioobe)
+      {
+	String msg = "While reading data elements, " +
+	  "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset +
+	  ", data.getSize()=" + data.getSize() + ": " + aioobe;
+	throw new ArrayIndexOutOfBoundsException(msg);
+      }
+  }
+
+  public Object getDataElements(int x, int y, int w, int h, Object obj,
+				DataBuffer data)
+  {
+    if (!tightPixelPacking)
+      {
+	return super.getDataElements(x, y, w, h, obj, data);
+      }
+
+    // using get speedup
+    
+    // We can copy whole rows
+    int rowSize = w*numBands;
+    int dataSize = rowSize*h;
+    
+    DataBuffer transferBuffer =
+      Buffers.createBuffer(getTransferType(), obj, dataSize);
+    obj = Buffers.getData(transferBuffer);
+
+    int inOffset =
+      pixelStride*x +
+      scanlineStride*y +
+      data.getOffset(); // Assumes only one band is used
+
+    /* We don't add band offsets since we assume that bands have
+       offsets 0, 1, 2, ... */
+
+    // See if we can copy everything in one go
+    if (scanlineStride == rowSize)
+      {
+	// Collapse scan lines:
+	rowSize *= h;
+	// We ignore scanlineStride since it won't be of any use
+	h = 1;
+      }
+
+    int outOffset = 0;
+    Object inArray = Buffers.getData(data);
+    for (int yd = 0; yd<h; yd++)
+      {
+	System.arraycopy(inArray, inOffset, obj, outOffset, rowSize);
+	inOffset  += scanlineStride;
+	outOffset += rowSize;
+      }
+    return obj;
+  }
+
+  public void setDataElements(int x, int y, int w, int h,
+			      Object obj, DataBuffer data)
+  {
+    if (!tightPixelPacking)
+      {
+	super.setDataElements(x, y, w, h, obj, data);
+	return;
+      }
+
+    // using set speedup, we can copy whole rows
+    int rowSize = w*numBands;
+    int dataSize = rowSize*h;
+    
+    DataBuffer transferBuffer =
+      Buffers.createBufferFromData(getTransferType(), obj, dataSize);
+
+    int[] bankOffsets = data.getOffsets();
+
+    int outOffset =
+      pixelStride*x +
+      scanlineStride*y +
+      bankOffsets[0]; // same assuptions as in get...
+
+    // See if we can copy everything in one go
+    if (scanlineStride == rowSize)
+      {
+	// Collapse scan lines:
+	scanlineStride = rowSize *= h;
+	h = 1;
+      }
+
+    int inOffset = 0;
+    Object outArray = Buffers.getData(data);
+    for (int yd = 0; yd<h; yd++)
+      {
+	System.arraycopy(obj, inOffset, outArray, outOffset, rowSize);
+	outOffset += scanlineStride;
+	inOffset  += rowSize;
+      }
+  }
+
+  public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    int offset = pixelStride*x + scanlineStride*y;
+    if (iArray == null) iArray = new int[numBands];
+    for (int b=0; b<numBands; b++)
+      {
+	iArray[b] = data.getElem(bankIndices[b], offset+bandOffsets[b]);
+      }
+    return iArray;
+  }
+
+  public int[] getPixels(int x, int y, int w, int h, int[] iArray,
+			 DataBuffer data)
+  {
+    int offset = pixelStride*x + scanlineStride*y;
+    if (iArray == null) iArray = new int[numBands*w*h];
+    int outOffset = 0;
+    for (y=0; y<h; y++)
+      {
+	int lineOffset = offset;
+	for (x=0; x<w; x++)
+	  {
+	    for (int b=0; b<numBands; b++)
+	      {
+		iArray[outOffset++] = 
+		  data.getElem(bankIndices[b], lineOffset+bandOffsets[b]);
+	      }
+	    lineOffset += pixelStride;
+	  }
+	offset += scanlineStride;
+      }
+    return iArray;
+  }
+    
+  public int getSample(int x, int y, int b, DataBuffer data)
+  {
+    return data.getElem(bankIndices[b], getOffset(x, y, b));
+  }
+
+  public void setDataElements(int x, int y, Object obj, DataBuffer data)
+  {
+    int offset = pixelStride*x + scanlineStride*y;
+    int[] totalBandDataOffsets = new int[numBands];
+    int[] bankOffsets = data.getOffsets();
+    for (int b=0; b<numBands; b++)
+      totalBandDataOffsets[b] =
+	bandOffsets[b]+bankOffsets[bankIndices[b]] + offset;
+
+    switch (getTransferType())
+      {
+      case DataBuffer.TYPE_BYTE:
+	{
+	  DataBufferByte out = (DataBufferByte) data;
+	  byte[] in = (byte[]) obj;
+	  
+	  for (int b=0; b<numBands; b++)
+	    out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
+	  
+	  return;
+	}
+      case DataBuffer.TYPE_USHORT:
+	{
+	  DataBufferUShort out = (DataBufferUShort) data;
+	  short[] in = (short[]) obj;
+	  
+	  for (int b=0; b<numBands; b++)
+	    out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
+	  
+	  return;
+	}
+      case DataBuffer.TYPE_INT:
+	{
+	  DataBufferInt out = (DataBufferInt) data;
+	  int[] in = (int[]) obj;
+	  
+	  for (int b=0; b<numBands; b++)
+	    out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
+	  
+	  return;
+	}
+      default:
+	throw new UnsupportedOperationException("transfer type not " +
+						"implemented");
+      }
+  }
+  
+  public void setPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    int offset = pixelStride*x + scanlineStride*y;
+    for (int b=0; b<numBands; b++)
+      data.setElem(bankIndices[b], offset+bandOffsets[b], iArray[b]);
+  }
+    
+  public void setSample(int x, int y, int b, int s, DataBuffer data)
+  {
+    data.setElem(bankIndices[b], getOffset(x, y, b), s);
+  }
+}
Index: libjava/java/awt/image/DataBuffer.java
===================================================================
RCS file: DataBuffer.java
diff -N DataBuffer.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ DataBuffer.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,177 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+/** 
+ * Class that manages arrays of data elements. A data buffer consists
+ * of one or more banks.  A bank is a continuous region of data
+ * elements.
+ *
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public abstract class DataBuffer
+{
+  public static final int TYPE_BYTE      =  0;
+  public static final int TYPE_USHORT    =  1;
+  public static final int TYPE_SHORT     =  2;
+  public static final int TYPE_INT       =  3;
+  public static final int TYPE_FLOAT     =  4;
+  public static final int TYPE_DOUBLE    =  5;
+  public static final int TYPE_UNDEFINED = 32;
+  
+  /** The type of the data elements stored in the data buffer.  */
+  protected int dataType;
+  
+  /** The number of banks in this buffer.  */
+  protected int banks = 1;
+  
+  /** Offset into the default (0'th) bank). */
+  protected int offset; // FIXME: Is offsets[0] always mirrored in offset?
+  
+  /** The size of the banks.  */
+  protected int size;
+  
+  /** Offset into each bank.  */
+  protected int[] offsets;
+  
+  protected DataBuffer(int dataType, int size)
+  {
+    this.dataType = dataType;
+    this.size = size;
+  }
+
+  protected DataBuffer(int dataType, int size, int numBanks) {
+    this(dataType, size);
+    banks = numBanks;
+    offsets = new int[numBanks];
+  }
+
+  protected DataBuffer(int dataType, int size, int numBanks, int offset) {
+    this(dataType, size, numBanks);
+    
+    java.util.Arrays.fill(offsets, offset);          
+    
+    this.offset = offset;
+  }
+
+  protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) {
+    this(dataType, size);
+    if (numBanks != offsets.length) 
+      throw new ArrayIndexOutOfBoundsException();
+    
+    banks = numBanks;
+    this.offsets = offsets;
+    
+    offset = offsets[0];
+  }
+  
+  public static int getDataTypeSize(int dataType) {
+    // Maybe this should be a lookup table instead.
+    switch (dataType)
+      {
+      case TYPE_BYTE:
+	return 8;
+      case TYPE_USHORT:
+      case TYPE_SHORT:
+	return 16;
+      case TYPE_INT:
+      case TYPE_FLOAT:
+	return 32;
+      case TYPE_DOUBLE:
+	return 64;
+      default:
+	throw new IllegalArgumentException();
+      }
+  }
+
+  public int getDataType()
+  {
+    return dataType;
+  }
+  
+  public int getSize()
+  {
+    return size;
+  }
+  
+  public int getOffset()
+  {
+    return offset;
+  }
+  
+  public int[] getOffsets()
+  {
+    if (offsets == null)
+    {
+      // is this necessary?
+      offsets = new int[1];
+      offsets[0] = offset;
+    }
+    return offsets;
+  }
+
+  public int getNumBanks()
+  {
+    return banks;
+  }
+
+  public int getElem(int i)
+  {
+    return getElem(0, i);
+  }
+
+  public abstract int getElem(int bank, int i);
+  
+  public void setElem(int i, int val)
+  {
+    setElem(0, i, val);
+  }
+
+  public abstract void setElem(int bank, int i, int val);
+  
+  public float getElemFloat(int i)
+  {
+    return getElem(i);
+  }
+    
+  public float getElemFloat(int bank, int i)
+  {
+    return getElem(bank, i);
+  }
+
+  public void setElemFloat(int i, float val)
+  {
+    setElem(i, (int) val);
+  }
+
+  public void setElemFloat(int bank, int i, float val)
+  {
+    setElem(bank, i, (int) val);
+  }
+
+  public double getElemDouble(int i)
+  {
+    return getElem(i);
+  }
+    
+  public double getElemDouble(int bank, int i)
+  {
+    return getElem(bank, i);
+  }
+
+  public void setElemDouble(int i, double val)
+  {
+    setElem(i, (int) val);
+  }
+
+  public void setElemDouble(int bank, int i, double val)
+  {
+    setElem(bank, i, (int) val);
+  }
+}
Index: libjava/java/awt/image/DataBufferByte.java
===================================================================
RCS file: DataBufferByte.java
diff -N DataBufferByte.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ DataBufferByte.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,103 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+/* This is one of several classes that are nearly identical. Maybe we
+   should have a central template and generate all these files. This
+   is one of the cases where templates or macros would have been
+   useful to have in Java.
+
+   This file has been created using search-replace. My only fear is
+   that these classes will grow out-of-sync as of a result of changes
+   that are not propagated to the other files. As always, mirroring
+   code is a maintenance nightmare.  */
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class DataBufferByte extends DataBuffer
+{
+  private byte[] data;
+  private byte[][] bankData;
+  
+  public DataBufferByte(int size)
+  {
+    super(TYPE_BYTE, size);
+    data = new byte[size];
+  }
+
+  public DataBufferByte(int size, int numBanks)
+  {
+    super(TYPE_BYTE, size, numBanks);
+    bankData = new byte[numBanks][size];
+    data = bankData[0];
+  }
+
+  public DataBufferByte(byte[] dataArray, int size)
+  {
+    super(TYPE_BYTE, size);
+    data = dataArray;
+  }
+    
+  public DataBufferByte(byte[] dataArray, int size, int offset)
+  {
+    super(TYPE_BYTE, size, 1, offset);
+    data = dataArray;
+  }
+
+  public DataBufferByte(byte[][] dataArray, int size)
+  {
+    super(TYPE_BYTE, size, dataArray.length);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+
+  public DataBufferByte(byte[][] dataArray, int size, int[] offsets)
+  {
+    super(TYPE_BYTE, size, dataArray.length, offsets);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+
+  public byte[] getData()
+  {
+    return data;
+  }
+    
+  public byte[] getData(int bank) 
+  {
+    return bankData[bank];
+  }
+    
+  public byte[][] getBankData()
+  {
+    return bankData;
+  }
+  
+  public int getElem(int i)
+  {
+    return data[i+offset] & 0xff; // get unsigned byte as int
+  }
+  
+  public int getElem(int bank, int i)
+  {
+    // get unsigned byte as int
+    return bankData[bank][i+offsets[bank]] & 0xff;
+  }
+
+  public void setElem(int i, int val)
+  {
+    data[i+offset] = (byte) val;
+  }
+
+  public void setElem(int bank, int i, int val)
+  {
+    bankData[bank][i+offsets[bank]] = (byte) val;
+  }
+}
Index: libjava/java/awt/image/DataBufferInt.java
===================================================================
RCS file: DataBufferInt.java
diff -N DataBufferInt.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ DataBufferInt.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,103 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+/* This is one of several classes that are nearly identical. Maybe we
+   should have a central template and generate all these files. This
+   is one of the cases where templates or macros would have been
+   useful to have in Java.
+
+   This file has been created using search-replace. My only fear is
+   that these classes will grow out-of-sync as of a result of changes
+   that are not propagated to the other files. As always, mirroring
+   code is a maintenance nightmare.  */
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class DataBufferInt extends DataBuffer
+{
+  private int[] data;
+  private int[][] bankData;
+  
+  public DataBufferInt(int size)
+  {
+    super(TYPE_INT, size);
+    data = new int[size];
+  }
+
+  public DataBufferInt(int size, int numBanks)
+  {
+    super(TYPE_INT, size, numBanks);
+    bankData = new int[numBanks][size];
+    data = bankData[0];
+  }
+  
+  public DataBufferInt(int[] dataArray, int size)
+  {
+    super(TYPE_INT, size);
+    data = dataArray;
+  }
+    
+  public DataBufferInt(int[] dataArray, int size, int offset)
+  {
+    super(TYPE_INT, size, 1, offset);
+    data = dataArray;
+  }
+  
+  public DataBufferInt(int[][] dataArray, int size)
+  {
+    super(TYPE_INT, size, dataArray.length);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+  
+  public DataBufferInt(int[][] dataArray, int size, int[] offsets)
+  {
+    super(TYPE_INT, size, dataArray.length, offsets);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+
+  public int[] getData()
+  {
+    return data;
+  }
+    
+  public int[] getData(int bank)
+  {
+    return bankData[bank];
+  }
+  
+  public int[][] getBankData()
+  {
+    return bankData;
+  }
+  
+  public int getElem(int i)
+  {
+    return data[i+offset];
+  }
+
+  public int getElem(int bank, int i)
+  {
+    // get unsigned int as int
+    return bankData[bank][i+offsets[bank]];
+  }
+
+  public void setElem(int i, int val)
+  {
+    data[i+offset] = (int) val;
+  }
+  
+  public void setElem(int bank, int i, int val)
+  {
+    bankData[bank][i+offsets[bank]] = (int) val;
+  }
+}
Index: libjava/java/awt/image/DataBufferUShort.java
===================================================================
RCS file: DataBufferUShort.java
diff -N DataBufferUShort.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ DataBufferUShort.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,103 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+/* This is one of several classes that are nearly identical. Maybe we
+   should have a central template and generate all these files. This
+   is one of the cases where templates or macros would have been
+   useful to have in Java.
+
+   This file has been created using search-replace. My only fear is
+   that these classes will grow out-of-sync as of a result of changes
+   that are not propagated to the other files. As always, mirroring
+   code is a maintenance nightmare.  */
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class DataBufferUShort extends DataBuffer
+{
+  private short[] data;
+  private short[][] bankData;
+  
+  public DataBufferUShort(int size)
+  {
+    super(TYPE_USHORT, size);
+    data = new short[size];
+  }
+
+  public DataBufferUShort(int size, int numBanks)
+  {
+    super(TYPE_USHORT, size, numBanks);
+    bankData = new short[numBanks][size];
+    data = bankData[0];
+  }
+
+  public DataBufferUShort(short[] dataArray, int size)
+  {
+    super(TYPE_USHORT, size);
+    data = dataArray;
+  }
+    
+  public DataBufferUShort(short[] dataArray, int size, int offset)
+  {
+    super(TYPE_USHORT, size, 1, offset);
+    data = dataArray;
+  }
+
+  public DataBufferUShort(short[][] dataArray, int size)
+  {
+    super(TYPE_USHORT, size, dataArray.length);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+
+  public DataBufferUShort(short[][] dataArray, int size, int[] offsets)
+  {
+    super(TYPE_USHORT, size, dataArray.length, offsets);
+    bankData = dataArray;
+    data = bankData[0];
+  }
+
+  public short[] getData()
+  {
+    return data;
+  }
+    
+  public short[] getData(int bank)
+  {
+    return bankData[bank];
+  }
+    
+  public short[][] getBankData()
+  {
+    return bankData;
+  }
+  
+  public int getElem(int i)
+  {
+    return data[i+offset] & 0xffff; // get unsigned short as int
+  }
+
+  public int getElem(int bank, int i)
+  {
+    // get unsigned short as int
+    return bankData[bank][i+offsets[bank]] & 0xffff;
+  }
+
+  public void setElem(int i, int val)
+  {
+    data[i+offset] = (short) val;
+  }
+
+  public void setElem(int bank, int i, int val)
+  {
+    bankData[bank][i+offsets[bank]] = (short) val;
+  }
+}
Index: libjava/java/awt/image/DirectColorModel.java
===================================================================
RCS file: DirectColorModel.java
diff -N DirectColorModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ DirectColorModel.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,338 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import gnu.gcj.awt.Buffers;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class DirectColorModel extends PackedColorModel
+{
+  public DirectColorModel(int pixelBits, int rmask, int gmask, int bmask)
+  {
+    this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits,
+	 rmask, gmask, bmask, 0, 
+	 false, // not alpha premultiplied
+	 Buffers.smallestAppropriateTransferType(pixelBits) // find type
+	 );
+  }
+
+  public DirectColorModel(int pixelBits,
+			  int rmask, int gmask, int bmask, int amask)
+  {
+    this(ColorSpace.getInstance(ColorSpace.CS_sRGB), pixelBits,
+	 rmask, gmask, bmask, amask,
+	 false, // not alpha premultiplied
+	 Buffers.smallestAppropriateTransferType(pixelBits) // find type
+	 );
+  }
+
+  public DirectColorModel(ColorSpace cspace, int pixelBits,
+			  int rmask, int gmask, int bmask, int amask,
+			  boolean isAlphaPremultiplied,
+			  int transferType)
+  {
+    super(cspace, pixelBits,
+	  rmask, gmask, bmask, amask, isAlphaPremultiplied,
+	  ((amask == 0) ? Transparency.OPAQUE : Transparency.TRANSLUCENT),
+	  transferType);
+  }
+    
+  public final int getRedMask()
+  {
+    return getMask(0);
+  }
+
+  public final int getGreenMask()
+  {
+    return getMask(1);
+  }
+
+  public final int getBlueMask()
+  {
+    return getMask(2);
+  }
+
+  public final int getAlphaMask()
+  {
+    return hasAlpha() ? getMask(3) : 0;
+  }
+
+  public final int getRed(int pixel)
+  {
+    return extractAndNormalizeSample(pixel, 0);
+  }
+
+  public final int getGreen(int pixel)
+  {
+    return extractAndNormalizeSample(pixel, 1);
+  }
+  
+  public final int getBlue(int pixel)
+  {
+    return extractAndNormalizeSample(pixel, 2);
+  }
+
+  public final int getAlpha(int pixel)
+  {
+    if (!hasAlpha()) return 0;
+    return extractAndScaleSample(pixel, 3);
+  }
+
+  private final int extractAndNormalizeSample(int pixel, int component)
+  {
+    int value = extractAndScaleSample(pixel, component);
+    if (hasAlpha() && isAlphaPremultiplied())
+      value = value*255/getAlpha(pixel);
+    return value;
+  }
+
+  private final int extractAndScaleSample(int pixel, int component)
+  {
+    int field = pixel & getMask(component);
+    int to8BitShift =
+      8 - shifts[component] - getComponentSize(component);
+    return (to8BitShift>0) ?
+      (field << to8BitShift) :
+      (field >>> (-to8BitShift));
+  }
+    
+
+  /* FIXME: The Sun docs show that this method is overridden, but I don't
+     see any way to improve on the superclass implementation. */
+  public final int getRGB(int pixel) 
+  {
+    return super.getRGB(pixel);
+  }
+  
+  public int getRed(Object inData)
+  {
+    return getRed(getPixelFromArray(inData));
+  }
+
+  public int getGreen(Object inData)
+  {
+    return getGreen(getPixelFromArray(inData));
+  }
+
+  public int getBlue(Object inData)
+  {
+    return getBlue(getPixelFromArray(inData));
+  }
+    
+  public int getAlpha(Object inData)
+  {
+    return getAlpha(getPixelFromArray(inData));
+  }
+
+  public int getRGB(Object inData)
+  {
+    return getRGB(getPixelFromArray(inData));
+  }
+    
+  /**
+   * Converts a normalized pixel int value in the sRGB color
+   * space to an array containing a single pixel of the color space
+   * of the color model.
+   *
+   * <p>This method performs the inverse function of
+   * <code>getRGB(Object inData)</code>.
+   *
+   * @param rgb pixel as a normalized sRGB, 0xAARRGGBB value.
+   *  
+   * @param pixel to avoid needless creation of arrays, an array to
+   * use to return the pixel can be given. If null, a suitable array
+   * will be created.
+   *
+   * @return array of transferType containing a single pixel. The
+   * pixel should be encoded in the natural way of the color model.
+   *
+   * @see #getRGB(Object)
+   */
+  public Object getDataElements(int rgb, Object pixel)
+  {
+    // FIXME: handle alpha multiply
+    
+    int pixelValue = 0;
+    int a = 0;
+    if (hasAlpha()) {
+      a = (rgb >>> 24) & 0xff;
+      pixelValue = valueToField(a, 3, 8);
+    }
+	
+    if (hasAlpha() && isAlphaPremultiplied())
+      {
+	int r, g, b;
+	/* if r=0xff and a=0xff, then resulting
+	   value will be (r*a)>>>8 == 0xfe... This seems wrong.
+	   We should divide by 255 rather than shifting >>>8 after
+	   multiplying.
+	   
+	   Too bad, shifting is probably less expensive.
+	   r = ((rgb >>> 16) & 0xff)*a;
+	   g = ((rgb >>>  8) & 0xff)*a;
+	   b = ((rgb >>> 0) & 0xff)*a; */
+	/* The r, g, b values we calculate are 16 bit. This allows
+	   us to avoid discarding the lower 8 bits obtained if
+	   multiplying with the alpha band. */
+	
+	// using 16 bit values
+	r = ((rgb >>> 8) & 0xff00)*a/255;
+	g = ((rgb >>> 0) & 0xff00)*a/255;
+	b = ((rgb <<  8) & 0xff00)*a/255;
+	pixelValue |= 
+	  valueToField(r, 0, 16) |  // Red
+	  valueToField(g, 1, 16) |  // Green
+	  valueToField(b, 2, 16);   // Blue
+      }
+    else
+      {
+	int r, g, b;
+	// using 8 bit values
+	r = (rgb >>> 16) & 0xff;
+	g = (rgb >>>  8) & 0xff;
+	b = (rgb >>>  0) & 0xff;
+	
+	pixelValue |= 
+	  valueToField(r, 0, 8) |  // Red
+	  valueToField(g, 1, 8) |  // Green
+	  valueToField(b, 2, 8);   // Blue
+      }
+    
+    /* In this color model, the whole pixel fits in the first element
+       of the array. */
+    DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1);
+    buffer.setElem(0, pixelValue);
+    return Buffers.getData(buffer);
+  }
+    
+  /**
+   * Converts a value to the correct field bits based on the
+   * information derived from the field masks.
+   *
+   * @param highBit the position of the most significant bit in the
+   * val parameter.
+   */
+  private final int valueToField(int val, int component, int highBit)
+  {
+    int toFieldShift = 
+      getComponentSize(component) + shifts[component] - highBit;
+    int ret = (toFieldShift>0) ?
+      (val << toFieldShift) :
+      (val >>> (-toFieldShift));
+    return ret & getMask(component);
+  }  
+
+  /**
+   * Converts a 16 bit value to the correct field bits based on the
+   * information derived from the field masks.
+   */
+  private final int value16ToField(int val, int component)
+  {
+    int toFieldShift = getComponentSize(component) + shifts[component] - 16;
+    return (toFieldShift>0) ?
+      (val << toFieldShift) :
+      (val >>> (-toFieldShift));
+  }
+
+  /**
+   * Fills an array with the unnormalized component samples from a
+   * pixel value. I.e. decompose the pixel, but not perform any
+   * color conversion.
+   */
+  public final int[] getComponents(int pixel, int[] components, int offset)
+  {
+    int numComponents = getNumComponents();
+    if (components == null) components = new int[offset + numComponents];
+    
+    for (int b=0; b<numComponents; b++)
+      components[offset++] = (pixel&getMask(b)) >>> shifts[b];
+	
+    return components;
+  }
+
+  public final int[] getComponents(Object pixel, int[] components,
+				   int offset)
+  {
+    return getComponents(getPixelFromArray(pixel), components, offset);
+  }
+  
+  public final WritableRaster createCompatibleWritableRaster(int w, int h)
+  {
+    SampleModel sm = createCompatibleSampleModel(w, h);
+    Point origin = new Point(0, 0);
+    return Raster.createWritableRaster(sm, origin);	
+  }
+
+  public int getDataElement(int[] components, int offset)
+  {
+    int numComponents = getNumComponents();
+    int pixelValue = 0;
+    
+    for (int c=0; c<numComponents; c++)
+      pixelValue |= (components[offset++] << shifts[c]) & getMask(c);
+
+    return pixelValue;
+  }  
+
+  public Object getDataElements(int[] components, int offset, Object obj)
+  {
+    /* In this color model, the whole pixel fits in the first element
+       of the array. */
+    int pixelValue = getDataElement(components, offset);
+
+    DataBuffer buffer = Buffers.createBuffer(transferType, obj, 1);
+    buffer.setElem(0, pixelValue);
+    return Buffers.getData(buffer);
+  }
+    
+  public ColorModel coerceData(WritableRaster raster,
+			       boolean isAlphaPremultiplied)
+  {
+    if (this.isAlphaPremultiplied == isAlphaPremultiplied)
+      return this;
+	
+    /* TODO: provide better implementation based on the
+       assumptions we can make due to the specific type of the
+       color model. */
+    super.coerceData(raster, isAlphaPremultiplied);
+	
+    return new ComponentColorModel(cspace, bits, hasAlpha(),
+				   isAlphaPremultiplied, // argument
+				   transparency, transferType);
+  } 
+
+  public boolean isCompatibleRaster(Raster raster)
+  {
+    /* FIXME: the Sun docs say this method is overridden here, 
+       but I don't see any way to improve upon the implementation
+       in ColorModel. */
+    return super.isCompatibleRaster(raster);
+  }
+
+  String stringParam()
+  {
+    return super.stringParam() +
+      ", redMask=" + Integer.toHexString(getRedMask()) +
+      ", greenMask=" + Integer.toHexString(getGreenMask()) +
+      ", blueMask=" + Integer.toHexString(getBlueMask()) +
+      ", alphaMask=" + Integer.toHexString(getAlphaMask());
+  }
+
+  public String toString()
+  {
+    /* FIXME: Again, docs say override, but how do we improve upon the
+       superclass implementation? */
+    return super.toString();
+  }
+}
Index: libjava/java/awt/image/ImageConsumer.java
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/awt/image/ImageConsumer.java,v
retrieving revision 1.3
diff -u -r1.3 ImageConsumer.java
--- ImageConsumer.java	2000/07/12 21:24:00	1.3
+++ ImageConsumer.java	2000/07/25 15:34:26
@@ -8,7 +8,6 @@
 
 package java.awt.image;
 import java.util.Hashtable;
-import java.awt.ColorModel;
 
 public interface ImageConsumer
 {
Index: libjava/java/awt/image/IndexColorModel.java
===================================================================
RCS file: IndexColorModel.java
diff -N IndexColorModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ IndexColorModel.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,355 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import gnu.gcj.awt.Buffers;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class IndexColorModel extends ColorModel
+{
+  private byte[] r;
+  private byte[] g;
+  private byte[] b;
+  private byte[] a;
+  private int[] argb;
+  private byte[] cmap;
+  private int start;
+  private int transparent;
+  private int size;
+  
+  public IndexColorModel(int bits, int size, byte[] r, byte[] g, byte[] b)
+  {
+    super(bits, nArray(bits, 3),
+	  ColorSpace.getInstance(ColorSpace.CS_sRGB),
+	  false,  // no transparency
+	  false,  // no premultiplied
+	  Transparency.OPAQUE,
+	  Buffers.smallestAppropriateTransferType(bits));
+    this.r = r;
+    this.g = g;
+    this.b = b;
+    this.size = size;
+  }
+
+  public IndexColorModel(int bits, int size, byte[] r, byte[] g, byte[] b,
+			 int transparent)
+  {
+    super(bits, nArray(bits, 4), 
+	  ColorSpace.getInstance(ColorSpace.CS_sRGB),
+	  true,  // has transparency
+	  false,
+	  Transparency.BITMASK,
+	  Buffers.smallestAppropriateTransferType(bits));
+    this.r = r;
+    this.g = g;
+    this.b = b;
+    this.transparent = transparent;
+    this.size = size;
+  }
+
+  public IndexColorModel(int bits, int size, byte[] r, byte[] g, byte[] b,
+			 byte[] a)
+  {
+    super(bits, nArray(bits, 4),
+	  ColorSpace.getInstance(ColorSpace.CS_sRGB),
+	  true,  // has transparency
+	  false,
+	  Transparency.BITMASK,
+	  Buffers.smallestAppropriateTransferType(bits));
+    this.r = r;
+    this.g = g;
+    this.b = b;
+    this.a = a;
+    this.size = size;
+  }
+
+  public IndexColorModel(int bits, int size, byte[] cmap, int start,
+			 boolean hasAlpha)
+  {
+    super(bits, nArray(bits, hasAlpha ? 4 : 3),
+	  ColorSpace.getInstance(ColorSpace.CS_sRGB),
+	  hasAlpha,
+	  false,
+	  hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE,
+	  Buffers.smallestAppropriateTransferType(bits));
+    this.cmap = cmap;
+    this.start = start;
+    this.size = size;
+  }
+
+  public IndexColorModel(int bits, int size, byte[] cmap, int start,
+			 boolean hasAlpha, int transparent,
+			 int transferType)
+  {
+    super(bits, nArray(bits, hasAlpha ? 4 : 3),
+	  ColorSpace.getInstance(ColorSpace.CS_sRGB),
+	  hasAlpha,
+	  false,
+	  hasAlpha ? 
+	  Transparency.TRANSLUCENT :
+	  ((transparent < 0) ?
+	   Transparency.OPAQUE :
+	   Transparency.BITMASK),
+	  transferType);
+    this.cmap = cmap;
+    this.start = start;
+    this.size = size;
+  }
+
+  public final int getMapSize()
+  {
+    return size;
+  }
+  
+  public final int getTransparentPixel()
+  {
+    return transparent;
+  }
+
+  public final void getReds(byte r[])
+  {
+    if (this.r == null) calcRGBArrays();
+    System.arraycopy(this.r, 0, r, 0, getMapSize());
+  }
+  
+  public final void getGreens(byte g[])
+  {
+    if (this.g == null) calcRGBArrays();
+    System.arraycopy(this.g, 0, g, 0, getMapSize());
+  }
+  
+  public final void getBlues(byte b[])
+  {
+    if (this.b == null) calcRGBArrays();
+    System.arraycopy(this.b, 0, b, 0, getMapSize());
+  }
+
+  public final void getAlphas(byte a[])
+  {
+    if (this.a == null) calcAlphaArray();
+    System.arraycopy(this.a, 0, a, 0, getMapSize());
+  }
+
+  public final void getRGBs(int rgb[])
+  {
+    if (this.argb == null) calcARGBArray();
+    System.arraycopy(this.argb, 0, rgb, 0, getMapSize());
+  }
+
+  public int getRed(int pixel)
+  {
+    try
+      {
+	return r[pixel];
+      }
+    catch (NullPointerException npe)
+      {
+	calcRGBArrays();
+	return r[pixel];
+      }
+  }
+
+  public int getGreen(int pixel)
+  {
+    try
+      {
+	return g[pixel];
+      }
+    catch (NullPointerException npe)
+      {
+	calcRGBArrays();
+	return g[pixel];
+      }
+  }
+
+  public int getBlue(int pixel)
+  {
+    try
+      {
+	return b[pixel];
+      }
+    catch (NullPointerException npe)
+      {
+	calcRGBArrays();
+	return b[pixel];
+      }
+  }
+  
+  public int getAlpha(int pixel)
+  {
+    try
+      {
+	return a[pixel];
+      } 
+    catch (NullPointerException npe)
+      {
+	calcAlphaArray();
+	return a[pixel];
+      }
+  }
+
+  private void calcRGBArrays() {
+    int j=0;
+    boolean hasAlpha = hasAlpha();
+    r = new byte[size];
+    g = new byte[size];
+    b = new byte[size];
+    if (hasAlpha) a = new byte[size];
+    
+    for (int i=0; i<size; i++)
+      {
+	r[i] = cmap[j++];
+	g[i] = cmap[j++];
+	b[i] = cmap[j++];
+	if (hasAlpha()) a[i] = cmap[j++];
+      }
+  }
+
+  private void calcAlphaArray()
+  {
+    int transparency = getTransparency();
+    switch (transparency)
+      {
+      case Transparency.OPAQUE:
+      case Transparency.BITMASK:
+	a = nArray((byte) 255, size);
+	if (transparency == Transparency.BITMASK)
+	  a[transparent] = 0;
+	break;
+      case Transparency.TRANSLUCENT:
+	calcRGBArrays();
+      }
+  }
+
+  private void calcARGBArray()
+  {
+    int mapSize = getMapSize();
+    argb = new int[mapSize];
+    for (int p=0; p<mapSize; p++) argb[p] = getRGB(p);
+  }
+  
+  public int getRed(Object inData)
+  {
+    return getRed(getPixelFromArray(inData));
+  }
+
+  public int getGreen(Object inData)
+  {
+    return getGreen(getPixelFromArray(inData));
+  }
+
+  public int getBlue(Object inData)
+  {
+    return getBlue(getPixelFromArray(inData));
+  }
+    
+  public int getAlpha(Object inData)
+  {
+    return getAlpha(getPixelFromArray(inData));
+  }
+
+  public int getRGB(Object inData)
+  {
+    return getRGB(getPixelFromArray(inData));
+  }
+
+  public Object getDataElements(int rgb, Object pixel)
+  {
+    int av, rv, gv, bv;
+    // using 8 bit values
+    av = (rgb >>> 24) & 0xff;
+    rv = (rgb >>> 16) & 0xff;
+    gv = (rgb >>>  8) & 0xff;
+    bv = (rgb >>>  0) & 0xff;
+    
+    int pixelValue = getPixelValue(av, rv, gv, bv);
+
+    /* In this color model, the whole pixel fits in the first element
+       of the array. */
+    DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1);
+    buffer.setElem(0, pixelValue);
+    return Buffers.getData(buffer);
+  }
+    
+  private int getPixelValue(int av, int rv, int gv, int bv)
+  {
+    if (r == null) calcRGBArrays();
+    if (a == null) calcAlphaArray();
+    
+    int minDAlpha = 1<<8;
+    int minDRGB = (1<<8)*(1<<8)*3;
+    int pixelValue = -1;
+    for (int i=0; i<size; i++)
+      {
+	int dAlpha = Math.abs(av-(a[i]&0xff));
+	if (dAlpha > minDAlpha) continue;
+	int dR = rv-(r[i]&0xff);
+	int dG = gv-(g[i]&0xff);
+	int dB = bv-(b[i]&0xff);
+	int dRGB = dR*dR + dG*dG + dB*dB;
+	
+	if (dRGB >= minDRGB) continue;
+	
+	pixelValue = i;
+	minDRGB = dRGB;
+      }
+    return pixelValue;
+  }  
+
+  public int[] getComponents(int pixel, int[] components, int offset)
+  {
+    int numComponents = getNumComponents();
+    if (components == null) components = new int[offset + numComponents];
+    components[offset++] = (r[pixel]&0xff);
+    components[offset++] = (g[pixel]&0xff);
+    components[offset++] = (b[pixel]&0xff);
+    if (hasAlpha()) components[offset++] = (a[pixel]&0xff);
+    return components;
+  }
+	
+  public final int[] getComponents(Object pixel, int[] components,
+				   int offset)
+  {
+    return getComponents(getPixelFromArray(pixel), components, offset);
+  }
+  
+  public int getDataElement(int[] components, int offset)
+  {
+    int r = components[offset++];
+    int g = components[offset++];
+    int b = components[offset++];
+    int a = hasAlpha() ? components[offset++] : 255;
+    
+    return getPixelValue(a, r, g, b);
+  }
+  
+  public Object getDataElements(int[] components, int offset, Object pixel)
+  {
+    int pixelValue = getDataElement(components, offset);
+    
+    /* In this color model, the whole pixel fits in the first element
+       of the array. */
+    DataBuffer buffer = Buffers.createBuffer(transferType, pixel, 1);
+    buffer.setElem(0, pixelValue);
+    return Buffers.getData(buffer);
+  }
+    
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    int[] bandOffsets = {0};
+    return new ComponentSampleModel(transferType, w, h,
+				    1, // pixel stride
+				    w, // scanline stride
+				    bandOffsets);
+  }
+}
Index: libjava/java/awt/image/PackedColorModel.java
===================================================================
RCS file: PackedColorModel.java
diff -N PackedColorModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ PackedColorModel.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,162 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.color.ColorSpace;
+import gnu.gcj.awt.BitMaskExtent;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public abstract class PackedColorModel extends ColorModel
+{
+  private int masks[];
+  
+  /* Package accessibility, the DirectColorModel needs this array */
+  int shifts[];
+
+  public PackedColorModel(ColorSpace cspace, int pixelBits,
+			  int[] colorMaskArray, int alphaMask,
+			  boolean isAlphaPremultiplied,
+			  int transparency,
+			  int transferType)
+  {
+    super(pixelBits, calcBitsPerComponent(colorMaskArray, alphaMask),
+	  cspace, (alphaMask != 0), isAlphaPremultiplied, transparency,
+	  transferType);
+    initMasks(colorMaskArray, alphaMask);
+    if ((pixelBits<1) || (pixelBits>32)) {
+      throw new IllegalArgumentException("pixels per bits must be " +
+					 "in the range [1, 32]");
+    }
+  }
+    
+  private static int[] calcBitsPerComponent(int[] colorMaskArray,
+					    int alphaMask)
+  {
+    int numComponents = colorMaskArray.length;
+    if (alphaMask != 0) numComponents++;
+    
+    int[] bitsPerComponent = new int[numComponents];
+    
+    BitMaskExtent extent = new BitMaskExtent();
+    for (int b=0; b<colorMaskArray.length; b++)
+      {
+	extent.setMask(colorMaskArray[b]);
+	bitsPerComponent[b] = extent.bitWidth;
+      }
+    if (alphaMask != 0)
+      {
+	extent.setMask(alphaMask);
+	bitsPerComponent[numComponents-1] = extent.bitWidth;
+      }
+    return bitsPerComponent;
+  }
+
+  /** Initializes the masks.
+   *
+   * @return an array containing the number of bits per color
+   * component.
+   */
+  private void initMasks(int[] colorMaskArray, int alphaMask)
+  {
+    int numComponents = colorMaskArray.length;
+    if (alphaMask == 0)
+      {
+	masks = colorMaskArray;
+      }
+    else
+      {
+	masks = new int[numComponents+1];
+	System.arraycopy(colorMaskArray, 0,
+			 masks, 0,
+			 numComponents);
+	masks[numComponents++] = alphaMask;
+      }
+	
+    shifts = new int[numComponents];
+	
+    // Bit field handling have been moved to a utility class
+    BitMaskExtent extent = new BitMaskExtent();
+    for (int b=0; b<numComponents; b++)
+      {
+	extent.setMask(masks[b]);
+	shifts[b] = extent.leastSignificantBit;
+      }
+  }
+    
+  public PackedColorModel(ColorSpace cspace, int pixelBits,
+			  int rmask, int gmask, int bmask,
+			  int amask, boolean isAlphaPremultiplied,
+			  int transparency,
+			  int transferType)
+  {
+    this(cspace, pixelBits, makeColorMaskArray(rmask, gmask, bmask),
+	 amask, isAlphaPremultiplied, transparency, transferType);
+  }
+    
+  /* TODO: If there is a alpha mask, it is inefficient to create a
+     color mask array that will be discarded when the alpha mask is
+     appended. We should probably create a private constructor that
+     takes a complete array of masks (color+alpha) as an
+     argument. */
+
+  private static int[] makeColorMaskArray(int rmask, int gmask, int bmask)
+  {
+    int[] colorMaskArray = { rmask, gmask, bmask };
+    return colorMaskArray;
+  }   
+
+  public final int getMask(int index)
+  {
+    return masks[index];
+  }
+  
+  public final int[] getMasks()
+  {
+    return masks;
+  }
+
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    return new SinglePixelPackedSampleModel(transferType, w, h, masks);
+  }
+    
+  public boolean isCompatibleSampleModel(SampleModel sm)
+  {
+    if (!super.isCompatibleSampleModel(sm)) return false;
+    if (!(sm instanceof SinglePixelPackedSampleModel)) return false;
+    
+    SinglePixelPackedSampleModel sppsm =
+      (SinglePixelPackedSampleModel) sm;
+    return java.util.Arrays.equals(sppsm.getBitMasks(), masks);
+  }
+
+  public WritableRaster getAlphaRaster(WritableRaster raster) {
+    if (!hasAlpha()) return null;
+	
+    SampleModel sm = raster.getSampleModel();
+    int[] alphaBand = { sm.getNumBands() - 1 };
+    SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
+    DataBuffer buffer = raster.getDataBuffer();
+    Point origin = new Point(0, 0);
+    return Raster.createWritableRaster(alphaModel, buffer, origin);
+  }
+    
+  public boolean equals(Object obj)
+  {
+    if (!super.equals(obj)) return false;
+    if (!(obj instanceof PackedColorModel)) return false;
+    
+    PackedColorModel other = (PackedColorModel) obj;
+    
+    return java.util.Arrays.equals(masks, other.masks);
+  }
+}
Index: libjava/java/awt/image/Raster.java
===================================================================
RCS file: Raster.java
diff -N Raster.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ Raster.java	Tue Jul 25 08:34:26 2000
@@ -0,0 +1,418 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.*;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class Raster
+{
+  protected SampleModel sampleModel;
+  protected DataBuffer dataBuffer;
+  protected int minX;
+  protected int minY;
+  protected int width;
+  protected int height;
+  protected int sampleModelTranslateX;
+  protected int sampleModelTranslateY;
+  protected int numBands;
+  protected int numDataElements;
+  protected Raster parent;
+  
+  protected Raster(SampleModel sampleModel, Point origin)
+  {
+    this(sampleModel, sampleModel.createDataBuffer(), origin);
+  }
+  
+  protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+		   Point origin)
+  {
+    this(sampleModel, dataBuffer,
+	 new Rectangle(origin.x, origin.y,
+		       sampleModel.getWidth(), sampleModel.getHeight()),
+	 origin, null);
+  }
+
+  protected Raster(SampleModel sampleModel, DataBuffer dataBuffer,
+		   Rectangle aRegion,
+		   Point sampleModelTranslate, Raster parent)
+  {
+    this.sampleModel = sampleModel;
+    this.dataBuffer = dataBuffer;
+    this.minX = aRegion.x;
+    this.minY = aRegion.y;
+    this.width = aRegion.width;
+    this.height = aRegion.height;
+    this.sampleModelTranslateX = sampleModelTranslate.x;
+    this.sampleModelTranslateY = sampleModelTranslate.y;
+    this.numBands = sampleModel.getNumBands();
+    this.numDataElements = sampleModel.getNumDataElements();
+    this.parent = parent;
+  }
+    
+  public static WritableRaster createInterleavedRaster(int dataType,
+						       int w, int h,
+						       int bands, 
+						       Point location)
+  {
+    int[] bandOffsets = new int[bands];
+    // TODO: Maybe not generate this every time.
+    for (int b=0; b<bands; b++) bandOffsets[b] = b;
+    
+    int scanlineStride = bands*w;
+    return createInterleavedRaster(dataType, w, h, scanlineStride, bands,
+				   bandOffsets, location);
+  }
+
+  public static WritableRaster createInterleavedRaster(int dataType,
+						       int w, int h,
+						       int scanlineStride,
+						       int pixelStride,
+						       int[] bandOffsets,
+						       Point location)
+  {
+    SampleModel sm = new ComponentSampleModel(dataType,
+					      w, h,
+					      pixelStride,
+					      scanlineStride,
+					      bandOffsets);
+    return createWritableRaster(sm, location);
+  }
+
+  public static WritableRaster createBandedRaster(int dataType, 
+						  int w, int h, int bands,
+						  Point location)
+  {
+    // FIXME: Implement;
+    throw new UnsupportedOperationException("not implemented yet");
+  }
+
+  public static WritableRaster createBandedRaster(int dataType,
+						  int w, int h,
+						  int scanlineStride,
+						  int[] bankIndices,
+						  int[] bandOffsets,
+						  Point location)
+  {
+    // FIXME: Implement;
+    throw new UnsupportedOperationException("not implemented yet");
+  }
+  
+  public static WritableRaster createPackedRaster(int dataType,
+						  int w, int h,
+						  int[] bandMasks,
+						  Point location)
+  {
+    SampleModel sm = new SinglePixelPackedSampleModel(dataType,
+						      w, h,
+						      bandMasks);
+    return createWritableRaster(sm, location);
+  }
+
+  public static WritableRaster
+  createInterleavedRaster(DataBuffer dataBuffer, int w, int h,
+			  int scanlineStride, int pixelStride,
+			  int[] bandOffsets, Point location)
+  {
+    SampleModel sm = new ComponentSampleModel(dataBuffer.getDataType(),
+					      w, h,
+					      scanlineStride,
+					      pixelStride,
+					      bandOffsets);
+    return createWritableRaster(sm, dataBuffer, location);
+  }
+
+  public static
+  WritableRaster createBandedRaster(DataBuffer dataBuffer,
+				    int w, int h,
+				    int scanlineStride,
+				    int[] bankIndices,
+				    int[] bandOffsets,
+				    Point location)
+  {
+    // FIXME: Implement;
+    throw new UnsupportedOperationException("not implemented yet");
+  }
+  
+  public static WritableRaster
+  createPackedRaster(DataBuffer dataBuffer,
+		     int w, int h,
+		     int scanlineStride,
+		     int[] bandMasks,
+		     Point location) {
+    SampleModel sm =
+      new SinglePixelPackedSampleModel(dataBuffer.getDataType(),
+				       w, h,
+				       scanlineStride,
+				       bandMasks);
+    return createWritableRaster(sm, dataBuffer, location);
+  }
+    
+  public static Raster createRaster(SampleModel sm, DataBuffer db,
+				    Point location)
+  {
+    return new Raster(sm, db, location);
+  }
+
+  public static WritableRaster createWritableRaster(SampleModel sm,
+						    Point location)
+  {
+    return new WritableRaster(sm, location);
+  }
+
+  public static WritableRaster createWritableRaster(SampleModel sm,
+						    DataBuffer db,
+						    Point location)
+  {
+    return new WritableRaster(sm, db, location);
+  }
+
+  public Raster getParent()
+  {
+    return parent;
+  }
+
+  public final int getSampleModelTranslateX()
+  {
+    return sampleModelTranslateX;
+  }
+
+  public final int getSampleModelTranslateY()
+  {
+    return sampleModelTranslateY;
+  }
+
+  public WritableRaster createCompatibleWritableRaster()
+  {
+    return new WritableRaster(getSampleModel(), new Point(minX, minY));
+  }
+
+  public WritableRaster createCompatibleWritableRaster(int w, int h)
+  {
+    return createCompatibleWritableRaster(minX, minY, w, h);
+  }
+
+  public WritableRaster createCompatibleWritableRaster(Rectangle rect)
+  {
+    return createCompatibleWritableRaster(rect.x, rect.y,
+					  rect.width, rect.height);
+  }
+
+  public WritableRaster createCompatibleWritableRaster(int x, int y,
+						       int w, int h)
+  {
+    SampleModel sm = getSampleModel().createCompatibleSampleModel(w, h);
+    return new WritableRaster(sm, sm.createDataBuffer(),
+			      new Point(x, y));
+  }
+
+  public Raster createTranslatedChild(int childMinX, int childMinY) {
+    int tcx = sampleModelTranslateX - minX + childMinX;
+    int tcy = sampleModelTranslateY - minY + childMinY;
+    
+    return new Raster(sampleModel, dataBuffer,
+		      new Rectangle(childMinX, childMinY,
+				    width, height),
+		      new Point(tcx, tcy),
+		      this);
+  }
+
+  public Raster createChild(int parentX, int parentY, int width,
+			    int height, int childMinX, int childMinY,
+			    int[] bandList)
+  {
+    /* FIXME: Throw RasterFormatException if child bounds extends
+       beyond the bounds of this raster. */
+
+    SampleModel sm = (bandList == null) ?
+      sampleModel :
+      sampleModel.createSubsetSampleModel(bandList);
+
+    /*
+        data origin
+       /
+      +-------------------------
+      |\. __ parent trans
+      | \`.  
+      |  \ `.    parent origin
+      |   \  `. /
+      |   /\   +-------- - -
+      |trans\ /<\-- deltaTrans
+      |child +-+-\---- - - 
+      |     /|`|  \__ parent [x, y]
+      |child | |`. \
+      |origin| :  `.\
+      |      |    / `\
+      |      :   /    +
+      | child [x, y] 
+
+      parent_xy - parent_trans = child_xy - child_trans
+
+      child_trans = parent_trans + child_xy - parent_xy
+    */
+
+    return new Raster(sm, dataBuffer,
+		      new Rectangle(childMinX, childMinY,
+				    width, height),
+		      new Point(sampleModelTranslateX+childMinX-parentX,
+				sampleModelTranslateY+childMinY-parentY),
+		      this);
+  }
+
+  public Rectangle getBounds()
+  {
+    return new Rectangle(minX, minY, width, height);
+  }
+
+  public final int getMinX()
+  {
+    return minX;
+  }
+
+  public final int getMinY()
+  {
+    return minY;
+  }
+
+  public final int getWidth()
+  {
+    return width;
+  }
+
+  public final int getHeight()
+  {
+    return height;
+  }
+
+  public final int getNumDataElements()
+  {
+    return numDataElements;
+  }
+    
+  public final int getTransferType()
+  {
+    return sampleModel.getTransferType();
+  }
+
+  public DataBuffer getDataBuffer()
+  {
+    return dataBuffer;
+  }
+
+  public SampleModel getSampleModel()
+  {
+    return sampleModel;
+  }
+
+  public Object getDataElements(int x, int y, Object outData)
+  {
+    return sampleModel.getDataElements(x-sampleModelTranslateX,
+				       y-sampleModelTranslateY,
+				       outData, dataBuffer);
+  }
+
+  public Object getDataElements(int x, int y, int w, int h,
+				Object outData)
+  {
+    return sampleModel.getDataElements(x-sampleModelTranslateX,
+				       y-sampleModelTranslateY,
+				       w, h, outData, dataBuffer);
+  }
+
+  public int[] getPixel(int x, int y, int[] iArray)
+  {
+    return sampleModel.getPixel(x-sampleModelTranslateX,
+				y-sampleModelTranslateY,
+				iArray, dataBuffer);
+  }
+
+  public float[] getPixel(int x, int y, float[] fArray)
+  {
+    return sampleModel.getPixel(x-sampleModelTranslateX,
+				y-sampleModelTranslateY,
+				fArray, dataBuffer);
+  }
+
+  public double[] getPixel(int x, int y, double[] dArray)
+  {
+    return sampleModel.getPixel(x-sampleModelTranslateX,
+				y-sampleModelTranslateY,
+				dArray, dataBuffer);
+  }
+
+  public int[] getPixels(int x, int y, int w, int h, int[] iArray)
+  {
+    return sampleModel.getPixels(x-sampleModelTranslateX,
+				 y-sampleModelTranslateY,
+				 w, h, iArray, dataBuffer);
+  }
+
+  public float[] getPixels(int x, int y, int w, int h,
+			   float[] fArray)
+  {
+    return sampleModel.getPixels(x-sampleModelTranslateX,
+				 y-sampleModelTranslateY,
+				 w, h, fArray, dataBuffer);
+  }
+
+  public double[] getPixels(int x, int y, int w, int h,
+			    double[] dArray)
+  {
+    return sampleModel.getPixels(x-sampleModelTranslateX,
+				 y-sampleModelTranslateY,
+				 w, h, dArray, dataBuffer);
+  }
+
+  public int getSample(int x, int y, int b)
+  {
+    return sampleModel.getSample(x-sampleModelTranslateX,
+				 y-sampleModelTranslateY,
+				 b, dataBuffer);
+  }
+
+  public float getSampleFloat(int x, int y, int b)
+  {
+    return sampleModel.getSampleFloat(x-sampleModelTranslateX,
+				      y-sampleModelTranslateY,
+				      b, dataBuffer);
+  }
+
+  public double getSampleDouble(int x, int y, int b)
+  {
+    return sampleModel.getSampleDouble(x-sampleModelTranslateX,
+				       y-sampleModelTranslateY,
+				       b, dataBuffer);
+  }
+
+  public int[] getSamples(int x, int y, int w, int h, int b,
+			  int[] iArray)
+  {
+    return sampleModel.getSamples(x-sampleModelTranslateX,
+				  y-sampleModelTranslateY,
+				  w, h, b, iArray, dataBuffer);
+  }
+
+  public float[] getSamples(int x, int y, int w, int h, int b,
+			    float[] fArray)
+  {
+    return sampleModel.getSamples(x-sampleModelTranslateX,
+				  y-sampleModelTranslateY,
+				  w, h, b, fArray, dataBuffer);
+  }
+
+  public double[] getSamples(int x, int y, int w, int h, int b,
+			     double[] dArray)
+  {
+    return sampleModel.getSamples(x-sampleModelTranslateX,
+				  y-sampleModelTranslateY,
+				  w, h, b, dArray, dataBuffer);
+  }
+}
Index: libjava/java/awt/image/SampleModel.java
===================================================================
RCS file: SampleModel.java
diff -N SampleModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ SampleModel.java	Tue Jul 25 08:34:27 2000
@@ -0,0 +1,436 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public abstract class SampleModel
+{
+  /** Width of image described. */
+  protected int width;
+  
+  /** Height of image described. */
+  protected int height;
+  
+  /** Number of bands in the image described. */
+  protected int numBands;
+
+  /** 
+   * The DataBuffer type that is used to store the data of the image
+   * described.
+   */
+  protected int dataType;
+
+  public SampleModel(int dataType, int w, int h, int numBands)
+  {
+    if ((w<=0) || (h<=0)) throw new IllegalArgumentException();
+	
+    // FIXME: How can an int be greater than Integer.MAX_VALUE?
+    // FIXME: How do we identify an unsupported data type?
+
+    this.dataType = dataType;
+    this.width = w;
+    this.height = h;
+    this.numBands = numBands;  
+  }
+
+  public final int getWidth()
+  {
+    return width;
+  }
+
+  public final int getHeight()
+  {
+    return height;
+  }
+
+  public final int getNumBands()
+  {
+    return numBands;
+  }
+    
+  public abstract int getNumDataElements();
+  
+  public final int getDataType()
+  {
+    return dataType;
+  }
+
+  public int getTransferType()
+  {
+    // FIXME: Is this a reasonable default implementation?
+    return dataType;
+  }
+
+  public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    if (iArray == null) iArray = new int[numBands];
+    for (int b=0; b<numBands; b++) iArray[b] = getSample(x, y, b, data);
+    return iArray;
+  }
+  
+  /**
+   *
+   * This method is provided as a faster alternative to getPixel(),
+   * that can be used when there is no need to decode the pixel into
+   * seperate sample values.
+   *
+   * @param obj An array to return the pixel data in. If null, an
+   * array of the right type and size will be created.
+   *
+   * @return A single pixel as an array object of a primitive type,
+   * based on the transfer type. Eg. if transfer type is
+   * DataBuffer.TYPE_USHORT, then a short[] object is returned.
+   */
+  public abstract Object getDataElements(int x, int y, Object obj,
+					 DataBuffer data);
+
+    
+  public Object getDataElements(int x, int y, int w, int h, Object obj,
+				DataBuffer data)
+  {
+    int size = w*h;
+    int numDataElements = getNumDataElements();
+    int dataSize = numDataElements*size;
+    
+    if (obj == null)
+      {
+	switch (getTransferType())
+	  {
+	  case DataBuffer.TYPE_BYTE:
+	    obj = new byte[dataSize];
+	    break;
+	  case DataBuffer.TYPE_USHORT:
+	    obj = new short[dataSize];
+	    break;
+	  case DataBuffer.TYPE_INT:
+	    obj = new int[dataSize];
+	    break;
+	  default:
+	    // Seems like the only sensible thing to do.
+	    throw new ClassCastException();
+	  }
+      }
+    Object pixelData = null;
+    int outOffset = 0;
+    for (int yy = y; yy<(y+h); yy++)
+      {
+	for (int xx = x; xx<(x+w); xx++)
+	  {
+	    pixelData = getDataElements(xx, yy, pixelData, data);
+	    System.arraycopy(pixelData, 0, obj, outOffset,
+			     numDataElements);
+	    outOffset += numDataElements;
+	  }
+      }
+    return obj;
+  }
+
+  public abstract void setDataElements(int x, int y, Object obj,
+				       DataBuffer data);
+
+  public void setDataElements(int x, int y, int w, int h,
+			      Object obj, DataBuffer data)
+  {
+    int size = w*h;
+    int numDataElements = getNumDataElements();
+    int dataSize = numDataElements*size;
+    
+    Object pixelData;
+    switch (getTransferType())
+      {
+      case DataBuffer.TYPE_BYTE:
+	pixelData = new byte[numDataElements];
+	break;
+      case DataBuffer.TYPE_USHORT:
+	pixelData = new short[numDataElements];
+	break;
+      case DataBuffer.TYPE_INT:
+	pixelData = new int[numDataElements];
+	break;
+      default:
+	// Seems like the only sensible thing to do.
+	throw new ClassCastException();
+      }
+    int inOffset = 0;
+
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    System.arraycopy(obj, inOffset, pixelData, 0,
+			     numDataElements);
+	    setDataElements(xx, yy, pixelData, data);
+	    inOffset += numDataElements;
+	  }
+      }
+  }
+
+  public float[] getPixel(int x, int y, float[] fArray, DataBuffer data)
+  {
+    if (fArray == null) fArray = new float[numBands];
+    
+    for (int b=0; b<numBands; b++)
+      {
+        fArray[0] = getSampleFloat(x, y, b, data);
+      }
+    return fArray;
+  }
+
+  public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) {
+    if (dArray == null) dArray = new double[numBands];
+    for (int b=0; b<numBands; b++)
+      {
+	dArray[0] = getSampleDouble(x, y, b, data);
+      }
+    return dArray;
+  }
+
+  /* FIXME: Should it return a banded or pixel interleaved array of
+     samples? (Assume interleaved.) */
+  public int[] getPixels(int x, int y, int w, int h, int[] iArray,
+			 DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    int[] pixel = null;
+    if (iArray == null) iArray = new int[w*h*numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    getPixel(xx, yy, pixel, data);
+	    System.arraycopy(pixel, 0, iArray, outOffset, numBands);
+	    outOffset += numBands;
+	  }
+      }
+    return iArray;
+  }
+
+  /* FIXME: Should it return a banded or pixel interleaved array of
+     samples? (Assume interleaved.) */
+  public float[] getPixels(int x, int y, int w, int h, float[] fArray,
+			   DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    float[] pixel = null;
+    if (fArray == null) fArray = new float[w*h*numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    getPixel(xx, yy, pixel, data);
+	    System.arraycopy(pixel, 0, fArray, outOffset, numBands);
+	    outOffset += numBands;
+	  }
+      }
+    return fArray;
+  }
+    
+  /* FIXME: Should it return a banded or pixel interleaved array of
+     samples? (Assume interleaved.) */
+  public double[] getPixels(int x, int y, int w, int h, double[] dArray,
+			    DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    double[] pixel = null;
+    if (dArray == null) dArray = new double[w*h*numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    getPixel(xx, yy, pixel, data);
+	    System.arraycopy(pixel, 0, dArray, outOffset, numBands);
+	    outOffset += numBands;
+	  }
+      }
+    return dArray;
+  }
+
+  public abstract int getSample(int x, int y, int b, DataBuffer data);
+
+  public float getSampleFloat(int x, int y, int b, DataBuffer data)
+  {
+    return getSample(x, y, b, data);
+  }
+
+  public double getSampleDouble(int x, int y, int b, DataBuffer data)
+  {
+    return getSampleFloat(x, y, b, data);
+  }
+
+  public int[] getSamples(int x, int y, int w, int h, int b,
+			  int[] iArray, DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    if (iArray == null) iArray = new int[size];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    iArray[outOffset++] = getSample(xx, yy, b, data);
+	  }
+      }
+    return iArray;
+  }
+
+  public float[] getSamples(int x, int y, int w, int h, int b,
+			    float[] fArray, DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    if (fArray == null) fArray = new float[size];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    fArray[outOffset++] = getSampleFloat(xx, yy, b, data);
+	  }
+      }
+    return fArray;
+  }
+
+  public double[] getSamples(int x, int y, int w, int h, int b,
+			     double[] dArray, DataBuffer data)
+  {
+    int size = w*h;
+    int outOffset = 0;
+    if (dArray == null) dArray = new double[size];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    dArray[outOffset++] = getSampleDouble(xx, yy, b, data);
+	  }
+      }
+    return dArray;
+  }
+  
+  public void setPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    for (int b=0; b<numBands; b++) setSample(x, y, b, iArray[b], data);
+  }
+
+  public void setPixel(int x, int y, float[] fArray, DataBuffer data)
+  {
+    for (int b=0; b<numBands; b++) setSample(x, y, b, fArray[b], data);
+  }
+
+  public void setPixel(int x, int y, double[] dArray, DataBuffer data)
+  {
+    for (int b=0; b<numBands; b++) setSample(x, y, b, dArray[b], data);
+  }
+
+  public void setPixels(int x, int y, int w, int h, int[] iArray,
+			DataBuffer data)
+  {
+    int inOffset = 0;
+    int[] pixel = new int[numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    System.arraycopy(iArray, inOffset, pixel, 0, numBands);
+	    setPixel(xx, yy, pixel, data);
+	    inOffset += numBands;
+	  }
+      }
+  }
+
+  public void setPixels(int x, int y, int w, int h, float[] fArray,
+			DataBuffer data)
+  {
+    int inOffset = 0;
+    float[] pixel = new float[numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    System.arraycopy(fArray, inOffset, pixel, 0, numBands);
+	    setPixel(xx, yy, pixel, data);
+	    inOffset += numBands;
+	  }
+      }
+  }
+
+  public void setPixels(int x, int y, int w, int h, double[] dArray,
+			DataBuffer data)
+  {
+    int inOffset = 0;
+    double[] pixel = new double[numBands];
+    for (int yy=y; yy<(y+h); yy++)
+      {
+	for (int xx=x; xx<(x+w); xx++)
+	  {
+	    System.arraycopy(dArray, inOffset, pixel, 0, numBands);
+	    setPixel(xx, yy, pixel, data);
+	    inOffset += numBands;
+	  }
+      }
+  }
+
+  public abstract void setSample(int x, int y, int b, int s,
+				 DataBuffer data);
+
+  public void setSample(int x, int y, int b, float s,
+			DataBuffer data)
+  {
+    setSample(x, y, b, (int) s, data);
+  }
+
+  public void setSample(int x, int y, int b, double s,
+			DataBuffer data)
+  {
+    setSample(x, y, b, (float) s, data);
+  }
+
+  public void setSamples(int x, int y, int w, int h, int b,
+			 int[] iArray, DataBuffer data)
+  {
+    int size = w*h;
+    int inOffset = 0;
+    for (int yy=y; yy<(y+h); yy++)
+      for (int xx=x; xx<(x+w); xx++)
+	setSample(xx, yy, b, iArray[inOffset++], data);
+  }
+
+  public void setSamples(int x, int y, int w, int h, int b,
+			 float[] fArray, DataBuffer data)
+  {
+    int size = w*h;
+    int inOffset = 0;
+    for (int yy=y; yy<(y+h); yy++)
+      for (int xx=x; xx<(x+w); xx++)
+	setSample(xx, yy, b, fArray[inOffset++], data);
+
+    }
+
+    public void setSamples(int x, int y, int w, int h, int b,
+			   double[] dArray, DataBuffer data) {
+      int size = w*h;
+      int inOffset = 0;
+      for (int yy=y; yy<(y+h); yy++)
+	for (int xx=x; xx<(x+w); xx++)
+	  setSample(xx, yy, b, dArray[inOffset++], data);
+    }
+
+    public abstract SampleModel createCompatibleSampleModel(int w, int h);
+
+    public abstract SampleModel createSubsetSampleModel(int[] bands);
+
+    public abstract DataBuffer createDataBuffer();
+
+    public abstract int[] getSampleSize();
+
+    public abstract int getSampleSize(int band);
+}
Index: libjava/java/awt/image/SinglePixelPackedSampleModel.java
===================================================================
RCS file: SinglePixelPackedSampleModel.java
diff -N SinglePixelPackedSampleModel.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ SinglePixelPackedSampleModel.java	Tue Jul 25 08:34:27 2000
@@ -0,0 +1,245 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import gnu.gcj.awt.BitMaskExtent;
+import gnu.gcj.awt.Buffers;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class SinglePixelPackedSampleModel extends SampleModel
+{
+  private int scanlineStride;
+  private int[] bitMasks;
+  private int[] bitOffsets;
+  private int[] sampleSize;;
+  
+  public SinglePixelPackedSampleModel(int dataType, int w, int h,
+				      int[] bitMasks)
+  {
+    this(dataType, w, h, w, bitMasks);
+  }
+
+  public SinglePixelPackedSampleModel(int dataType, int w, int h,
+				      int scanlineStride, int[] bitMasks)
+  {
+    super(dataType, w, h, bitMasks.length);
+    
+    this.scanlineStride = scanlineStride;
+    this.bitMasks = bitMasks;
+    
+    bitOffsets = new int[numBands];
+    sampleSize = new int[numBands];
+    
+    BitMaskExtent extent = new BitMaskExtent();
+    for (int b=0; b<numBands; b++)
+      {
+	extent.setMask(bitMasks[b]);
+	sampleSize[b] = extent.bitWidth;
+	bitOffsets[b] = extent.leastSignificantBit;
+      }
+  }
+
+  public int getNumDataElements()
+  {
+    return 1;
+  }
+
+  public SampleModel createCompatibleSampleModel(int w, int h)
+  {
+    /* FIXME: We can avoid recalculation of bit offsets and sample
+       sizes here by passing these from the current instance to a
+       special private constructor. */
+    return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks);
+  }
+
+  public DataBuffer createDataBuffer()
+  {
+    // Important: use scanlineStride here, not width!
+    int size = scanlineStride*height;
+    return Buffers.createBuffer(getDataType(), size);
+  }
+
+  public int[] getSampleSize()
+  {
+    return sampleSize;
+  }
+  
+  public int getSampleSize(int band)
+  {
+    return sampleSize[band];
+  }
+
+  public int getOffset(int x, int y)
+  {
+    return scanlineStride*y + x;
+  }
+
+  public int[] getBitOffsets()
+  {
+    return bitOffsets;
+  }
+
+  public int[] getBitMasks()
+  {
+    return bitMasks;
+  }
+
+  public int getScanlineStride()
+  {
+    return scanlineStride;
+  }
+
+  public SampleModel createSubsetSampleModel(int[] bands)
+  {
+    // FIXME: Is this the right way to interpret bands?
+    
+    int numBands = bands.length;
+    
+    int[] bitMasks = new int[numBands];
+
+    for (int b=0; b<numBands; b++)
+      bitMasks[b] = this.bitMasks[bands[b]];
+
+    return new SinglePixelPackedSampleModel(dataType, width, height,
+					    scanlineStride, bitMasks);
+  }
+
+  public Object getDataElements(int x, int y, Object obj,
+				DataBuffer data)
+  {
+    int offset = scanlineStride*y + x + data.getOffset();
+    
+    return Buffers.getData(data, offset, obj,
+			   0, // destination offset,
+			   1  // length
+			   );
+  }
+
+  public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    int offset = scanlineStride*y + x;
+    if (iArray == null) iArray = new int[numBands];
+    int samples = data.getElem(offset);
+
+    for (int b=0; b<numBands; b++)
+      iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b];
+	
+    return iArray;
+  }
+
+  public int[] getPixels(int x, int y, int w, int h, int[] iArray,
+			 DataBuffer data)
+  {
+    int offset = scanlineStride*y + x;
+    if (iArray == null) iArray = new int[numBands*w*h];
+    int outOffset = 0;
+    for (y=0; y<h; y++)
+      {
+	int lineOffset = offset;
+	for (x=0; x<w; x++)
+	  {
+	    int samples = data.getElem(lineOffset++);
+	    for (int b=0; b<numBands; b++)
+	      iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b];
+	  }
+	offset += scanlineStride;
+      }
+    return iArray;	
+  }
+
+  public int getSample(int x, int y, int b, DataBuffer data)
+  {
+    int offset = scanlineStride*y + x;
+    int samples = data.getElem(offset);
+    return (samples & bitMasks[b]) >>> bitOffsets[b];
+  }
+
+  public void setDataElements(int x, int y, Object obj, DataBuffer data)
+  {
+    int offset = scanlineStride*y + x + data.getOffset();
+    
+    int transferType = getTransferType();
+    if (getTransferType() != data.getDataType())
+      {
+	throw new IllegalArgumentException("transfer type ("+
+					   getTransferType()+"), "+
+					   "does not match data "+
+					   "buffer type (" +
+					   data.getDataType() +
+					   ").");
+      }
+
+    try
+      {
+	switch (transferType)
+	  {
+	  case DataBuffer.TYPE_BYTE:
+	    {
+	      DataBufferByte out = (DataBufferByte) data;
+	      byte[] in = (byte[]) obj;
+	      out.getData()[offset] = in[0];
+	      return;
+	    }
+	  case DataBuffer.TYPE_USHORT:
+	    {
+	      DataBufferUShort out = (DataBufferUShort) data;
+	      short[] in = (short[]) obj;
+	      out.getData()[offset] = in[0];
+	      return;
+	    }
+	  case DataBuffer.TYPE_INT:
+	    {
+	      DataBufferInt out = (DataBufferInt) data;
+	      int[] in = (int[]) obj;
+	      out.getData()[offset] = in[0];
+	      return;
+	    }
+	    // FIXME: Fill in the other possible types.
+	  default:
+	    throw new InternalError();
+	  }
+      }
+    catch (ArrayIndexOutOfBoundsException aioobe)
+      {
+	String msg = "While writing data elements" +
+	  ", x="+x+", y="+y+
+	  ", width="+width+", height="+height+
+	  ", scanlineStride="+scanlineStride+
+	  ", offset="+offset+
+	  ", data.getSize()="+data.getSize()+
+	  ", data.getOffset()="+data.getOffset()+
+	  ": " +
+	  aioobe;
+	throw new ArrayIndexOutOfBoundsException(msg);
+      }
+    }
+
+  public void setPixel(int x, int y, int[] iArray, DataBuffer data)
+  {
+    int offset = scanlineStride*y + x;
+    
+    int samples = 0;
+    for (int b=0; b<numBands; b++)
+      samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b];
+
+    data.setElem(offset, samples);
+  }
+
+  public void setSample(int x, int y, int b, int s, DataBuffer data)
+  {
+    int offset = scanlineStride*y + x;
+    int samples = data.getElem(offset);
+    int bitMask = bitMasks[b];
+    samples &= ~bitMask;
+    samples |= (s << bitOffsets[b]) & bitMask;
+    data.setElem(offset, samples);
+  }
+}
Index: libjava/java/awt/image/WritableRaster.java
===================================================================
RCS file: WritableRaster.java
diff -N WritableRaster.java
--- /dev/null	Tue May  5 13:32:27 1998
+++ WritableRaster.java	Tue Jul 25 08:34:27 2000
@@ -0,0 +1,234 @@
+/* Copyright © 2000  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+package java.awt.image;
+
+import java.awt.*;
+
+/**
+ * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
+ */
+public class WritableRaster extends Raster
+{
+  protected WritableRaster(SampleModel sampleModel, Point origin) 
+  {
+    this(sampleModel, sampleModel.createDataBuffer(), origin);
+  }
+  
+  protected WritableRaster(SampleModel sampleModel,
+			   DataBuffer dataBuffer, Point origin)
+  {
+    this(sampleModel, dataBuffer,
+	 new Rectangle(origin.x, origin.y,
+		       sampleModel.getWidth(), sampleModel.getHeight()),
+	 origin,
+	 null);
+  }
+
+  protected WritableRaster(SampleModel sampleModel, 
+			   DataBuffer dataBuffer,
+			   Rectangle aRegion,
+			   Point sampleModelTranslate,
+			   WritableRaster parent)
+  {
+    super(sampleModel, dataBuffer, aRegion, sampleModelTranslate,
+	  parent);
+  }
+
+  public WritableRaster getWritableParent()
+  {
+    return (WritableRaster) getParent();
+  }
+  
+  public WritableRaster createWritableTranslatedChild(int childMinX,
+						      int childMinY)
+  {
+    // This mirrors the code from the super class
+    int tcx = sampleModelTranslateX - minX + childMinX;
+    int tcy = sampleModelTranslateY - minY + childMinY;
+    
+    return new WritableRaster(sampleModel, dataBuffer,
+			      new Rectangle(childMinX, childMinY,
+					    width, height),
+			      new Point(tcx, tcy),
+			      this);
+  }
+
+  public WritableRaster createWritableChild(int parentX,
+					    int parentY,
+					    int w, int h,
+					    int childMinX,
+					    int childMinY,
+					    int[] bandList)
+  {
+    // This mirrors the code from the super class
+    
+    // FIXME: Throw RasterFormatException if child bounds extends
+    // beyond the bounds of this raster.
+    
+    SampleModel sm = (bandList == null) ?
+      sampleModel :
+      sampleModel.createSubsetSampleModel(bandList);
+    
+    return new
+      WritableRaster(sm, dataBuffer,
+		     new Rectangle(childMinX, childMinY,
+				   w, h),
+		     new Point(sampleModelTranslateX+childMinX-parentX,
+			       sampleModelTranslateY+childMinY-parentY),
+		     this);
+  }
+
+  public void setDataElements(int x, int y, Object inData)
+  {
+    sampleModel.setDataElements(x-sampleModelTranslateX,
+				y-sampleModelTranslateY,
+				inData, dataBuffer);
+  }
+
+  public void setDataElements(int x, int y, Raster inRaster)
+  {
+    Object dataElements = getDataElements(0, 0,
+					  inRaster.getWidth(),
+					  inRaster.getHeight(),
+					  null);
+    setDataElements(x, y, dataElements);
+  }
+
+  public void setDataElements(int x, int y, int w, int h,
+			      Object inData)
+  {
+    sampleModel.setDataElements(x-sampleModelTranslateX,
+				y-sampleModelTranslateY,
+				w, h, inData, dataBuffer);
+  }
+
+  public void setRect(Raster srcRaster)
+  {
+    setRect(srcRaster, 0, 0);
+  }
+
+  public void setRect(Raster srcRaster, int dx, int dy) 
+  {
+    Rectangle targetUnclipped = new Rectangle(srcRaster.getMinX()+dx,
+					      srcRaster.getMinY()+dy,
+					      srcRaster.getWidth(),
+					      srcRaster.getHeight());
+	
+    Rectangle target = getBounds().intersection(targetUnclipped);
+
+    if (target.isEmpty()) return;
+    
+    int sx = target.x - dx;
+    int sy = target.y - dy;
+    
+    // FIXME: Do tests on rasters and use get/set data instead.
+    
+    /* The JDK documentation seems to imply this implementation.
+       (the trucation of higher bits), but an implementation using
+       get/setDataElements would be more efficient. None of the
+       implementations would do anything sensible when the sample
+       models don't match.
+       
+       But this is probably not the place to consider such
+       optimizations.*/
+
+    int[] pixels = srcRaster.getPixels(sx, sy,
+				       target.width, target.height,
+				       (int[]) null);
+
+    setPixels(target.x, target.y, target.width, target.height, pixels);
+  }
+
+  public void setPixel(int x, int y, int[] iArray)
+  {
+    sampleModel.setPixel(x-sampleModelTranslateX,
+			 y-sampleModelTranslateY,
+			 iArray, dataBuffer);
+  }
+
+  public void setPixel(int x, int y, float[] fArray)
+  {
+    sampleModel.setPixel(x-sampleModelTranslateX,
+			 y-sampleModelTranslateY,
+			 fArray, dataBuffer);
+  }
+
+  public void setPixel(int x, int y, double[] dArray)
+  {
+    sampleModel.setPixel(x-sampleModelTranslateX,
+			 y-sampleModelTranslateY,
+			 dArray, dataBuffer);
+  }
+
+  public void setPixels(int x, int y, int w, int h, int[] iArray)
+  {
+    sampleModel.setPixels(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  w, h, iArray, dataBuffer);
+  }
+
+  public void setPixels(int x, int y, int w, int h, float[] fArray)
+  {
+    sampleModel.setPixels(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  w, h, fArray, dataBuffer);
+  }
+
+  public void setPixels(int x, int y, int w, int h, double[] dArray)
+  {
+    sampleModel.setPixels(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  w, h, dArray, dataBuffer);
+  }
+
+  public void setSample(int x, int y, int b, int s)
+  {
+    sampleModel.setSample(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  b, s, dataBuffer);
+  }
+
+  public void setSample(int x, int y, int b, float s)
+  {
+    sampleModel.setSample(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  b, s, dataBuffer);
+  }
+
+  public void setSample(int x, int y, int b, double s)
+  {
+    sampleModel.setSample(x-sampleModelTranslateX,
+			  y-sampleModelTranslateY,
+			  b, s, dataBuffer);
+  }
+
+  public void setSamples(int x, int y, int w, int h, int b,
+			 int[] iArray)
+  {
+    sampleModel.setSamples(x-sampleModelTranslateX,
+			   y-sampleModelTranslateY,
+			   w, h, b, iArray, dataBuffer);
+  }
+
+  public void setSamples(int x, int y, int w, int h, int b,
+			 float[] fArray)
+  {
+    sampleModel.setSamples(x-sampleModelTranslateX,
+			   y-sampleModelTranslateY,
+			   w, h, b, fArray, dataBuffer);
+  }
+
+  public void setSamples(int x, int y, int w, int h, int b,
+			 double[] dArray)
+  {
+    sampleModel.setSamples(x-sampleModelTranslateX,
+			   y-sampleModelTranslateY,
+			   w, h, b, dArray, dataBuffer);
+  }
+}


-- 
Rolf W. Rasmussen

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]