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