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