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