~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/java/awt/image/BufferedImage.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
 
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
4
 *
 
5
 * This code is free software; you can redistribute it and/or modify it
 
6
 * under the terms of the GNU General Public License version 2 only, as
 
7
 * published by the Free Software Foundation.  Oracle designates this
 
8
 * particular file as subject to the "Classpath" exception as provided
 
9
 * by Oracle in the LICENSE file that accompanied this code.
 
10
 *
 
11
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
14
 * version 2 for more details (a copy is included in the LICENSE file that
 
15
 * accompanied this code).
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License version
 
18
 * 2 along with this work; if not, write to the Free Software Foundation,
 
19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 *
 
21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
22
 * or visit www.oracle.com if you need additional information or have any
 
23
 * questions.
 
24
 */
 
25
 
 
26
package java.awt.image;
 
27
 
 
28
import cli.System.Drawing.Color;
 
29
import cli.System.Drawing.Imaging.*;
 
30
 
 
31
import java.awt.Transparency;
 
32
import java.awt.color.ColorSpace;
 
33
import java.awt.Graphics2D;
 
34
import java.awt.GraphicsConfiguration;
 
35
import java.awt.GraphicsEnvironment;
 
36
import java.awt.ImageCapabilities;
 
37
import java.awt.geom.Rectangle2D;
 
38
import java.awt.geom.Point2D;
 
39
import java.awt.Point;
 
40
import java.awt.Rectangle;
 
41
import java.util.Hashtable;
 
42
import java.util.Vector;
 
43
 
 
44
import sun.awt.image.BytePackedRaster;
 
45
import sun.awt.image.ShortComponentRaster;
 
46
import sun.awt.image.ByteComponentRaster;
 
47
import sun.awt.image.IntegerComponentRaster;
 
48
import sun.awt.image.OffScreenImageSource;
 
49
 
 
50
/**
 
51
 *
 
52
 * The <code>BufferedImage</code> subclass describes an {@link
 
53
 * java.awt.Image Image} with an accessible buffer of image data.
 
54
 * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a
 
55
 * {@link Raster} of image data.
 
56
 * The number and types of bands in the {@link SampleModel} of the
 
57
 * <code>Raster</code> must match the number and types required by the
 
58
 * <code>ColorModel</code> to represent its color and alpha components.
 
59
 * All <code>BufferedImage</code> objects have an upper left corner
 
60
 * coordinate of (0,&nbsp;0).  Any <code>Raster</code> used to construct a
 
61
 * <code>BufferedImage</code> must therefore have minX=0 and minY=0.
 
62
 *
 
63
 * <p>
 
64
 * This class relies on the data fetching and setting methods
 
65
 * of <code>Raster</code>,
 
66
 * and on the color characterization methods of <code>ColorModel</code>.
 
67
 *
 
68
 * @see ColorModel
 
69
 * @see Raster
 
70
 * @see WritableRaster
 
71
 */
 
72
 
 
73
public class BufferedImage extends java.awt.Image
 
74
                           implements WritableRenderedImage, Transparency
 
