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