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