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.
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.
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).
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.
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
26
package java.awt.image;
28
import cli.System.Drawing.Color;
29
import cli.System.Drawing.Imaging.*;
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;
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;
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, 0). Any <code>Raster</code> used to construct a
61
* <code>BufferedImage</code> must therefore have minX=0 and minY=0.
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>.
73
public class BufferedImage extends java.awt.Image
74
implements WritableRenderedImage, Transparency
76
int imageType = TYPE_CUSTOM;
77
ColorModel colorModel;
78
WritableRaster raster;
79
OffScreenImageSource osis;
82
boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in
86
* Image Type Constants
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()
94
public static final int TYPE_CUSTOM = 0;
97
* Represents an image with 8-bit RGB color components packed into
98
* integer pixels. The image has a {@link DirectColorModel} without
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.
107
public static final int TYPE_INT_RGB = 1;
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.
118
public static final int TYPE_INT_ARGB = 2;
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.
126
public static final int TYPE_INT_ARGB_PRE = 3;
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.
140
public static final int TYPE_INT_BGR = 4;
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.
154
public static final int TYPE_3BYTE_BGR = 5;
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.
165
public static final int TYPE_4BYTE_ABGR = 6;
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.
175
public static final int TYPE_4BYTE_ABGR_PRE = 7;
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.
188
public static final int TYPE_USHORT_565_RGB = 8;
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.
201
public static final int TYPE_USHORT_555_RGB = 9;
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.
214
public static final int TYPE_BYTE_GRAY = 10;
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.
227
public static final int TYPE_USHORT_GRAY = 11;
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, 0, 0} and
238
* {255, 255, 255}.
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.
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>.
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.
256
public static final int TYPE_BYTE_BINARY = 12;
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.
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.
275
public static final int TYPE_BYTE_INDEXED = 13;
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;
291
/** reference to the :NET equivalent */
292
private cli.System.Drawing.Bitmap bitmap;
294
/** Which buffer include the current data, raster or bitmap */
295
private int currentBuffer;
297
private static final int BUFFER_BITMAP = 1;
298
private static final int BUFFER_RASTER = 2;
299
private static final int BUFFER_BOTH = 3;
302
* Create a BufferedImage directly from the .NET Bitmap class
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;
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
321
* @see #TYPE_INT_ARGB
322
* @see #TYPE_INT_ARGB_PRE
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
334
public BufferedImage(int width,
337
this.imageType = imageType;
338
this.colorModel = createColorModel();
339
this.bitmap = createBitmap(width, height);
340
this.currentBuffer = BUFFER_BITMAP;
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
349
private cli.System.Drawing.Bitmap createBitmap(int width, int height){
353
if(width <= 0 || height <= 0){
354
throw new IllegalArgumentException("Width (" + width + ") and height (" + height + ") cannot be <= 0");
356
return new cli.System.Drawing.Bitmap(width, height, PixelFormat.wrap(PixelFormat.Format32bppArgb));
360
* Constructs a <code>BufferedImage</code> of one of the predefined
362
* TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
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.
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
382
public BufferedImage (int width,
385
IndexColorModel cm) {
386
if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
387
throw new IllegalArgumentException("This image types do not have "+
388
"premultiplied alpha.");
392
case TYPE_BYTE_BINARY:
393
int bits; // Will be set below
394
int mapSize = cm.getMapSize();
397
} else if (mapSize <= 4) {
399
} else if (mapSize <= 16) {
402
throw new IllegalArgumentException
403
("Color map for TYPE_BYTE_BINARY " +
404
"must have no more than 16 entries");
406
raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
407
width, height, 1, bits, null);
410
case TYPE_BYTE_INDEXED:
411
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
412
width, height, 1, null);
415
throw new IllegalArgumentException("Invalid image type (" +
416
imageType+"). Image type must"+
417
" be either TYPE_BYTE_BINARY or "+
418
" TYPE_BYTE_INDEXED");
421
if (!cm.isCompatibleRaster(raster)) {
422
throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
426
this.imageType = imageType;
427
this.currentBuffer = BUFFER_RASTER;
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>
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
454
* @exception <code>IllegalArgumentException</code> if
455
* <code>raster</code> is incompatible with <code>cm</code>
458
* @see WritableRaster
464
* FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
465
* SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
468
public BufferedImage (ColorModel cm,
469
WritableRaster raster,
470
boolean isRasterPremultiplied,
471
Hashtable<?,?> properties) {
473
if (!cm.isCompatibleRaster(raster)) {
475
IllegalArgumentException("Raster "+raster+
476
" is incompatible with ColorModel "+
480
if ((raster.minX != 0) || (raster.minY != 0)) {
482
IllegalArgumentException("Raster "+raster+
483
" has minX or minY not equal to zero: "
484
+ raster.minX + " " + raster.minY);
488
this.raster = raster;
489
this.currentBuffer = BUFFER_RASTER;
490
this.properties = properties;
491
int numBands = raster.getNumBands();
492
boolean isAlphaPre = cm.isAlphaPremultiplied();
495
// Force the raster data alpha state to match the premultiplied
496
// state in the color model
497
coerceData(isRasterPremultiplied);
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;
521
imageType = TYPE_CUSTOM;
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
532
int pixSize = cm.getPixelSize();
533
if (iraster.getPixelStride() == 1 &&
534
cm instanceof DirectColorModel &&
535
(pixSize == 32 || pixSize == 24))
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)
545
if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
546
imageType = (isAlphaPre
552
if (!dcm.hasAlpha()) {
553
imageType = TYPE_INT_RGB;
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;
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))
568
IndexColorModel icm = (IndexColorModel) cm;
569
int pixSize = icm.getPixelSize();
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;
580
} // else if (cm instanceof IndexColorModel) && (numBands == 1))
581
else if ((raster instanceof ShortComponentRaster)
582
&& (cm instanceof DirectColorModel)
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;
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;
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))
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 "+
613
ccm.getNumComponents()+
614
") does not match # in "+
615
" Raster ("+numBands+")");
617
int[] nBits = ccm.getComponentSize();
618
boolean is8bit = true;
619
for (int i=0; i < numBands; i++) {
626
offs[0] == numBands-1 &&
627
offs[1] == numBands-2 &&
628
offs[2] == numBands-3)
631
imageType = TYPE_3BYTE_BGR;
633
else if (offs[3] == 0) {
634
imageType = (isAlphaPre
635
? TYPE_4BYTE_ABGR_PRE
639
} // else if ((raster instanceof ByteComponentRaster) &&
643
* Get the .NET Bitmap object.
645
@cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
646
public cli.System.Drawing.Bitmap getBitmap(){
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.
656
private void raster2Bitmap(){
657
if(currentBuffer != BUFFER_RASTER){
658
return; // BUFFER_BOTH and BUFFER_BITMAP
660
int width = getWidth();
661
int height = getHeight();
663
// First map the pixel from Java type to .NET type
666
copyToBitmap(width, height, ((DataBufferInt)raster.getDataBuffer()).getData());
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));
678
this.currentBuffer = BUFFER_BOTH;
682
@cli.System.Security.SecuritySafeCriticalAttribute.Annotation
683
private void copyToBitmap(int width, int height, int[] pixelData)
685
long size = (long)width * (long)height;
686
if (size > pixelData.length)
688
throw new IllegalArgumentException();
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);
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.
705
private void bitmap2Raster(){
706
if(currentBuffer != BUFFER_BITMAP){
707
return; // BUFFER_BOTH and BUFFER_RASTER
709
synchronized( bitmap ) {
710
int width = bitmap.get_Width();
711
int height = bitmap.get_Height();
712
if(colorModel == null){
713
colorModel = createColorModel();
716
raster = createRaster(width, height);
721
copyFromBitmap(bitmap, ((DataBufferInt)raster.getDataBuffer()).getData());
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));
731
this.currentBuffer = BUFFER_BOTH;
735
@cli.System.Security.SecuritySafeCriticalAttribute.Annotation
736
private static void copyFromBitmap(cli.System.Drawing.Bitmap bitmap, int[] pixelData)
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)
743
throw new IllegalArgumentException();
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);
753
* Create a new ColorModel based on the current imageType.
755
private ColorModel createColorModel(){
758
return new DirectColorModel(24, 0x00ff0000, // Red
764
case TYPE_INT_ARGB: {
765
return ColorModel.getRGBdefault();
767
case TYPE_INT_ARGB_PRE: {
768
return new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000,// Red
772
true, // Alpha Premultiplied
773
DataBuffer.TYPE_INT);
776
return new DirectColorModel(24, 0x000000ff, // Red
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);
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);
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);
798
case TYPE_BYTE_GRAY: {
799
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
801
return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
803
case TYPE_USHORT_GRAY: {
804
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
806
return new ComponentColorModel(cs, nBits, false, true, Transparency.OPAQUE,
807
DataBuffer.TYPE_USHORT);
809
case TYPE_BYTE_BINARY: {
810
byte[] arr = {(byte)0, (byte)0xff};
812
return new IndexColorModel(1, 2, arr, arr, arr);
814
case TYPE_BYTE_INDEXED: {
815
// Create a 6x6x6 color cube
816
int[] cmap = new int[256];
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;
825
// And populate the rest of the cmap with gray values
826
int grayIncr = 256 / (256 - i);
828
// The gray ramp will be between 18 and 252
829
int gray = grayIncr * 3;
831
cmap[i] = (gray << 16) | (gray << 8) | gray;
835
return new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
837
case TYPE_USHORT_565_RGB: {
838
return new DirectColorModel(16, DCM_565_RED_MASK, DCM_565_GRN_MASK, DCM_565_BLU_MASK);
840
case TYPE_USHORT_555_RGB: {
841
return new DirectColorModel(15, DCM_555_RED_MASK, DCM_555_GRN_MASK, DCM_555_BLU_MASK);
844
throw new IllegalArgumentException("Unknown image type " + imageType);
849
* Create a new WritableRaster based on the current imageType and ColorModel.
851
private WritableRaster createRaster(int width, int height){
855
case TYPE_INT_ARGB_PRE:
858
case TYPE_USHORT_GRAY:
859
case TYPE_USHORT_565_RGB:
860
case TYPE_USHORT_555_RGB: {
861
return colorModel.createCompatibleWritableRaster(width, height);
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);
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);
872
case TYPE_BYTE_BINARY: {
873
return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null);
875
case TYPE_BYTE_INDEXED: {
876
return Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null);
879
throw new IllegalArgumentException("Unknown image type " + imageType);
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>.
888
* @see #TYPE_INT_ARGB
889
* @see #TYPE_INT_ARGB_PRE
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
902
public int getType() {
907
* Returns the <code>ColorModel</code>.
908
* @return the <code>ColorModel</code> of this
909
* <code>BufferedImage</code>.
911
public ColorModel getColorModel() {
916
* Returns the {@link WritableRaster}.
917
* @return the <code>WriteableRaster</code> of this
918
* <code>BufferedImage</code>.
920
public WritableRaster getRaster() {
922
this.currentBuffer = BUFFER_RASTER;
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>.
948
public WritableRaster getAlphaRaster() {
950
return colorModel.getAlphaRaster(raster);
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
963
* An <code>ArrayOutOfBoundsException</code> may be thrown
964
* if the coordinates are not in bounds.
965
* However, explicit bounds checking is not guaranteed.
967
* @param x the X coordinate of the pixel from which to get
968
* the pixel in the default RGB color model and sRGB
970
* @param y the Y coordinate of the pixel from which to get
971
* the pixel in the default RGB color model and sRGB
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)
978
public int getRGB(int x, int y) {
980
return colorModel.getRGB(raster.getDataElements(x, y, null));
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, y) in the
991
* image, the ARGB pixel can be accessed in this way:
995
* pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
999
* An <code>ArrayOutOfBoundsException</code> may be thrown
1000
* if the region is not in bounds.
1001
* However, explicit bounds checking is not guaranteed.
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
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)
1015
public int[] getRGB(int startX, int startY, int w, int h,
1016
int[] rgbArray, int offset, int scansize) {
1021
int nbands = raster.getNumBands();
1022
int dataType = raster.getDataBuffer().getDataType();
1024
case DataBuffer.TYPE_BYTE:
1025
data = new byte[nbands];
1027
case DataBuffer.TYPE_USHORT:
1028
data = new short[nbands];
1030
case DataBuffer.TYPE_INT:
1031
data = new int[nbands];
1033
case DataBuffer.TYPE_FLOAT:
1034
data = new float[nbands];
1036
case DataBuffer.TYPE_DOUBLE:
1037
data = new double[nbands];
1040
throw new IllegalArgumentException("Unknown data buffer type: "+
1044
if (rgbArray == null) {
1045
rgbArray = new int[offset+h*scansize];
1048
for (int y = startY; y < startY+h; y++, yoff+=scansize) {
1050
for (int x = startX; x < startX+w; x++) {
1051
rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x,
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
1070
* An <code>ArrayOutOfBoundsException</code> may be thrown
1071
* if the coordinates are not in bounds.
1072
* However, explicit bounds checking is not guaranteed.
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)
1080
public synchronized void setRGB(int x, int y, int rgb) {
1081
switch( currentBuffer ) {
1083
synchronized (bitmap) {
1084
bitmap.SetPixel(x, y, Color.FromArgb(rgb));
1088
raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
1091
raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
1092
synchronized (bitmap) {
1093
bitmap.SetPixel(x, y, Color.FromArgb(rgb));
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, y) in the
1107
* this image, the ARGB pixel can be accessed in this way:
1109
* pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
1111
* WARNING: No dithering takes place.
1115
* An <code>ArrayOutOfBoundsException</code> may be thrown
1116
* if the region is not in bounds.
1117
* However, explicit bounds checking is not guaranteed.
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)
1129
public void setRGB(int startX, int startY, int w, int h,
1130
int[] rgbArray, int offset, int scansize) {
1134
for (int y = startY; y < startY+h; y++, yoff+=scansize) {
1136
for (int x = startX; x < startX+w; x++) {
1137
setRGB(x, y, rgbArray[off++]);
1144
* Returns the width of the <code>BufferedImage</code>.
1145
* @return the width of this <code>BufferedImage</code>
1147
public int getWidth() {
1148
if(currentBuffer == BUFFER_BITMAP){
1149
synchronized( bitmap ) {
1150
return bitmap.get_Width();
1153
return raster.getWidth();
1158
* Returns the height of the <code>BufferedImage</code>.
1159
* @return the height of this <code>BufferedImage</code>
1161
public int getHeight() {
1162
if(currentBuffer == BUFFER_BITMAP){
1163
synchronized( bitmap ) {
1164
return bitmap.get_Height();
1167
return raster.getHeight();
1172
* Returns the width of the <code>BufferedImage</code>.
1173
* @param observer ignored
1174
* @return the width of this <code>BufferedImage</code>
1176
public int getWidth(ImageObserver observer) {
1181
* Returns the height of the <code>BufferedImage</code>.
1182
* @param observer ignored
1183
* @return the height of this <code>BufferedImage</code>
1185
public int getHeight(ImageObserver observer) {
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
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();
1206
return new java.awt.image.MemoryImageSource(width, height, pix, 0, width);
1210
if(properties == null){
1211
properties = new Hashtable();
1213
osis = new OffScreenImageSource(this, properties);
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
1240
public Object getProperty(String name, ImageObserver observer) {
1241
return getProperty(name);
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.
1251
public Object getProperty(String name) {
1253
throw new NullPointerException("null property name is not allowed");
1255
if (properties == null) {
1256
return java.awt.Image.UndefinedProperty;
1258
Object o = properties.get(name);
1260
o = java.awt.Image.UndefinedProperty;
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
1273
public java.awt.Graphics getGraphics() {
1274
return createGraphics();
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
1283
public Graphics2D createGraphics() {
1284
ikvm.awt.IkvmToolkit toolkit = ikvm.awt.IkvmToolkit.DefaultToolkit.get();
1286
this.currentBuffer = BUFFER_BITMAP;
1287
return toolkit.createGraphics( bitmap );
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>.
1305
public BufferedImage getSubimage (int x, int y, int w, int h) {
1307
return new BufferedImage (colorModel,
1308
raster.createWritableChild(x, y, w, h,
1310
colorModel.isAlphaPremultiplied(),
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.
1320
public boolean isAlphaPremultiplied() {
1321
return colorModel.isAlphaPremultiplied();
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.
1332
public void coerceData (boolean isAlphaPremultiplied) {
1333
if (colorModel.hasAlpha() &&
1334
colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
1336
this.currentBuffer = BUFFER_RASTER;
1337
// Make the color model do the conversion
1338
colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
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>.
1348
public String toString() {
1349
return new String("BufferedImage@"+Integer.toHexString(hashCode())
1350
+": type = "+imageType
1351
+" "+colorModel+" "+raster);
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.
1369
public Vector<RenderedImage> getSources() {
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.
1381
public String[] getPropertyNames() {
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>.
1391
public int getMinX() {
1393
return raster.getMinX();
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>.
1402
public int getMinY() {
1404
return raster.getMinY();
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>.
1413
public SampleModel getSampleModel() {
1415
return raster.getSampleModel();
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.
1423
public int getNumXTiles() {
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.
1432
public int getNumYTiles() {
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.
1441
public int getMinTileX() {
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.
1450
public int getMinTileY() {
1455
* Returns the tile width in pixels.
1456
* @return the tile width in pixels.
1458
public int getTileWidth() {
1463
* Returns the tile height in pixels.
1464
* @return the tile height in pixels.
1466
public int getTileHeight() {
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, 0). This is always zero.
1474
* @return the x offset of the tile grid.
1476
public int getTileGridXOffset() {
1478
return raster.getSampleModelTranslateX();
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, 0). This is always zero.
1485
* @return the y offset of the tile grid.
1487
public int getTileGridYOffset() {
1489
return raster.getSampleModelTranslateY();
1493
* Returns tile (<code>tileX</code>, <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
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
1506
public Raster getTile(int tileX, int tileY) {
1507
if (tileX == 0 && tileY == 0) {
1511
throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
1512
" one tile with index 0,0");
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
1519
* @return a <code>Raster</code> that is a copy of the image data.
1520
* @see #setData(Raster)
1522
public Raster getData() {
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();
1533
Raster.createWritableRaster(raster.getSampleModel(),
1534
new Point(raster.getSampleModelTranslateX(),
1535
raster.getSampleModelTranslateY()));
1537
Object tdata = null;
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);
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
1551
* @param rect the region of the <code>BufferedImage</code> to be
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)
1557
public Raster getData(Rectangle rect) {
1559
SampleModel sm = raster.getSampleModel();
1560
SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
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;
1569
Object tdata = null;
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);
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>.
1593
public WritableRaster copyData(WritableRaster outRaster) {
1595
if (outRaster == null) {
1596
return (WritableRaster) getData();
1598
int width = outRaster.getWidth();
1599
int height = outRaster.getHeight();
1600
int startX = outRaster.getMinX();
1601
int startY = outRaster.getMinY();
1603
Object tdata = null;
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);
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>
1621
* @see #getData(Rectangle)
1623
public void setData(Raster r) {
1625
this.currentBuffer = BUFFER_RASTER;
1627
int width = r.getWidth();
1628
int height = r.getHeight();
1629
int startX = r.getMinX();
1630
int startY = r.getMinY();
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()) {
1641
width = intersect.width;
1642
height = intersect.height;
1643
startX = intersect.x;
1644
startY = intersect.y;
1646
// remind use get/setDataElements for speed if Rasters are
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);
1656
* Adds a tile observer. If the observer is already present,
1657
* it receives multiple notifications.
1658
* @param to the specified {@link TileObserver}
1660
public void addTileObserver (TileObserver to) {
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>.
1669
public void removeTileObserver (TileObserver to) {
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>
1679
* @exception <code>ArrayIndexOutOfBoundsException</code> if both
1680
* <code>tileX</code> and <code>tileY</code> are not equal
1683
public boolean isTileWritable (int tileX, int tileY) {
1684
if (tileX == 0 && tileY == 0) {
1687
throw new IllegalArgumentException("Only 1 tile in image");
1691
* Returns an array of {@link Point} objects indicating which tiles
1692
* are checked out for writing. Returns <code>null</code> if none are
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.
1698
public Point[] getWritableTileIndices() {
1699
Point[] p = new Point[1];
1700
p[0] = new Point(0, 0);
1706
* Returns whether or not any tile is checked out for writing.
1707
* Semantically equivalent to
1709
* (getWritableTileIndices() != null).
1711
* @return <code>true</code> if any tile is checked out for writing;
1712
* <code>false</code> otherwise.
1714
public boolean hasTileWriters () {
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.
1727
public WritableRaster getWritableTile (int tileX, int tileY) {
1729
this.currentBuffer = BUFFER_RASTER;
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
1741
* @param tileX the x index of the tile
1742
* @param tileY the y index of the tile
1744
public void releaseWritableTile (int tileX, int tileY) {
1748
* Returns the transparency. Returns either OPAQUE, BITMASK,
1750
* @return the transparency of this <code>BufferedImage</code>.
1751
* @see Transparency#OPAQUE
1752
* @see Transparency#BITMASK
1753
* @see Transparency#TRANSLUCENT
1756
public int getTransparency() {
1757
return colorModel.getTransparency();
1760
public void flush(){