75
{
 
76
    int        imageType = TYPE_CUSTOM;
 
77
    ColorModel colorModel;
 
78
    WritableRaster raster;
 
79
    OffScreenImageSource osis;
 
80
    Hashtable properties;
 
81
 
 
82
    boolean    isAlphaPremultiplied;// If true, alpha has been premultiplied in
 
83
    // color channels
 
84
 
 
85
    /**
 
86
     * Image Type Constants
 
87
     */
 
88
 
 
89
    /**
 
90
     * Image type is not recognized so it must be a customized
 
91
     * image.  This type is only used as a return value for the getType()
 
92
     * method.
 
93
     */
 
94
    public static final int TYPE_CUSTOM = 0;
 
95
 
 
96
    /**
 
97
     * Represents an image with 8-bit RGB color components packed into
 
98
     * integer pixels.  The image has a {@link DirectColorModel} without
 
99
     * alpha.
 
100
     * When data with non-opaque alpha is stored
 
101
     * in an image of this type,
 
102
     * the color data must be adjusted to a non-premultiplied form
 
103
     * and the alpha discarded,
 
104
     * as described in the
 
105
     * {@link java.awt.AlphaComposite} documentation.
 
106
     */
 
107
    public static final int TYPE_INT_RGB = 1;
 
108
 
 
109
    /**
 
110
     * Represents an image with 8-bit RGBA color components packed into
 
111
     * integer pixels.  The image has a <code>DirectColorModel</code>
 
112
     * with alpha. The color data in this image is considered not to be
 
113
     * premultiplied with alpha.  When this type is used as the
 
114
     * <code>imageType</code> argument to a <code>BufferedImage</code>
 
115
     * constructor, the created image is consistent with images
 
116
     * created in the JDK1.1 and earlier releases.
 
117
     */
 
118
    public static final int TYPE_INT_ARGB = 2;
 
119
 
 
120
    /**
 
121
     * Represents an image with 8-bit RGBA color components packed into
 
122
     * integer pixels.  The image has a <code>DirectColorModel</code>
 
123
     * with alpha.  The color data in this image is considered to be
 
124
     * premultiplied with alpha.
 
125
     */
 
126
    public static final int TYPE_INT_ARGB_PRE = 3;
 
127
 
 
128
    /**
 
129
     * Represents an image with 8-bit RGB color components, corresponding
 
130
     * to a Windows- or Solaris- style BGR color model, with the colors
 
131
     * Blue, Green, and Red packed into integer pixels.  There is no alpha.
 
132
     * The image has a {@link DirectColorModel}.
 
133
     * When data with non-opaque alpha is stored
 
134
     * in an image of this type,
 
135
     * the color data must be adjusted to a non-premultiplied form
 
136
     * and the alpha discarded,
 
137
     * as described in the
 
138
     * {@link java.awt.AlphaComposite} documentation.
 
139
     */
 
140
    public static final int TYPE_INT_BGR = 4;
 
141
 
 
142
    /**
 
143
     * Represents an image with 8-bit RGB color components, corresponding
 
144
     * to a Windows-style BGR color model) with the colors Blue, Green,
 
145
     * and Red stored in 3 bytes.  There is no alpha.  The image has a
 
146
     * <code>ComponentColorModel</code>.
 
147
     * When data with non-opaque alpha is stored
 
148
     * in an image of this type,
 
149
     * the color data must be adjusted to a non-premultiplied form
 
150
     * and the alpha discarded,
 
151
     * as described in the
 
152
     * {@link java.awt.AlphaComposite} documentation.
 
153
     */
 
154
    public static final int TYPE_3BYTE_BGR = 5;
 
155
 
 
156
    /**
 
157
     * Represents an image with 8-bit RGBA color components with the colors
 
158
     * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
 
159
     * image has a <code>ComponentColorModel</code> with alpha.  The
 
160
     * color data in this image is considered not to be premultiplied with
 
161
     * alpha.  The byte data is interleaved in a single
 
162
     * byte array in the order A, B, G, R
 
163
     * from lower to higher byte addresses within each pixel.
 
164
     */
 
165
    public static final int TYPE_4BYTE_ABGR = 6;
 
166
 
 
167
    /**
 
168
     * Represents an image with 8-bit RGBA color components with the colors
 
169
     * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha.  The
 
170
     * image has a <code>ComponentColorModel</code> with alpha. The color
 
171
     * data in this image is considered to be premultiplied with alpha.
 
172
     * The byte data is interleaved in a single byte array in the order
 
173
     * A, B, G, R from lower to higher byte addresses within each pixel.
 
174
     */
 
175
    public static final int TYPE_4BYTE_ABGR_PRE = 7;
 
176
 
 
177
    /**
 
178
     * Represents an image with 5-6-5 RGB color components (5-bits red,
 
179
     * 6-bits green, 5-bits blue) with no alpha.  This image has
 
180
     * a <code>DirectColorModel</code>.
 
181
     * When data with non-opaque alpha is stored
 
182
     * in an image of this type,
 
183
     * the color data must be adjusted to a non-premultiplied form
 
184
     * and the alpha discarded,
 
185
     * as described in the
 
186
     * {@link java.awt.AlphaComposite} documentation.
 
187
     */
 
188
    public static final int TYPE_USHORT_565_RGB = 8;
 
189
 
 
190
    /**
 
191
     * Represents an image with 5-5-5 RGB color components (5-bits red,
 
192
     * 5-bits green, 5-bits blue) with no alpha.  This image has
 
193
     * a <code>DirectColorModel</code>.
 
194
     * When data with non-opaque alpha is stored
 
195
     * in an image of this type,
 
196
     * the color data must be adjusted to a non-premultiplied form
 
197
     * and the alpha discarded,
 
198
     * as described in the
 
199
     * {@link java.awt.AlphaComposite} documentation.
 
200
     */
 
201
    public static final int TYPE_USHORT_555_RGB = 9;
 
202
 
 
203
    /**
 
204
     * Represents a unsigned byte grayscale image, non-indexed.  This
 
205
     * image has a <code>ComponentColorModel</code> with a CS_GRAY
 
206
     * {@link ColorSpace}.
 
207
     * When data with non-opaque alpha is stored
 
208
     * in an image of this type,
 
209
     * the color data must be adjusted to a non-premultiplied form
 
210
     * and the alpha discarded,
 
211
     * as described in the
 
212
     * {@link java.awt.AlphaComposite} documentation.
 
213
     */
 
214
    public static final int TYPE_BYTE_GRAY = 10;
 
215
 
 
216
    /**
 
217
     * Represents an unsigned short grayscale image, non-indexed).  This
 
218
     * image has a <code>ComponentColorModel</code> with a CS_GRAY
 
219
     * <code>ColorSpace</code>.
 
220
     * When data with non-opaque alpha is stored
 
221
     * in an image of this type,
 
222
     * the color data must be adjusted to a non-premultiplied form
 
223
     * and the alpha discarded,
 
224
     * as described in the
 
225
     * {@link java.awt.AlphaComposite} documentation.
 
226
     */
 
227
    public static final int TYPE_USHORT_GRAY = 11;
 
228
 
 
229
    /**
 
230
     * Represents an opaque byte-packed 1, 2, or 4 bit image.  The
 
231
     * image has an {@link IndexColorModel} without alpha.  When this
 
232
     * type is used as the <code>imageType</code> argument to the
 
233
     * <code>BufferedImage</code> constructor that takes an
 
234
     * <code>imageType</code> argument but no <code>ColorModel</code>
 
235
     * argument, a 1-bit image is created with an
 
236
     * <code>IndexColorModel</code> with two colors in the default
 
237
     * sRGB <code>ColorSpace</code>: {0,&nbsp;0,&nbsp;0} and
 
238
     * {255,&nbsp;255,&nbsp;255}.
 
239
     *
 
240
     * <p> Images with 2 or 4 bits per pixel may be constructed via
 
241
     * the <code>BufferedImage</code> constructor that takes a
 
242
     * <code>ColorModel</code> argument by supplying a
 
243
     * <code>ColorModel</code> with an appropriate map size.
 
244
     *
 
245
     * <p> Images with 8 bits per pixel should use the image types
 
246
     * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code>
 
247
     * depending on their <code>ColorModel</code>.
 
248
 
 
249
     * <p> When color data is stored in an image of this type,
 
250
     * the closest color in the colormap is determined
 
251
     * by the <code>IndexColorModel</code> and the resulting index is stored.
 
252
     * Approximation and loss of alpha or color components
 
253
     * can result, depending on the colors in the
 
254
     * <code>IndexColorModel</code> colormap.
 
255
     */
 
256
    public static final int TYPE_BYTE_BINARY = 12;
 
257
 
 
258
    /**
 
259
     * Represents an indexed byte image.  When this type is used as the
 
260
     * <code>imageType</code> argument to the <code>BufferedImage</code>
 
261
     * constructor that takes an <code>imageType</code> argument
 
262
     * but no <code>ColorModel</code> argument, an
 
263
     * <code>IndexColorModel</code> is created with
 
264
     * a 256-color 6/6/6 color cube palette with the rest of the colors
 
265
     * from 216-255 populated by grayscale values in the
 
266
     * default sRGB ColorSpace.
 
267
     *
 
268
     * <p> When color data is stored in an image of this type,
 
269
     * the closest color in the colormap is determined
 
270
     * by the <code>IndexColorModel</code> and the resulting index is stored.
 
271
     * Approximation and loss of alpha or color components
 
272
     * can result, depending on the colors in the
 
273
     * <code>IndexColorModel</code> colormap.
 
274
     */
 
275
    public static final int TYPE_BYTE_INDEXED = 13;
 
276
 
 
277
    private static final int DCM_RED_MASK   = 0x00ff0000;
 
278
    private static final int DCM_GREEN_MASK = 0x0000ff00;
 
279
    private static final int DCM_BLUE_MASK  = 0x000000ff;
 
280
    private static final int DCM_ALPHA_MASK = 0xff000000;
 
281
    private static final int DCM_565_RED_MASK = 0xf800;
 
282
    private static final int DCM_565_GRN_MASK = 0x07E0;
 
283
    private static final int DCM_565_BLU_MASK = 0x001F;
 
284
    private static final int DCM_555_RED_MASK = 0x7C00;
 
285
    private static final int DCM_555_GRN_MASK = 0x03E0;
 
286
    private static final int DCM_555_BLU_MASK = 0x001F;
 
287
    private static final int DCM_BGR_RED_MASK = 0x0000ff;
 
288
    private static final int DCM_BGR_GRN_MASK = 0x00ff00;
 
289
    private static final int DCM_BGR_BLU_MASK = 0xff0000;
 
290
 
 
291
    /** reference to the :NET equivalent */
 
292
    private cli.System.Drawing.Bitmap bitmap;
 
293
    
 
294
    /** Which buffer include the current data, raster or bitmap */
 
295
    private int currentBuffer;
 
296
    
 
297
    private static final int BUFFER_BITMAP = 1;
 
298
    private static final int BUFFER_RASTER = 2;
 
299
    private static final int BUFFER_BOTH   = 3;
 
300
 
 
301
    /**
 
302
     * Create a BufferedImage directly from the .NET Bitmap class
 
303
     */
 
304
    @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
 
305
    public BufferedImage(cli.System.Drawing.Bitmap bitmap){
 
306
        this.imageType = TYPE_INT_ARGB;
 
307
        this.colorModel = createColorModel();
 
308
        this.bitmap = bitmap;
 
309
        this.currentBuffer = BUFFER_BITMAP;
 
310
    }
 
311
 
 
312
    /**
 
313
     * Constructs a <code>BufferedImage</code> of one of the predefined
 
314
     * image types.  The <code>ColorSpace</code> for the image is the
 
315
     * default sRGB space.
 
316
     * @param width     width of the created image
 
317
     * @param height    height of the created image
 
318
     * @param imageType type of the created image
 
319
     * @see ColorSpace
 
320
     * @see #TYPE_INT_RGB
 
321
     * @see #TYPE_INT_ARGB
 
322
     * @see #TYPE_INT_ARGB_PRE
 
323
     * @see #TYPE_INT_BGR
 
324
     * @see #TYPE_3BYTE_BGR
 
325
     * @see #TYPE_4BYTE_ABGR
 
326
     * @see #TYPE_4BYTE_ABGR_PRE
 
327
     * @see #TYPE_BYTE_GRAY
 
328
     * @see #TYPE_USHORT_GRAY
 
329
     * @see #TYPE_BYTE_BINARY
 
330
     * @see #TYPE_BYTE_INDEXED
 
331
     * @see #TYPE_USHORT_565_RGB
 
332
     * @see #TYPE_USHORT_555_RGB
 
333
     */
 
334
    public BufferedImage(int width,
 
335
                         int height,
 
336
                         int imageType) {
 
337
        this.imageType = imageType;
 
338
        this.colorModel = createColorModel();
 
339
        this.bitmap = createBitmap(width, height);
 
340
        this.currentBuffer = BUFFER_BITMAP;
 
341
    }
 
342
 
 
343
    /**
 
344
     * Create a Bitmap if not already one exists
 
345
     * @param width     width of the created image
 
346
     * @param height    height of the created image
 
347
     * @return a Bitmap object, never null
 
348
     */
 
349
    private cli.System.Drawing.Bitmap createBitmap(int width, int height){
 
350
        if(bitmap != null){
 
351
            return bitmap;
 
352
        }
 
353
        if(width <= 0 || height <= 0){
 
354
            throw new IllegalArgumentException("Width (" + width + ") and height (" + height + ") cannot be <= 0");
 
355
        }
 
356
        return new cli.System.Drawing.Bitmap(width, height, PixelFormat.wrap(PixelFormat.Format32bppArgb));
 
357
    }
 
358
 
 
359
    /**
 
360
     * Constructs a <code>BufferedImage</code> of one of the predefined
 
361
     * image types:
 
362
     * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
 
363
     *
 
364
     * <p> If the image type is TYPE_BYTE_BINARY, the number of
 
365
     * entries in the color model is used to determine whether the
 
366
     * image should have 1, 2, or 4 bits per pixel.  If the color model
 
367
     * has 1 or 2 entries, the image will have 1 bit per pixel.  If it
 
368
     * has 3 or 4 entries, the image with have 2 bits per pixel.  If
 
369
     * it has between 5 and 16 entries, the image will have 4 bits per
 
370
     * pixel.  Otherwise, an IllegalArgumentException will be thrown.
 
371
     *
 
372
     * @param width     width of the created image
 
373
     * @param height    height of the created image
 
374
     * @param imageType type of the created image
 
375
     * @param cm        <code>IndexColorModel</code> of the created image
 
376
     * @throws IllegalArgumentException   if the imageType is not
 
377
     * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is
 
378
     * TYPE_BYTE_BINARY and the color map has more than 16 entries.
 
379
     * @see #TYPE_BYTE_BINARY
 
380
     * @see #TYPE_BYTE_INDEXED
 
381
     */
 
382
    public BufferedImage (int width,
 
383
                          int height,
 
384
                          int imageType,
 
385
                          IndexColorModel cm) {
 
386
        if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
 
387
            throw new IllegalArgumentException("This image types do not have "+
 
388
                                               "premultiplied alpha.");
 
389
        }
 
390
 
 
391
        switch(imageType) {
 
392
        case TYPE_BYTE_BINARY:
 
393
            int bits; // Will be set below
 
394
            int mapSize = cm.getMapSize();
 
395
            if (mapSize <= 2) {
 
396
                bits = 1;
 
397
            } else if (mapSize <= 4) {
 
398
                bits = 2;
 
399
            } else if (mapSize <= 16) {
 
400
                bits = 4;
 
401
            } else {
 
402
                throw new IllegalArgumentException
 
403
                    ("Color map for TYPE_BYTE_BINARY " +
 
404
                     "must have no more than 16 entries");
 
405
            }
 
406
            raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
 
407
                                                width, height, 1, bits, null);
 
408
            break;
 
409
 
 
410
        case TYPE_BYTE_INDEXED:
 
411
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
 
412
                                                    width, height, 1, null);
 
413
            break;
 
414
        default:
 
415
            throw new IllegalArgumentException("Invalid image type (" +
 
416
                                               imageType+").  Image type must"+
 
417
                                               " be either TYPE_BYTE_BINARY or "+
 
418
                                               " TYPE_BYTE_INDEXED");
 
419
        }
 
420
 
 
421
        if (!cm.isCompatibleRaster(raster)) {
 
422
            throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
 
423
        }
 
424
 
 
425
        colorModel = cm;
 
426
        this.imageType = imageType;
 
427
        this.currentBuffer = BUFFER_RASTER;
 
428
    }
 
429
 
 
430
    /**
 
431
     * Constructs a new <code>BufferedImage</code> with a specified
 
432
     * <code>ColorModel</code> and <code>Raster</code>.  If the number and
 
433
     * types of bands in the <code>SampleModel</code> of the
 
434
     * <code>Raster</code> do not match the number and types required by
 
435
     * the <code>ColorModel</code> to represent its color and alpha
 
436
     * components, a {@link RasterFormatException} is thrown.  This
 
437
     * method can multiply or divide the color <code>Raster</code> data by
 
438
     * alpha to match the <code>alphaPremultiplied</code> state
 
439
     * in the <code>ColorModel</code>.  Properties for this
 
440
     * <code>BufferedImage</code> can be established by passing
 
441
     * in a {@link Hashtable} of <code>String</code>/<code>Object</code>
 
442
     * pairs.
 
443
     * @param cm <code>ColorModel</code> for the new image
 
444
     * @param raster     <code>Raster</code> for the image data
 
445
     * @param isRasterPremultiplied   if <code>true</code>, the data in
 
446
     *                  the raster has been premultiplied with alpha.
 
447
     * @param properties <code>Hashtable</code> of
 
448
     *                  <code>String</code>/<code>Object</code> pairs.
 
449
     * @exception <code>RasterFormatException</code> if the number and
 
450
     * types of bands in the <code>SampleModel</code> of the
 
451
     * <code>Raster</code> do not match the number and types required by
 
452
     * the <code>ColorModel</code> to represent its color and alpha
 
453
     * components.
 
454
     * @exception <code>IllegalArgumentException</code> if
 
455
     *          <code>raster</code> is incompatible with <code>cm</code>
 
456
     * @see ColorModel
 
457
     * @see Raster
 
458
     * @see WritableRaster
 
459
     */
 
460
 
 
461
 
 
462
/*
 
463
 *
 
464
 *  FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
 
465
 *  SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
 
466
 *
 
467
 */
 
468
    public BufferedImage (ColorModel cm,
 
469
                          WritableRaster raster,
 
470
                          boolean isRasterPremultiplied,
 
471
                          Hashtable<?,?> properties) {
 
472
        
 
473
        if (!cm.isCompatibleRaster(raster)) {
 
474
            throw new
 
475
                IllegalArgumentException("Raster "+raster+
 
476
                                         " is incompatible with ColorModel "+
 
477
                                         cm);
 
478
        }
 
479
 
 
480
        if ((raster.minX != 0) || (raster.minY != 0)) {
 
481
            throw new
 
482
                IllegalArgumentException("Raster "+raster+
 
483
                                         " has minX or minY not equal to zero: "
 
484
                                         + raster.minX + " " + raster.minY);
 
485
        }
 
486
 
 
487
        colorModel = cm;
 
488
        this.raster  = raster;
 
489
        this.currentBuffer = BUFFER_RASTER;
 
490
        this.properties = properties;
 
491
        int numBands = raster.getNumBands();
 
492
        boolean isAlphaPre = cm.isAlphaPremultiplied();
 
493
        ColorSpace cs;
 
494
 
 
495
        // Force the raster data alpha state to match the premultiplied
 
496
        // state in the color model
 
497
        coerceData(isRasterPremultiplied);
 
498
 
 
499
        SampleModel sm = raster.getSampleModel();
 
500
        cs = cm.getColorSpace();
 
501
        int csType = cs.getType();
 
502
        if (csType != ColorSpace.TYPE_RGB) {
 
503
            if (csType == ColorSpace.TYPE_GRAY
 
504
                && cm instanceof ComponentColorModel) {
 
505
                // Check if this might be a child raster (fix for bug 4240596)
 
506
                if (sm instanceof ComponentSampleModel &&
 
507
                    ((ComponentSampleModel)sm).getPixelStride() != numBands) {
 
508
                    imageType = TYPE_CUSTOM;
 
509
                } else if (raster instanceof ByteComponentRaster &&
 
510
                       raster.getNumBands() == 1 &&
 
511
                       cm.getComponentSize(0) == 8 &&
 
512
                       ((ByteComponentRaster)raster).getPixelStride() == 1) {
 
513
                    imageType = TYPE_BYTE_GRAY;
 
514
                } else if (raster instanceof ShortComponentRaster &&
 
515
                       raster.getNumBands() == 1 &&
 
516
                       cm.getComponentSize(0) == 16 &&
 
517
                       ((ShortComponentRaster)raster).getPixelStride() == 1) {
 
518
                    imageType = TYPE_USHORT_GRAY;
 
519
                }
 
520
            } else {
 
521
                imageType = TYPE_CUSTOM;
 
522
            }
 
523
            return;
 
524
        }
 
525
 
 
526
        if ((raster instanceof IntegerComponentRaster) &&
 
527
            (numBands == 3 || numBands == 4)) {
 
528
            IntegerComponentRaster iraster =
 
529
                (IntegerComponentRaster) raster;
 
530
            // Check if the raster params and the color model
 
531
            // are correct
 
532
            int pixSize = cm.getPixelSize();
 
533
            if (iraster.getPixelStride() == 1 &&
 
534
                cm instanceof DirectColorModel  &&
 
535
                (pixSize == 32 || pixSize == 24))
 
536
            {
 
537
                // Now check on the DirectColorModel params
 
538
                DirectColorModel dcm = (DirectColorModel) cm;
 
539
                int rmask = dcm.getRedMask();
 
540
                int gmask = dcm.getGreenMask();
 
541
                int bmask = dcm.getBlueMask();
 
542
                if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
 
543
                    bmask == DCM_BLUE_MASK)
 
544
                {
 
545
                    if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
 
546
                        imageType = (isAlphaPre
 
547
                                     ? TYPE_INT_ARGB_PRE
 
548
                                     : TYPE_INT_ARGB);
 
549
                    }
 
550
                    else {
 
551
                        // No Alpha
 
552
                        if (!dcm.hasAlpha()) {
 
553
                            imageType = TYPE_INT_RGB;
 
554
                        }
 
555
                    }
 
556
                }   // if (dcm.getRedMask() == DCM_RED_MASK &&
 
557
                else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
 
558
                         && bmask == DCM_BGR_BLU_MASK) {
 
559
                    if (!dcm.hasAlpha()) {
 
560
                        imageType = TYPE_INT_BGR;
 
561
                    }
 
562
                }  // if (rmask == DCM_BGR_RED_MASK &&
 
563
            }   // if (iraster.getPixelStride() == 1
 
564
        }   // ((raster instanceof IntegerComponentRaster) &&
 
565
        else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
 
566
                 (!cm.hasAlpha() || !isAlphaPre))
 
567
        {
 
568
            IndexColorModel icm = (IndexColorModel) cm;
 
569
            int pixSize = icm.getPixelSize();
 
570
 
 
571
            if (raster instanceof BytePackedRaster) {
 
572
                imageType = TYPE_BYTE_BINARY;
 
573
            }   // if (raster instanceof BytePackedRaster)
 
574
            else if (raster instanceof ByteComponentRaster) {
 
575
                ByteComponentRaster braster = (ByteComponentRaster) raster;
 
576
                if (braster.getPixelStride() == 1 && pixSize <= 8) {
 
577
                    imageType = TYPE_BYTE_INDEXED;
 
578
                }
 
579
            }
 
580
        }   // else if (cm instanceof IndexColorModel) && (numBands == 1))
 
581
        else if ((raster instanceof ShortComponentRaster)
 
582
                 && (cm instanceof DirectColorModel)
 
583
                 && (numBands == 3)
 
584
                 && !cm.hasAlpha())
 
585
        {
 
586
            DirectColorModel dcm = (DirectColorModel) cm;
 
587
            if (dcm.getRedMask() == DCM_565_RED_MASK) {
 
588
                if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
 
589
                    dcm.getBlueMask()  == DCM_565_BLU_MASK) {
 
590
                    imageType = TYPE_USHORT_565_RGB;
 
591
                }
 
592
            }
 
593
            else if (dcm.getRedMask() == DCM_555_RED_MASK) {
 
594
                if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
 
595
                    dcm.getBlueMask() == DCM_555_BLU_MASK) {
 
596
                    imageType = TYPE_USHORT_555_RGB;
 
597
                }
 
598
            }
 
599
        }   // else if ((cm instanceof IndexColorModel) && (numBands == 1))
 
600
        else if ((raster instanceof ByteComponentRaster)
 
601
                 && (cm instanceof ComponentColorModel)
 
602
                 && (raster.getSampleModel() instanceof PixelInterleavedSampleModel)
 
603
                 && (numBands == 3 || numBands == 4))
 
604
        {
 
605
            ComponentColorModel ccm = (ComponentColorModel) cm;
 
606
            PixelInterleavedSampleModel csm =
 
607
                (PixelInterleavedSampleModel)raster.getSampleModel();
 
608
            ByteComponentRaster braster = (ByteComponentRaster) raster;
 
609
            int[] offs = csm.getBandOffsets();
 
610
            if (ccm.getNumComponents() != numBands) {
 
611
                throw new RasterFormatException("Number of components in "+
 
612
                                                "ColorModel ("+
 
613
                                                ccm.getNumComponents()+
 
614
                                                ") does not match # in "+
 
615
                                                " Raster ("+numBands+")");
 
616
            }
 
617
            int[] nBits = ccm.getComponentSize();
 
618
            boolean is8bit = true;
 
619
            for (int i=0; i < numBands; i++) {
 
620
                if (nBits[i] != 8) {
 
621
                    is8bit = false;
 
622
                    break;
 
623
                }
 
624
            }
 
625
            if (is8bit &&
 
626
                offs[0] == numBands-1 &&
 
627
                offs[1] == numBands-2 &&
 
628
                offs[2] == numBands-3)
 
629
            {
 
630
                if (numBands == 3) {
 
631
                    imageType = TYPE_3BYTE_BGR;
 
632
                }
 
633
                else if (offs[3] == 0) {
 
634
                    imageType = (isAlphaPre
 
635
                                 ? TYPE_4BYTE_ABGR_PRE
 
636
                                 : TYPE_4BYTE_ABGR);
 
637
                }
 
638
            }
 
639
        }   // else if ((raster instanceof ByteComponentRaster) &&
 
640
    }
 
641
    
 
642
    /**
 
643
     * Get the .NET Bitmap object.
 
644
     */
 
645
    @cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
 
646
    public cli.System.Drawing.Bitmap getBitmap(){
 
647
        raster2Bitmap();
 
648
        return bitmap;
 
649
    }
 
650
 
 
651
    /**
 
652
     * This Implementation of BufferedImage has 2 different Buffer, 
 
653
     * a Java WritableRaster and a .NET Bitmap.
 
654
     * This method convert a Java WritableRaster to a .NET Bitmap if needed.
 
655
     */
 
656
    private void raster2Bitmap(){
 
657
        if(currentBuffer != BUFFER_RASTER){
 
658
            return; // BUFFER_BOTH and BUFFER_BITMAP
 
659
        }
 
660
        int width = getWidth();
 
661
        int height = getHeight();
 
662
        
 
663
        // First map the pixel from Java type to .NET type
 
664
        switch (getType()){
 
665
            case TYPE_INT_ARGB:
 
666
                copyToBitmap(width, height, ((DataBufferInt)raster.getDataBuffer()).getData());
 
667
                break;
 
668
            default:{
 
669
                bitmap = createBitmap(width, height);
 
670
                for( int y = 0; y<height; y++){
 
671
                    for(int x = 0; x<width; x++){
 
672
                        int rgb = colorModel.getRGB(raster.getDataElements(x, y, null));
 
673
                        bitmap.SetPixel(x, y, cli.System.Drawing.Color.FromArgb(rgb));
 
674
                    }
 
675
                }
 
676
            }   
 
677
        }
 
678
        this.currentBuffer = BUFFER_BOTH;
 
679
        return;
 
680
    }
 
681
 
 
682
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
683
    private void copyToBitmap(int width, int height, int[] pixelData)
 
684
    {
 
685
        long size = (long)width * (long)height;
 
686
        if (size > pixelData.length)
 
687
        {
 
688
            throw new IllegalArgumentException();
 
689
        }
 
690
        synchronized( bitmap ) {            
 
691
            bitmap = createBitmap(width, height);
 
692
            cli.System.Drawing.Rectangle rect = new cli.System.Drawing.Rectangle(0, 0, width, height);
 
693
            cli.System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, ImageLockMode.wrap(ImageLockMode.WriteOnly), PixelFormat.wrap(PixelFormat.Format32bppArgb));
 
694
            cli.System.IntPtr pixelPtr = data.get_Scan0();
 
695
            cli.System.Runtime.InteropServices.Marshal.Copy(pixelData, 0, pixelPtr, (int)size);
 
696
            bitmap.UnlockBits(data);
 
697
        }
 
698
    }
 
699
 
 
700
    /**
 
701
     * This Implementation of BufferedImage has 2 different Buffer, 
 
702
     * a Java WritableRaster and a .NET Bitmap.
 
703
     * This method convert the .NET Bitmap object to Java WritableRaster.
 
704
     */
 
705
    private void bitmap2Raster(){
 
706
        if(currentBuffer != BUFFER_BITMAP){
 
707
            return; // BUFFER_BOTH and BUFFER_RASTER
 
708
        }
 
709
        synchronized( bitmap ) {
 
710
            int width = bitmap.get_Width();
 
711
            int height = bitmap.get_Height();
 
712
            if(colorModel == null){
 
713
                colorModel = createColorModel();
 
714
            }
 
715
            if(raster == null){
 
716
                raster = createRaster(width, height);
 
717
            }
 
718
            
 
719
            switch (getType()){
 
720
                case TYPE_INT_ARGB:
 
721
                    copyFromBitmap(bitmap, ((DataBufferInt)raster.getDataBuffer()).getData());
 
722
                    break;
 
723
                default:
 
724
                    for( int y = 0; y<height; y++){
 
725
                        for(int x = 0; x<width; x++){
 
726
                            int rgb = bitmap.GetPixel(x, y).ToArgb();
 
727
                            raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
 
728
                        }
 
729
                    }
 
730
            }
 
731
            this.currentBuffer = BUFFER_BOTH;
 
732
        }
 
733
    }
 
734
 
 
735
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
736
    private static void copyFromBitmap(cli.System.Drawing.Bitmap bitmap, int[] pixelData)
 
737
    {
 
738
        int width = bitmap.get_Width();
 
739
        int height = bitmap.get_Height();
 
740
        long size = (long)width * (long)height;
 
741
        if (width <= 0 || height <= 0 || pixelData.length < size)
 
742
        {
 
743
            throw new IllegalArgumentException();
 
744
        }
 
745
        cli.System.Drawing.Rectangle rect = new cli.System.Drawing.Rectangle(0, 0, width, height);
 
746
        cli.System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, ImageLockMode.wrap(ImageLockMode.ReadOnly), PixelFormat.wrap(PixelFormat.Format32bppArgb));
 
747
        cli.System.IntPtr pixelPtr = data.get_Scan0();
 
748
        cli.System.Runtime.InteropServices.Marshal.Copy(pixelPtr, pixelData, 0, (int)size);        
 
749
        bitmap.UnlockBits(data);
 
750
    }
 
751
 
 
752
    /**
 
753
     * Create a new ColorModel based on the current imageType.
 
754
     */
 
755
    private ColorModel createColorModel(){
 
756
        switch(imageType){
 
757
            case TYPE_INT_RGB: {
 
758
                return new DirectColorModel(24, 0x00ff0000, // Red
 
759
                        0x0000ff00, // Green
 
760
                        0x000000ff, // Blue
 
761
                        0x0 // Alpha
 
762
                );
 
763
            }
 
764
            case TYPE_INT_ARGB: {
 
765
                return ColorModel.getRGBdefault();
 
766
            }
 
767
            case TYPE_INT_ARGB_PRE: {
 
768
                return new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000,// Red
 
769
                        0x0000ff00,// Green
 
770
                        0x000000ff,// Blue
 
771
                        0xff000000,// Alpha
 
772
                        true, // Alpha Premultiplied
 
773
                        DataBuffer.TYPE_INT);
 
774
            }
 
775
            case TYPE_INT_BGR: {
 
776
                return new DirectColorModel(24, 0x000000ff, // Red
 
777
                        0x0000ff00, // Green
 
778
                        0x00ff0000 // Blue
 
779
                );
 
780
            }
 
781
            case TYPE_3BYTE_BGR: {
 
782
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 
783
                int[] nBits = {8, 8, 8};
 
784
                return new ComponentColorModel(cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
 
785
            }
 
786
            case TYPE_4BYTE_ABGR: {
 
787
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 
788
                int[] nBits = {8, 8, 8, 8};
 
789
                return new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT,
 
790
                        DataBuffer.TYPE_BYTE);
 
791
            }
 
792
            case TYPE_4BYTE_ABGR_PRE: {
 
793
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
 
794
                int[] nBits = {8, 8, 8, 8};
 
795
                return new ComponentColorModel(cs, nBits, true, true, Transparency.TRANSLUCENT,
 
796
                        DataBuffer.TYPE_BYTE);
 
797
            }
 
798
            case TYPE_BYTE_GRAY: {
 
799
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
 
800
                int[] nBits = {8};
 
801
                return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
 
802
            }
 
803
            case TYPE_USHORT_GRAY: {
 
804
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
 
805
                int[] nBits = {16};
 
806
                return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE,
 
807
                        DataBuffer.TYPE_USHORT);
 
808
            }
 
809
            case TYPE_BYTE_BINARY: {
 
810
                byte[] arr = {(byte)0, (byte)0xff};
 
811
 
 
812
                return new IndexColorModel(1, 2, arr, arr, arr);
 
813
            }
 
814
            case TYPE_BYTE_INDEXED: {
 
815
                // Create a 6x6x6 color cube
 
816
                int[] cmap = new int[256];
 
817
                int i = 0;
 
818
                for(int r = 0; r < 256; r += 51){
 
819
                    for(int g = 0; g < 256; g += 51){
 
820
                        for(int b = 0; b < 256; b += 51){
 
821
                            cmap[i++] = (r << 16) | (g << 8) | b;
 
822
                        }
 
823
                    }
 
824
                }
 
825
                // And populate the rest of the cmap with gray values
 
826
                int grayIncr = 256 / (256 - i);
 
827
 
 
828
                // The gray ramp will be between 18 and 252
 
829
                int gray = grayIncr * 3;
 
830
                for(; i < 256; i++){
 
831
                    cmap[i] = (gray << 16) | (gray << 8) | gray;
 
832
                    gray += grayIncr;
 
833
                }
 
834
 
 
835
                return new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
 
836
            }
 
837
            case TYPE_USHORT_565_RGB: {
 
838
                return new DirectColorModel(16, DCM_565_RED_MASK, DCM_565_GRN_MASK, DCM_565_BLU_MASK);
 
839
            }
 
840
            case TYPE_USHORT_555_RGB: {
 
841
                return new DirectColorModel(15, DCM_555_RED_MASK, DCM_555_GRN_MASK, DCM_555_BLU_MASK);
 
842
            }
 
843
            default:
 
844
                throw new IllegalArgumentException("Unknown image type " + imageType);
 
845
        }
 
846
    }
 
847
 
 
848
    /**
 
849
     * Create a new WritableRaster based on the current imageType and ColorModel.
 
850
     */
 
851
    private WritableRaster createRaster(int width, int height){
 
852
        switch(imageType){
 
853
            case TYPE_INT_RGB:
 
854
            case TYPE_INT_ARGB:
 
855
            case TYPE_INT_ARGB_PRE:
 
856
            case TYPE_INT_BGR:
 
857
            case TYPE_BYTE_GRAY:
 
858
            case TYPE_USHORT_GRAY:
 
859
            case TYPE_USHORT_565_RGB:
 
860
            case TYPE_USHORT_555_RGB: {
 
861
                return colorModel.createCompatibleWritableRaster(width, height);
 
862
            }
 
863
            case TYPE_3BYTE_BGR: {
 
864
                int[] bOffs = {2, 1, 0};
 
865
                return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 3, 3, bOffs, null);
 
866
            }
 
867
            case TYPE_4BYTE_ABGR:
 
868
            case TYPE_4BYTE_ABGR_PRE: {
 
869
                int[] bOffs = {3, 2, 1, 0};
 
870
                return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, width * 4, 4, bOffs, null);
 
871
            }
 
872
            case TYPE_BYTE_BINARY: {
 
873
                return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null);
 
874
            }
 
875
            case TYPE_BYTE_INDEXED: {
 
876
                return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null);
 
877
            }
 
878
            default:
 
879
                throw new IllegalArgumentException("Unknown image type " + imageType);
 
880
        }
 
881
    }
 
882
 
 
883
    /**
 
884
     * Returns the image type.  If it is not one of the known types,
 
885
     * TYPE_CUSTOM is returned.
 
886
     * @return the image type of this <code>BufferedImage</code>.
 
887
     * @see #TYPE_INT_RGB
 
888
     * @see #TYPE_INT_ARGB
 
889
     * @see #TYPE_INT_ARGB_PRE
 
890
     * @see #TYPE_INT_BGR
 
891
     * @see #TYPE_3BYTE_BGR
 
892
     * @see #TYPE_4BYTE_ABGR
 
893
     * @see #TYPE_4BYTE_ABGR_PRE
 
894
     * @see #TYPE_BYTE_GRAY
 
895
     * @see #TYPE_BYTE_BINARY
 
896
     * @see #TYPE_BYTE_INDEXED
 
897
     * @see #TYPE_USHORT_GRAY
 
898
     * @see #TYPE_USHORT_565_RGB
 
899
     * @see #TYPE_USHORT_555_RGB
 
900
     * @see #TYPE_CUSTOM
 
901
     */
 
902
    public int getType() {
 
903
        return imageType;
 
904
    }
 
905
 
 
906
    /**
 
907
     * Returns the <code>ColorModel</code>.
 
908
     * @return the <code>ColorModel</code> of this
 
909
     *  <code>BufferedImage</code>.
 
910
     */
 
911
    public ColorModel getColorModel() {
 
912
        return colorModel;
 
913
    }
 
914
 
 
915
    /**
 
916
     * Returns the {@link WritableRaster}.
 
917
     * @return the <code>WriteableRaster</code> of this
 
918
     *  <code>BufferedImage</code>.
 
919
     */
 
920
    public WritableRaster getRaster() {
 
921
        bitmap2Raster();
 
922
        this.currentBuffer = BUFFER_RASTER;
 
923
        return raster;
 
924
    }
 
925
 
 
926
 
 
927
    /**
 
928
     * Returns a <code>WritableRaster</code> representing the alpha
 
929
     * channel for <code>BufferedImage</code> objects
 
930
     * with <code>ColorModel</code> objects that support a separate
 
931
     * spatial alpha channel, such as <code>ComponentColorModel</code> and
 
932
     * <code>DirectColorModel</code>.  Returns <code>null</code> if there
 
933
     * is no alpha channel associated with the <code>ColorModel</code> in
 
934
     * this image.  This method assumes that for all
 
935
     * <code>ColorModel</code> objects other than
 
936
     * <code>IndexColorModel</code>, if the <code>ColorModel</code>
 
937
     * supports alpha, there is a separate alpha channel
 
938
     * which is stored as the last band of image data.
 
939
     * If the image uses an <code>IndexColorModel</code> that
 
940
     * has alpha in the lookup table, this method returns
 
941
     * <code>null</code> since there is no spatially discrete alpha
 
942
     * channel.  This method creates a new
 
943
     * <code>WritableRaster</code>, but shares the data array.
 
944
     * @return a <code>WritableRaster</code> or <code>null</code> if this
 
945
     *          <code>BufferedImage</code> has no alpha channel associated
 
946
     *          with its <code>ColorModel</code>.
 
947
     */
 
948
    public WritableRaster getAlphaRaster() {
 
949
        bitmap2Raster();
 
950
        return colorModel.getAlphaRaster(raster);
 
951
    }
 
952
 
 
953
    /**
 
954
     * Returns an integer pixel in the default RGB color model
 
955
     * (TYPE_INT_ARGB) and default sRGB colorspace.  Color
 
956
     * conversion takes place if this default model does not match
 
957
     * the image <code>ColorModel</code>.  There are only 8-bits of
 
958
     * precision for each color component in the returned data when using
 
959
     * this method.
 
960
     *
 
961
     * <p>
 
962
     *
 
963
     * An <code>ArrayOutOfBoundsException</code> may be thrown
 
964
     * if the coordinates are not in bounds.
 
965
     * However, explicit bounds checking is not guaranteed.
 
966
     *
 
967
     * @param x the X coordinate of the pixel from which to get
 
968
     *          the pixel in the default RGB color model and sRGB
 
969
     *          color space
 
970
     * @param y the Y coordinate of the pixel from which to get
 
971
     *          the pixel in the default RGB color model and sRGB
 
972
     *          color space
 
973
     * @return an integer pixel in the default RGB color model and
 
974
     *          default sRGB colorspace.
 
975
     * @see #setRGB(int, int, int)
 
976
     * @see #setRGB(int, int, int, int, int[], int, int)
 
977
     */
 
978
    public int getRGB(int x, int y) {
 
979
        bitmap2Raster();
 
980
        return colorModel.getRGB(raster.getDataElements(x, y, null));
 
981
    }
 
982
 
 
983
    /**
 
984
     * Returns an array of integer pixels in the default RGB color model
 
985
     * (TYPE_INT_ARGB) and default sRGB color space,
 
986
     * from a portion of the image data.  Color conversion takes
 
987
     * place if the default model does not match the image
 
988
     * <code>ColorModel</code>.  There are only 8-bits of precision for
 
989
     * each color component in the returned data when
 
990
     * using this method.  With a specified coordinate (x,&nbsp;y) in the
 
991
     * image, the ARGB pixel can be accessed in this way:
 
992
     * </p>
 
993
     *
 
994
     * <pre>
 
995
     *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
 
996
     *
 
997
     * <p>
 
998
     *
 
999
     * An <code>ArrayOutOfBoundsException</code> may be thrown
 
1000
     * if the region is not in bounds.
 
1001
     * However, explicit bounds checking is not guaranteed.
 
1002
     *
 
1003
     * @param startX      the starting X coordinate
 
1004
     * @param startY      the starting Y coordinate
 
1005
     * @param w           width of region
 
1006
     * @param h           height of region
 
1007
     * @param rgbArray    if not <code>null</code>, the rgb pixels are
 
1008
     *          written here
 
1009
     * @param offset      offset into the <code>rgbArray</code>
 
1010
     * @param scansize    scanline stride for the <code>rgbArray</code>
 
1011
     * @return            array of RGB pixels.
 
1012
     * @see #setRGB(int, int, int)
 
1013
     * @see #setRGB(int, int, int, int, int[], int, int)
 
1014
     */
 
1015
    public int[] getRGB(int startX, int startY, int w, int h,
 
1016
                        int[] rgbArray, int offset, int scansize) {
 
1017
        int yoff  = offset;
 
1018
        int off;
 
1019
        Object data;
 
1020
        bitmap2Raster();
 
1021
        int nbands = raster.getNumBands();
 
1022
        int dataType = raster.getDataBuffer().getDataType();
 
1023
        switch (dataType) {
 
1024
        case DataBuffer.TYPE_BYTE:
 
1025
            data = new byte[nbands];
 
1026
            break;
 
1027
        case DataBuffer.TYPE_USHORT:
 
1028
            data = new short[nbands];
 
1029
            break;
 
1030
        case DataBuffer.TYPE_INT:
 
1031
            data = new int[nbands];
 
1032
            break;
 
1033
        case DataBuffer.TYPE_FLOAT:
 
1034
            data = new float[nbands];
 
1035
            break;
 
1036
        case DataBuffer.TYPE_DOUBLE:
 
1037
            data = new double[nbands];
 
1038
            break;
 
1039
        default:
 
1040
            throw new IllegalArgumentException("Unknown data buffer type: "+
 
1041
                                               dataType);
 
1042
        }
 
1043
 
 
1044
        if (rgbArray == null) {
 
1045
            rgbArray = new int[offset+h*scansize];
 
1046
        }
 
1047
 
 
1048
        for (int y = startY; y < startY+h; y++, yoff+=scansize) {
 
1049
            off = yoff;
 
1050
            for (int x = startX; x < startX+w; x++) {
 
1051
                rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x,
 
1052
                                                                        y,
 
1053
                                                                        data));
 
1054
            }
 
1055
        }
 
1056
 
 
1057
        return rgbArray;
 
1058
    }
 
1059
 
 
1060
 
 
1061
    /**
 
1062
     * Sets a pixel in this <code>BufferedImage</code> to the specified
 
1063
     * RGB value. The pixel is assumed to be in the default RGB color
 
1064
     * model, TYPE_INT_ARGB, and default sRGB color space.  For images
 
1065
     * with an <code>IndexColorModel</code>, the index with the nearest
 
1066
     * color is chosen.
 
1067
     *
 
1068
     * <p>
 
1069
     *
 
1070
     * An <code>ArrayOutOfBoundsException</code> may be thrown
 
1071
     * if the coordinates are not in bounds.
 
1072
     * However, explicit bounds checking is not guaranteed.
 
1073
     *
 
1074
     * @param x the X coordinate of the pixel to set
 
1075
     * @param y the Y coordinate of the pixel to set
 
1076
     * @param rgb the RGB value
 
1077
     * @see #getRGB(int, int)
 
1078
     * @see #getRGB(int, int, int, int, int[], int, int)
 
1079
     */
 
1080
    public synchronized void setRGB(int x, int y, int rgb) {
 
1081
        switch( currentBuffer ) {
 
1082
        case BUFFER_BITMAP:
 
1083
                synchronized (bitmap) {
 
1084
                        bitmap.SetPixel(x, y, Color.FromArgb(rgb));
 
1085
                        }
 
1086
                break;
 
1087
        case BUFFER_RASTER:
 
1088
                raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
 
1089
                break;
 
1090
        case BUFFER_BOTH:
 
1091
                raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
 
1092
                synchronized (bitmap) {
 
1093
                        bitmap.SetPixel(x, y, Color.FromArgb(rgb));
 
1094
                        }
 
1095
                break;
 
1096
        }
 
1097
    }
 
1098
 
 
1099
    /**
 
1100
     * Sets an array of integer pixels in the default RGB color model
 
1101
     * (TYPE_INT_ARGB) and default sRGB color space,
 
1102
     * into a portion of the image data.  Color conversion takes place
 
1103
     * if the default model does not match the image
 
1104
     * <code>ColorModel</code>.  There are only 8-bits of precision for
 
1105
     * each color component in the returned data when
 
1106
     * using this method.  With a specified coordinate (x,&nbsp;y) in the
 
1107
     * this image, the ARGB pixel can be accessed in this way:
 
1108
     * <pre>
 
1109
     *    pixel   = rgbArray[offset + (y-startY)*scansize + (x-startX)];
 
1110
     * </pre>
 
1111
     * WARNING: No dithering takes place.
 
1112
     *
 
1113
     * <p>
 
1114
     *
 
1115
     * An <code>ArrayOutOfBoundsException</code> may be thrown
 
1116
     * if the region is not in bounds.
 
1117
     * However, explicit bounds checking is not guaranteed.
 
1118
     *
 
1119
     * @param startX      the starting X coordinate
 
1120
     * @param startY      the starting Y coordinate
 
1121
     * @param w           width of the region
 
1122
     * @param h           height of the region
 
1123
     * @param rgbArray    the rgb pixels
 
1124
     * @param offset      offset into the <code>rgbArray</code>
 
1125
     * @param scansize    scanline stride for the <code>rgbArray</code>
 
1126
     * @see #getRGB(int, int)
 
1127
     * @see #getRGB(int, int, int, int, int[], int, int)
 
1128
     */
 
1129
    public void setRGB(int startX, int startY, int w, int h,
 
1130
                        int[] rgbArray, int offset, int scansize) {
 
1131
        int yoff  = offset;
 
1132
        int off;
 
1133
 
 
1134
        for (int y = startY; y < startY+h; y++, yoff+=scansize) {
 
1135
            off = yoff;
 
1136
            for (int x = startX; x < startX+w; x++) {
 
1137
                setRGB(x, y, rgbArray[off++]);
 
1138
            }
 
1139
        }
 
1140
    }
 
1141
 
 
1142
 
 
1143
    /**
 
1144
     * Returns the width of the <code>BufferedImage</code>.
 
1145
     * @return the width of this <code>BufferedImage</code>
 
1146
     */
 
1147
    public int getWidth() {
 
1148
        if(currentBuffer == BUFFER_BITMAP){
 
1149
            synchronized( bitmap ) {
 
1150
                return bitmap.get_Width();
 
1151
            }
 
1152
        }else{
 
1153
            return raster.getWidth();
 
1154
        }
 
1155
    }
 
1156
 
 
1157
    /**
 
1158
     * Returns the height of the <code>BufferedImage</code>.
 
1159
     * @return the height of this <code>BufferedImage</code>
 
1160
     */
 
1161
    public int getHeight() {
 
1162
        if(currentBuffer == BUFFER_BITMAP){
 
1163
            synchronized( bitmap ) {
 
1164
                return bitmap.get_Height();
 
1165
            }
 
1166
        }else{
 
1167
            return raster.getHeight();
 
1168
        }
 
1169
    }
 
1170
 
 
1171
    /**
 
1172
     * Returns the width of the <code>BufferedImage</code>.
 
1173
     * @param observer ignored
 
1174
     * @return the width of this <code>BufferedImage</code>
 
1175
     */
 
1176
    public int getWidth(ImageObserver observer) {
 
1177
        return getWidth();
 
1178
    }
 
1179
 
 
1180
    /**
 
1181
     * Returns the height of the <code>BufferedImage</code>.
 
1182
     * @param observer ignored
 
1183
     * @return the height of this <code>BufferedImage</code>
 
1184
     */
 
1185
    public int getHeight(ImageObserver observer) {
 
1186
        return getHeight();
 
1187
    }
 
1188
 
 
1189
    /**
 
1190
     * Returns the object that produces the pixels for the image.
 
1191
     * @return the {@link ImageProducer} that is used to produce the
 
1192
     * pixels for this image.
 
1193
     * @see ImageProducer
 
1194
     */
 
1195
    public ImageProducer getSource(){
 
1196
        if(currentBuffer != BUFFER_RASTER){
 
1197
            synchronized( bitmap ) {
 
1198
                int width = bitmap.get_Width();
 
1199
                int height = bitmap.get_Height();
 
1200
                int[] pix = new int[width * height];
 
1201
                for(int y = 0; y < height; y++){
 
1202
                    for(int x = 0; x < width; x++){
 
1203
                        pix[x + y * width] = bitmap.GetPixel(x, y).ToArgb();
 
1204
                    }
 
1205
                }
 
1206
                return new java.awt.image.MemoryImageSource(width, height, pix, 0, width);
 
1207
            }
 
1208
        }else{
 
1209
            if(osis == null){
 
1210
                if(properties == null){
 
1211
                    properties = new Hashtable();
 
1212
                }
 
1213
                osis = new OffScreenImageSource(this, properties);
 
1214
            }
 
1215
            return osis;
 
1216
        }
 
1217
    }
 
1218
 
 
1219
 
 
1220
    /**
 
1221
     * Returns a property of the image by name.  Individual property names
 
1222
     * are defined by the various image formats.  If a property is not
 
1223
     * defined for a particular image, this method returns the
 
1224
     * <code>UndefinedProperty</code> field.  If the properties
 
1225
     * for this image are not yet known, then this method returns
 
1226
     * <code>null</code> and the <code>ImageObserver</code> object is
 
1227
     * notified later.  The property name "comment" should be used to
 
1228
     * store an optional comment that can be presented to the user as a
 
1229
     * description of the image, its source, or its author.
 
1230
     * @param name the property name
 
1231
     * @param observer the <code>ImageObserver</code> that receives
 
1232
     *  notification regarding image information
 
1233
     * @return an {@link Object} that is the property referred to by the
 
1234
     *          specified <code>name</code> or <code>null</code> if the
 
1235
     *          properties of this image are not yet known.
 
1236
     * @throws <code>NullPointerException</code> if the property name is null.
 
1237
     * @see ImageObserver
 
1238
     * @see java.awt.Image#UndefinedProperty
 
1239
     */
 
1240
    public Object getProperty(String name, ImageObserver observer) {
 
1241
        return getProperty(name);
 
1242
    }
 
1243
 
 
1244
    /**
 
1245
     * Returns a property of the image by name.
 
1246
     * @param name the property name
 
1247
     * @return an <code>Object</code> that is the property referred to by
 
1248
     *          the specified <code>name</code>.
 
1249
     * @throws <code>NullPointerException</code> if the property name is null.
 
1250
     */
 
1251
    public Object getProperty(String name) {
 
1252
        if (name == null) {
 
1253
            throw new NullPointerException("null property name is not allowed");
 
1254
        }
 
1255
        if (properties == null) {
 
1256
            return java.awt.Image.UndefinedProperty;
 
1257
        }
 
1258
        Object o = properties.get(name);
 
1259
        if (o == null) {
 
1260
            o = java.awt.Image.UndefinedProperty;
 
1261
        }
 
1262
        return o;
 
1263
    }
 
1264
 
 
1265
    /**
 
1266
     * This method returns a {@link Graphics2D}, but is here
 
1267
     * for backwards compatibility.  {@link #createGraphics() createGraphics} is more
 
1268
     * convenient, since it is declared to return a
 
1269
     * <code>Graphics2D</code>.
 
1270
     * @return a <code>Graphics2D</code>, which can be used to draw into
 
1271
     *          this image.
 
1272
     */
 
1273
    public java.awt.Graphics getGraphics() {
 
1274
        return createGraphics();
 
1275
    }
 
1276
 
 
1277
    /**
 
1278
     * Creates a <code>Graphics2D</code>, which can be used to draw into
 
1279
     * this <code>BufferedImage</code>.
 
1280
     * @return a <code>Graphics2D</code>, used for drawing into this
 
1281
     *          image.
 
1282
     */
 
1283
    public Graphics2D createGraphics() {
 
1284
        ikvm.awt.IkvmToolkit toolkit = ikvm.awt.IkvmToolkit.DefaultToolkit.get();
 
1285
        raster2Bitmap();
 
1286
        this.currentBuffer = BUFFER_BITMAP;
 
1287
        return toolkit.createGraphics( bitmap );
 
1288
    }
 
1289
 
 
1290
    /**
 
1291
     * Returns a subimage defined by a specified rectangular region.
 
1292
     * The returned <code>BufferedImage</code> shares the same
 
1293
     * data array as the original image.
 
1294
     * @param x the X coordinate of the upper-left corner of the
 
1295
     *          specified rectangular region
 
1296
     * @param y the Y coordinate of the upper-left corner of the
 
1297
     *          specified rectangular region
 
1298
     * @param w the width of the specified rectangular region
 
1299
     * @param h the height of the specified rectangular region
 
1300
     * @return a <code>BufferedImage</code> that is the subimage of this
 
1301
     *          <code>BufferedImage</code>.
 
1302
     * @exception <code>RasterFormatException</code> if the specified
 
1303
     * area is not contained within this <code>BufferedImage</code>.
 
1304
     */
 
1305
    public BufferedImage getSubimage (int x, int y, int w, int h) {
 
1306
        bitmap2Raster();
 
1307
        return new BufferedImage (colorModel,
 
1308
                                  raster.createWritableChild(x, y, w, h,
 
1309
                                                             0, 0, null),
 
1310
                                  colorModel.isAlphaPremultiplied(),
 
1311
                                  properties);
 
1312
    }
 
1313
 
 
1314
    /**
 
1315
     * Returns whether or not the alpha has been premultiplied.  It
 
1316
     * returns <code>false</code> if there is no alpha.
 
1317
     * @return <code>true</code> if the alpha has been premultiplied;
 
1318
     *          <code>false</code> otherwise.
 
1319
     */
 
1320
    public boolean isAlphaPremultiplied() {
 
1321
        return colorModel.isAlphaPremultiplied();
 
1322
    }
 
1323
 
 
1324
    /**
 
1325
     * Forces the data to match the state specified in the
 
1326
     * <code>isAlphaPremultiplied</code> variable.  It may multiply or
 
1327
     * divide the color raster data by alpha, or do nothing if the data is
 
1328
     * in the correct state.
 
1329
     * @param isAlphaPremultiplied <code>true</code> if the alpha has been
 
1330
     *          premultiplied; <code>false</code> otherwise.
 
1331
     */
 
1332
    public void coerceData (boolean isAlphaPremultiplied) {
 
1333
        if (colorModel.hasAlpha() &&
 
1334
            colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
 
1335
            bitmap2Raster();
 
1336
            this.currentBuffer = BUFFER_RASTER;
 
1337
            // Make the color model do the conversion
 
1338
            colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
 
1339
        }
 
1340
    }
 
1341
 
 
1342
    /**
 
1343
     * Returns a <code>String</code> representation of this
 
1344
     * <code>BufferedImage</code> object and its values.
 
1345
     * @return a <code>String</code> representing this
 
1346
     *          <code>BufferedImage</code>.
 
1347
     */
 
1348
    public String toString() {
 
1349
        return new String("BufferedImage@"+Integer.toHexString(hashCode())
 
1350
                          +": type = "+imageType
 
1351
                          +" "+colorModel+" "+raster);
 
1352
    }
 
1353
 
 
1354
    /**
 
1355
     * Returns a {@link Vector} of {@link RenderedImage} objects that are
 
1356
     * the immediate sources, not the sources of these immediate sources,
 
1357
     * of image data for this <code>BufferedImage</code>.  This
 
1358
     * method returns <code>null</code> if the <code>BufferedImage</code>
 
1359
     * has no information about its immediate sources.  It returns an
 
1360
     * empty <code>Vector</code> if the <code>BufferedImage</code> has no
 
1361
     * immediate sources.
 
1362
     * @return a <code>Vector</code> containing immediate sources of
 
1363
     *          this <code>BufferedImage</code> object's image date, or
 
1364
     *          <code>null</code> if this <code>BufferedImage</code> has
 
1365
     *          no information about its immediate sources, or an empty
 
1366
     *          <code>Vector</code> if this <code>BufferedImage</code>
 
1367
     *          has no immediate sources.
 
1368
     */
 
1369
    public Vector<RenderedImage> getSources() {
 
1370
        return null;
 
1371
    }
 
1372
 
 
1373
    /**
 
1374
     * Returns an array of names recognized by
 
1375
     * {@link #getProperty(String) getProperty(String)}
 
1376
     * or <code>null</code>, if no property names are recognized.
 
1377
     * @return a <code>String</code> array containing all of the property
 
1378
     *          names that <code>getProperty(String)</code> recognizes;
 
1379
     *          or <code>null</code> if no property names are recognized.
 
1380
     */
 
1381
    public String[] getPropertyNames() {
 
1382
         return null;
 
1383
    }
 
1384
 
 
1385
    /**
 
1386
     * Returns the minimum x coordinate of this
 
1387
     * <code>BufferedImage</code>.  This is always zero.
 
1388
     * @return the minimum x coordinate of this
 
1389
     *          <code>BufferedImage</code>.
 
1390
     */
 
1391
    public int getMinX() {
 
1392
        bitmap2Raster();
 
1393
        return raster.getMinX();
 
1394
    }
 
1395
 
 
1396
    /**
 
1397
     * Returns the minimum y coordinate of this
 
1398
     * <code>BufferedImage</code>.  This is always zero.
 
1399
     * @return the minimum y coordinate of this
 
1400
     *          <code>BufferedImage</code>.
 
1401
     */
 
1402
    public int getMinY() {
 
1403
        bitmap2Raster();
 
1404
        return raster.getMinY();
 
1405
    }
 
1406
 
 
1407
    /**
 
1408
     * Returns the <code>SampleModel</code> associated with this
 
1409
     * <code>BufferedImage</code>.
 
1410
     * @return the <code>SampleModel</code> of this
 
1411
     *          <code>BufferedImage</code>.
 
1412
     */
 
1413
    public SampleModel getSampleModel() {
 
1414
        bitmap2Raster();
 
1415
        return raster.getSampleModel();
 
1416
    }
 
1417
 
 
1418
    /**
 
1419
     * Returns the number of tiles in the x direction.
 
1420
     * This is always one.
 
1421
     * @return the number of tiles in the x direction.
 
1422
     */
 
1423
    public int getNumXTiles() {
 
1424
        return 1;
 
1425
    }
 
1426
 
 
1427
    /**
 
1428
     * Returns the number of tiles in the y direction.
 
1429
     * This is always one.
 
1430
     * @return the number of tiles in the y direction.
 
1431
     */
 
1432
    public int getNumYTiles() {
 
1433
        return 1;
 
1434
    }
 
1435
 
 
1436
    /**
 
1437
     * Returns the minimum tile index in the x direction.
 
1438
     * This is always zero.
 
1439
     * @return the minimum tile index in the x direction.
 
1440
     */
 
1441
    public int getMinTileX() {
 
1442
        return 0;
 
1443
    }
 
1444
 
 
1445
    /**
 
1446
     * Returns the minimum tile index in the y direction.
 
1447
     * This is always zero.
 
1448
     * @return the mininum tile index in the y direction.
 
1449
     */
 
1450
    public int getMinTileY() {
 
1451
        return 0;
 
1452
    }
 
1453
 
 
1454
    /**
 
1455
     * Returns the tile width in pixels.
 
1456
     * @return the tile width in pixels.
 
1457
     */
 
1458
    public int getTileWidth() {
 
1459
       return getWidth();
 
1460
    }
 
1461
 
 
1462
    /**
 
1463
     * Returns the tile height in pixels.
 
1464
     * @return the tile height in pixels.
 
1465
     */
 
1466
    public int getTileHeight() {
 
1467
       return getHeight();
 
1468
    }
 
1469
 
 
1470
    /**
 
1471
     * Returns the x offset of the tile grid relative to the origin,
 
1472
     * For example, the x coordinate of the location of tile
 
1473
     * (0,&nbsp;0).  This is always zero.
 
1474
     * @return the x offset of the tile grid.
 
1475
     */
 
1476
    public int getTileGridXOffset() {
 
1477
        bitmap2Raster();
 
1478
        return raster.getSampleModelTranslateX();
 
1479
    }
 
1480
 
 
1481
    /**
 
1482
     * Returns the y offset of the tile grid relative to the origin,
 
1483
     * For example, the y coordinate of the location of tile
 
1484
     * (0,&nbsp;0).  This is always zero.
 
1485
     * @return the y offset of the tile grid.
 
1486
     */
 
1487
    public int getTileGridYOffset() {
 
1488
        bitmap2Raster();
 
1489
        return raster.getSampleModelTranslateY();
 
1490
    }
 
1491
 
 
1492
    /**
 
1493
     * Returns tile (<code>tileX</code>,&nbsp;<code>tileY</code>).  Note
 
1494
     * that <code>tileX</code> and <code>tileY</code> are indices
 
1495
     * into the tile array, not pixel locations.  The <code>Raster</code>
 
1496
     * that is returned is live, which means that it is updated if the
 
1497
     * image is changed.
 
1498
     * @param tileX the x index of the requested tile in the tile array
 
1499
     * @param tileY the y index of the requested tile in the tile array
 
1500
     * @return a <code>Raster</code> that is the tile defined by the
 
1501
     *          arguments <code>tileX</code> and <code>tileY</code>.
 
1502
     * @exception <code>ArrayIndexOutOfBoundsException</code> if both
 
1503
     *          <code>tileX</code> and <code>tileY</code> are not
 
1504
     *          equal to 0
 
1505
     */
 
1506
    public Raster getTile(int tileX, int tileY) {
 
1507
        if (tileX == 0 && tileY == 0) {
 
1508
            bitmap2Raster();
 
1509
            return raster;
 
1510
        }
 
1511
        throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
 
1512
             " one tile with index 0,0");
 
1513
    }
 
1514
 
 
1515
    /**
 
1516
     * Returns the image as one large tile.  The <code>Raster</code>
 
1517
     * returned is a copy of the image data is not updated if the
 
1518
     * image is changed.
 
1519
     * @return a <code>Raster</code> that is a copy of the image data.
 
1520
     * @see #setData(Raster)
 
1521
     */
 
1522
    public Raster getData() {
 
1523
        bitmap2Raster();
 
1524
 
 
1525
        // REMIND : this allocates a whole new tile if raster is a
 
1526
        // subtile.  (It only copies in the requested area)
 
1527
        // We should do something smarter.
 
1528
        int width = raster.getWidth();
 
1529
        int height = raster.getHeight();
 
1530
        int startX = raster.getMinX();
 
1531
        int startY = raster.getMinY();
 
1532
        WritableRaster wr =
 
1533
           Raster.createWritableRaster(raster.getSampleModel(),
 
1534
                         new Point(raster.getSampleModelTranslateX(),
 
1535
                                   raster.getSampleModelTranslateY()));
 
1536
 
 
1537
        Object tdata = null;
 
1538
 
 
1539
        for (int i = startY; i < startY+height; i++)  {
 
1540
            tdata = raster.getDataElements(startX,i,width,1,tdata);
 
1541
            wr.setDataElements(startX,i,width,1, tdata);
 
1542
        }
 
1543
        return wr;
 
1544
    }
 
1545
 
 
1546
    /**
 
1547
     * Computes and returns an arbitrary region of the
 
1548
     * <code>BufferedImage</code>.  The <code>Raster</code> returned is a
 
1549
     * copy of the image data and is not updated if the image is
 
1550
     * changed.
 
1551
     * @param rect the region of the <code>BufferedImage</code> to be
 
1552
     * returned.
 
1553
     * @return a <code>Raster</code> that is a copy of the image data of
 
1554
     *          the specified region of the <code>BufferedImage</code>
 
1555
     * @see #setData(Raster)
 
1556
     */
 
1557
    public Raster getData(Rectangle rect) {
 
1558
        bitmap2Raster();
 
1559
        SampleModel sm = raster.getSampleModel();
 
1560
        SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
 
1561
                                                         rect.height);
 
1562
        WritableRaster wr = Raster.createWritableRaster(nsm,
 
1563
                                                  rect.getLocation());
 
1564
        int width = rect.width;
 
1565
        int height = rect.height;
 
1566
        int startX = rect.x;
 
1567
        int startY = rect.y;
 
1568
 
 
1569
        Object tdata = null;
 
1570
 
 
1571
        for (int i = startY; i < startY+height; i++)  {
 
1572
            tdata = raster.getDataElements(startX,i,width,1,tdata);
 
1573
            wr.setDataElements(startX,i,width,1, tdata);
 
1574
        }
 
1575
        return wr;
 
1576
    }
 
1577
 
 
1578
    /**
 
1579
     * Computes an arbitrary rectangular region of the
 
1580
     * <code>BufferedImage</code> and copies it into a specified
 
1581
     * <code>WritableRaster</code>.  The region to be computed is
 
1582
     * determined from the bounds of the specified
 
1583
     * <code>WritableRaster</code>.  The specified
 
1584
     * <code>WritableRaster</code> must have a
 
1585
     * <code>SampleModel</code> that is compatible with this image.  If
 
1586
     * <code>outRaster</code> is <code>null</code>,
 
1587
     * an appropriate <code>WritableRaster</code> is created.
 
1588
     * @param outRaster a <code>WritableRaster</code> to hold the returned
 
1589
     *          part of the image, or <code>null</code>
 
1590
     * @return a reference to the supplied or created
 
1591
     *          <code>WritableRaster</code>.
 
1592
     */
 
1593
    public WritableRaster copyData(WritableRaster outRaster) {
 
1594
        bitmap2Raster();
 
1595
        if (outRaster == null) {
 
1596
            return (WritableRaster) getData();
 
1597
        }
 
1598
        int width = outRaster.getWidth();
 
1599
        int height = outRaster.getHeight();
 
1600
        int startX = outRaster.getMinX();
 
1601
        int startY = outRaster.getMinY();
 
1602
 
 
1603
        Object tdata = null;
 
1604
 
 
1605
        for (int i = startY; i < startY+height; i++)  {
 
1606
            tdata = raster.getDataElements(startX,i,width,1,tdata);
 
1607
            outRaster.setDataElements(startX,i,width,1, tdata);
 
1608
        }
 
1609
 
 
1610
        return outRaster;
 
1611
    }
 
1612
 
 
1613
  /**
 
1614
     * Sets a rectangular region of the image to the contents of the
 
1615
     * specified <code>Raster</code> <code>r</code>, which is
 
1616
     * assumed to be in the same coordinate space as the
 
1617
     * <code>BufferedImage</code>. The operation is clipped to the bounds
 
1618
     * of the <code>BufferedImage</code>.
 
1619
     * @param r the specified <code>Raster</code>
 
1620
     * @see #getData
 
1621
     * @see #getData(Rectangle)
 
1622
    */
 
1623
    public void setData(Raster r) {
 
1624
        bitmap2Raster();
 
1625
        this.currentBuffer = BUFFER_RASTER;
 
1626
        
 
1627
        int width = r.getWidth();
 
1628
        int height = r.getHeight();
 
1629
        int startX = r.getMinX();
 
1630
        int startY = r.getMinY();
 
1631
 
 
1632
        int[] tdata = null;
 
1633
 
 
1634
        // Clip to the current Raster
 
1635
        Rectangle rclip = new Rectangle(startX, startY, width, height);
 
1636
        Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height);
 
1637
        Rectangle intersect = rclip.intersection(bclip);
 
1638
        if (intersect.isEmpty()) {
 
1639
            return;
 
1640
        }
 
1641
        width = intersect.width;
 
1642
        height = intersect.height;
 
1643
        startX = intersect.x;
 
1644
        startY = intersect.y;
 
1645
 
 
1646
        // remind use get/setDataElements for speed if Rasters are
 
1647
        // compatible
 
1648
        for (int i = startY; i < startY+height; i++)  {
 
1649
            tdata = r.getPixels(startX,i,width,1,tdata);
 
1650
            raster.setPixels(startX,i,width,1, tdata);
 
1651
        }
 
1652
    }
 
1653
 
 
1654
 
 
1655
  /**
 
1656
   * Adds a tile observer.  If the observer is already present,
 
1657
   * it receives multiple notifications.
 
1658
   * @param to the specified {@link TileObserver}
 
1659
   */
 
1660
    public void addTileObserver (TileObserver to) {
 
1661
    }
 
1662
 
 
1663
  /**
 
1664
   * Removes a tile observer.  If the observer was not registered,
 
1665
   * nothing happens.  If the observer was registered for multiple
 
1666
   * notifications, it is now registered for one fewer notification.
 
1667
   * @param to the specified <code>TileObserver</code>.
 
1668
   */
 
1669
    public void removeTileObserver (TileObserver to) {
 
1670
    }
 
1671
 
 
1672
    /**
 
1673
     * Returns whether or not a tile is currently checked out for writing.
 
1674
     * @param tileX the x index of the tile.
 
1675
     * @param tileY the y index of the tile.
 
1676
     * @return <code>true</code> if the tile specified by the specified
 
1677
     *          indices is checked out for writing; <code>false</code>
 
1678
     *          otherwise.
 
1679
     * @exception <code>ArrayIndexOutOfBoundsException</code> if both
 
1680
     *          <code>tileX</code> and <code>tileY</code> are not equal
 
1681
     *          to 0
 
1682
     */
 
1683
    public boolean isTileWritable (int tileX, int tileY) {
 
1684
        if (tileX == 0 && tileY == 0) {
 
1685
            return true;
 
1686
        }
 
1687
        throw new IllegalArgumentException("Only 1 tile in image");
 
1688
    }
 
1689
 
 
1690
    /**
 
1691
     * Returns an array of {@link Point} objects indicating which tiles
 
1692
     * are checked out for writing.  Returns <code>null</code> if none are
 
1693
     * checked out.
 
1694
     * @return a <code>Point</code> array that indicates the tiles that
 
1695
     *          are checked out for writing, or <code>null</code> if no
 
1696
     *          tiles are checked out for writing.
 
1697
     */
 
1698
    public Point[] getWritableTileIndices() {
 
1699
        Point[] p = new Point[1];
 
1700
        p[0] = new Point(0, 0);
 
1701
 
 
1702
        return p;
 
1703
    }
 
1704
 
 
1705
    /**
 
1706
     * Returns whether or not any tile is checked out for writing.
 
1707
     * Semantically equivalent to
 
1708
     * <pre>
 
1709
     * (getWritableTileIndices() != null).
 
1710
     * </pre>
 
1711
     * @return <code>true</code> if any tile is checked out for writing;
 
1712
     *          <code>false</code> otherwise.
 
1713
     */
 
1714
    public boolean hasTileWriters () {
 
1715
        return true;
 
1716
    }
 
1717
 
 
1718
  /**
 
1719
   * Checks out a tile for writing.  All registered
 
1720
   * <code>TileObservers</code> are notified when a tile goes from having
 
1721
   * no writers to having one writer.
 
1722
   * @param tileX the x index of the tile
 
1723
   * @param tileY the y index of the tile
 
1724
   * @return a <code>WritableRaster</code> that is the tile, indicated by
 
1725
   *            the specified indices, to be checked out for writing.
 
1726
   */
 
1727
    public WritableRaster getWritableTile (int tileX, int tileY) {
 
1728
        bitmap2Raster();
 
1729
        this.currentBuffer = BUFFER_RASTER;
 
1730
        return raster;
 
1731
    }
 
1732
 
 
1733
  /**
 
1734
   * Relinquishes permission to write to a tile.  If the caller
 
1735
   * continues to write to the tile, the results are undefined.
 
1736
   * Calls to this method should only appear in matching pairs
 
1737
   * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}.  Any other leads
 
1738
   * to undefined results.  All registered <code>TileObservers</code>
 
1739
   * are notified when a tile goes from having one writer to having no
 
1740
   * writers.
 
1741
   * @param tileX the x index of the tile
 
1742
   * @param tileY the y index of the tile
 
1743
   */
 
1744
    public void releaseWritableTile (int tileX, int tileY) {
 
1745
    }
 
1746
 
 
1747
    /**
 
1748
     * Returns the transparency.  Returns either OPAQUE, BITMASK,
 
1749
     * or TRANSLUCENT.
 
1750
     * @return the transparency of this <code>BufferedImage</code>.
 
1751
     * @see Transparency#OPAQUE
 
1752
     * @see Transparency#BITMASK
 
1753
     * @see Transparency#TRANSLUCENT
 
1754
     * @since 1.5
 
1755
     */
 
1756
    public int getTransparency() {
 
1757
        return colorModel.getTransparency();
 
1758
    }
 
1759
    
 
1760
    public void flush(){
 
1761
    }
 
1762
}