1. /*
  2. * @(#)IndexColorModel.java 1.75 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 sun.java2d.loops.ImageData;
  11. /**
  12. * A ColorModel class that works with pixel values consisting of a
  13. * single sample which is an index into a fixed colormap in the default
  14. * sRGB ColorSpace. The colormap specifies red, green, blue, and
  15. * optional alpha components corresponding to each index. All components
  16. * are represented in the colormap as 8-bit unsigned integral values. If
  17. * alpha is not present, an opaque alpha component (alpha = 1.0) will be
  18. * assumed for each entry. An optional transparent
  19. * pixel value can be supplied which indicates a completely transparent
  20. * pixel, regardless of any alpha component recorded for that pixel value.
  21. * Note that alpha values in IndexColorModels are never premultiplied.
  22. * This color model is similar to an X11 PseudoColor visual.
  23. * <p>
  24. * The index represented by a pixel value is stored in the least
  25. * significant n bits of the pixel representations passed to the
  26. * methods of this class, where n is the pixel size specified to the
  27. * constructor for a particular IndexColorModel object. Higher order
  28. * bits in pixel representations are assumed to be zero.
  29. * For those methods which use a primitive array pixel representation of
  30. * type transferType, the array length is always one. The transfer types
  31. * supported are DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, and
  32. * DataBuffer.TYPE_INT. A single int pixel representation is valid for all
  33. * objects of this class, since it is always possible to represent pixel
  34. * values used with this class in a single int. Therefore, methods which
  35. * use this representation will not throw an IllegalArgumentException due
  36. * to an invalid pixel value.
  37. * <p>
  38. * Many of the methods in this class are final. The reason for
  39. * this is that the underlying native graphics code makes assumptions
  40. * about the layout and operation of this class and those assumptions
  41. * are reflected in the implementations of the methods here that are
  42. * marked final. You can subclass this class for other reaons, but
  43. * you cannot override or modify the behaviour of those methods.
  44. *
  45. * @see ColorModel
  46. * @see ColorSpace
  47. * @see DataBuffer
  48. *
  49. * @version 10 Feb 1997
  50. */
  51. public class IndexColorModel extends ColorModel {
  52. private int rgb[] = null;
  53. private int map_size = 0;
  54. private int transparent_index = -1;
  55. private boolean allgrayopaque;
  56. static private native void initIDs();
  57. static {
  58. ColorModel.loadLibraries();
  59. initIDs();
  60. }
  61. /**
  62. * Constructs an IndexColorModel from the given arrays of red,
  63. * green, and blue components. Pixels described by this color
  64. * model will all have alpha components of 255 unnormalized (1.0
  65. * normalized), i.e. fully opaque.
  66. * All of the arrays specifying the color components must have
  67. * at least the specified number of entries. The ColorSpace will
  68. * be the default sRGB space. The transparency value will be
  69. * Transparency.OPAQUE. The transfer type will be the smallest
  70. * of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
  71. * DataBuffer.TYPE_INT that can hold a single pixel.
  72. * @param bits The number of bits each pixel occupies.
  73. * @param size The size of the color component arrays.
  74. * @param r The array of red color components.
  75. * @param g The array of green color components.
  76. * @param b The array of blue color components.
  77. */
  78. public IndexColorModel(int bits, int size,
  79. byte r[], byte g[], byte b[]) {
  80. super(bits, IndexColorModel.setBits(bits, false),
  81. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  82. false, false, Transparency.OPAQUE,
  83. ColorModel.getDefaultTransferType(bits));
  84. if (bits < 1 || bits > 32) {
  85. throw new IllegalArgumentException("Number of bits must be between"
  86. +" 1 and 32.");
  87. }
  88. setRGBs(size, r, g, b, null);
  89. checkAllGrayOpaque();
  90. }
  91. /**
  92. * Constructs an IndexColorModel from the given arrays of red,
  93. * green, and blue components. Pixels described by this color
  94. * model will all have alpha components of 255 unnormalized (1.0
  95. * normalized), i.e. fully opaque, except for the indicated
  96. * transparent pixel. All of the arrays
  97. * specifying the color components must have at least the specified
  98. * number of entries. The ColorSpace will be the default sRGB space.
  99. * The transparency value will be Transparency.BITMASK.
  100. * The transfer type will be the smallest of DataBuffer.TYPE_BYTE,
  101. * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT that can hold a
  102. * single pixel.
  103. * @param bits The number of bits each pixel occupies.
  104. * @param size The size of the color component arrays.
  105. * @param r The array of red color components.
  106. * @param g The array of green color components.
  107. * @param b The array of blue color components.
  108. * @param trans The index of the transparent pixel.
  109. */
  110. public IndexColorModel(int bits, int size,
  111. byte r[], byte g[], byte b[], int trans) {
  112. super(bits, IndexColorModel.setBits(bits, (trans>=0)),
  113. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  114. (trans > -1), false, Transparency.BITMASK,
  115. ColorModel.getDefaultTransferType(bits));
  116. if (bits < 1 || bits > 32) {
  117. throw new IllegalArgumentException("Number of bits must be between"
  118. +" 1 and 32.");
  119. }
  120. setRGBs(size, r, g, b, null);
  121. if (trans > -1) {
  122. transparency = Transparency.BITMASK;
  123. setTransparentPixel(trans);
  124. }
  125. checkAllGrayOpaque();
  126. }
  127. /**
  128. * Constructs an IndexColorModel from the given arrays of red,
  129. * green, blue and alpha components. All of the arrays specifying
  130. * the components must have at least the specified number
  131. * of entries. The ColorSpace will be the default sRGB space.
  132. * The transparency value will be Transparency.TRANSLUCENT.
  133. * The transfer type will be the smallest of DataBuffer.TYPE_BYTE,
  134. * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT that can hold a
  135. * single pixel.
  136. * @param bits The number of bits each pixel occupies.
  137. * @param size The size of the color component arrays.
  138. * @param r The array of red color components.
  139. * @param g The array of green color components.
  140. * @param b The array of blue color components.
  141. * @param a The array of alpha value components.
  142. */
  143. public IndexColorModel(int bits, int size,
  144. byte r[], byte g[], byte b[], byte a[]) {
  145. super (bits, IndexColorModel.setBits(bits, true),
  146. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  147. true, false, Transparency.TRANSLUCENT,
  148. ColorModel.getDefaultTransferType(bits));
  149. if (bits < 1 || bits > 32) {
  150. throw new IllegalArgumentException("Number of bits must be between"
  151. +" 1 and 32.");
  152. }
  153. setRGBs (size, r, g, b, a);
  154. setTransparentPixel (-1);
  155. checkAllGrayOpaque();
  156. }
  157. /**
  158. * Constructs an IndexColorModel from a single array of interleaved
  159. * red, green, blue and optional alpha components. The array
  160. * must have enough values in it to fill all of the needed
  161. * component arrays of the specified size. The ColorSpace will
  162. * be the default sRGB space. The transparency value will be
  163. * Transparency.TRANSLUCENT if hasAlpha is true, Transparency.OPAQUE
  164. * otherwise. The transfer type will be the smallest of
  165. * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
  166. * that can hold a single pixel.
  167. * sRGB ColorSpace.
  168. * @param bits The number of bits each pixel occupies.
  169. * @param size The size of the color component arrays.
  170. * @param cmap The array of color components.
  171. * @param start The starting offset of the first color component.
  172. * @param hasalpha Indicates whether alpha values are contained in
  173. * the cmap array.
  174. */
  175. public IndexColorModel(int bits, int size, byte cmap[], int start,
  176. boolean hasalpha) {
  177. this(bits, size, cmap, start, hasalpha, -1);
  178. if (bits < 1 || bits > 32) {
  179. throw new IllegalArgumentException("Number of bits must be between"
  180. +" 1 and 32.");
  181. }
  182. }
  183. /**
  184. * Constructs an IndexColorModel from a single array of interleaved
  185. * red, green, blue and optional alpha components. The specified
  186. * transparent index represents a pixel that will be considered
  187. * entirely transparent regardless of any alpha value specified
  188. * for it. The array must have enough values in it to fill all
  189. * of the needed component arrays of the specified size.
  190. * The ColorSpace will be the default sRGB space. The transparency
  191. * value will be Transparency.TRANSLUCENT if hasAlpha is true;
  192. * otherwise it will be Transparency.BITMASK if trans is a valid
  193. * index into the colormap (between 0 and size - 1) or
  194. * Transparency.OPAQUE if trans is not a valid index.
  195. * The transfer type will be the smallest of
  196. * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
  197. * that can hold a single pixel.
  198. * @param bits The number of bits each pixel occupies.
  199. * @param size The size of the color component arrays.
  200. * @param cmap The array of color components.
  201. * @param start The starting offset of the first color component.
  202. * @param hasalpha Indicates whether alpha values are contained in
  203. * the cmap array.
  204. * @param trans The index of the fully transparent pixel.
  205. */
  206. public IndexColorModel(int bits, int size, byte cmap[], int start,
  207. boolean hasalpha, int trans) {
  208. // REMIND: This assumes the ordering: RGB[A]
  209. super(bits, IndexColorModel.setBits(bits, hasalpha || (trans > -1)),
  210. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  211. (hasalpha || (trans > -1)), false,
  212. hasalpha ? Transparency.TRANSLUCENT
  213. : (trans >= 0 ? Transparency.BITMASK
  214. : Transparency.OPAQUE),
  215. ColorModel.getDefaultTransferType(bits));
  216. if (bits < 1 || bits > 32) {
  217. throw new IllegalArgumentException("Number of bits must be between"
  218. +" 1 and 32.");
  219. }
  220. if (size <= 1) {
  221. throw new IllegalArgumentException("Map size ("+size+
  222. ") must be >= 1");
  223. }
  224. map_size = size;
  225. rgb = new int[Math.max(size, 256)];
  226. int j = start;
  227. int alpha = 0xff;
  228. transparency = OPAQUE;
  229. for (int i = 0; i < size; i++) {
  230. rgb[i] = ((cmap[j++] & 0xff) << 16)
  231. | ((cmap[j++] & 0xff) << 8)
  232. | (cmap[j++] & 0xff);
  233. if (hasalpha) {
  234. alpha = cmap[j++];
  235. if (alpha != 0xff && transparency != TRANSLUCENT) {
  236. transparency = (alpha == 0x0
  237. ? BITMASK
  238. : TRANSLUCENT);
  239. }
  240. }
  241. rgb[i] |= (alpha << 24);
  242. }
  243. setTransparentPixel(trans);
  244. if (transparent_index >= 0) {
  245. if (transparency == OPAQUE) {
  246. transparency = BITMASK;
  247. }
  248. }
  249. else if (transparency == OPAQUE) {
  250. // Force it in case transparent_index was invalid
  251. supportsAlpha = false;
  252. numComponents = 3;
  253. }
  254. if (supportsAlpha) {
  255. nBits = new int[4];
  256. nBits[0] = nBits[1] = nBits[2] = nBits[3] = 8;
  257. }
  258. else {
  259. if (transparent_index > -1) {
  260. nBits = new int[4];
  261. nBits[3] = 1;
  262. }
  263. else {
  264. nBits = new int[3];
  265. }
  266. nBits[0] = nBits[1] = nBits[2] = 8;
  267. }
  268. checkAllGrayOpaque();
  269. }
  270. /**
  271. * Constructs an IndexColorModel from an array of ints where each
  272. * int is comprised of red, green, blue, and optional alpha components
  273. * in the default RGB color model format. The specified
  274. * transparent index represents a pixel that will be considered
  275. * entirely transparent regardless of any alpha value specified
  276. * for it. The array must have enough values in it to fill all
  277. * of the needed component arrays of the specified size.
  278. * The ColorSpace will be the default sRGB space. The transparency
  279. * value will be Transparency.TRANSLUCENT if hasAlpha is true;
  280. * otherwise it will be Transparency.BITMASK if trans is a valid
  281. * index into the colormap (between 0 and size - 1) or
  282. * Transparency.OPAQUE if trans is not a valid index.
  283. * The transfer type will be the smallest of
  284. * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
  285. * that can hold a single pixel.
  286. * @param bits The number of bits each pixel occupies.
  287. * @param size The size of the color component arrays.
  288. * @param cmap The array of color components.
  289. * @param start The starting offset of the first color component.
  290. * @param hasalpha Indicates whether alpha values are contained in
  291. * the cmap array.
  292. * @param trans The index of the fully transparent pixel.
  293. */
  294. public IndexColorModel(int bits, int size,
  295. int cmap[], int start,
  296. boolean hasalpha, int trans, int transferType) {
  297. // REMIND: This assumes the ordering: RGB[A]
  298. super(bits, IndexColorModel.setBits(bits, hasalpha),
  299. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  300. hasalpha ? true : (trans >= 0 ? true : false),
  301. false,
  302. hasalpha ? Transparency.TRANSLUCENT
  303. : (trans >= 0 ? Transparency.BITMASK
  304. : Transparency.OPAQUE),
  305. transferType);
  306. if (bits < 1 || bits > 32) {
  307. throw new IllegalArgumentException("Number of bits must be between"
  308. +" 1 and 32.");
  309. }
  310. if (size <= 1) {
  311. throw new IllegalArgumentException("Map size ("+size+
  312. ") must be >= 1");
  313. }
  314. map_size = size;
  315. rgb = new int[Math.max(size, 256)];
  316. int j = start;
  317. int alpha = 0xff000000;
  318. transparency = OPAQUE;
  319. if (!hasalpha) {
  320. // Need to make sure that the alpha is 0xff
  321. for (int i=0; i < size; i++, j++) {
  322. rgb[i] = cmap[j] | 0xff000000;
  323. }
  324. }
  325. else {
  326. for (int i = 0; i < size; i++, j++) {
  327. rgb[i] = cmap[j];
  328. alpha = cmap[j] & 0xff000000;
  329. if (alpha != 0xff000000 && transparency != TRANSLUCENT) {
  330. transparency = (alpha == 0x0
  331. ? BITMASK
  332. : TRANSLUCENT);
  333. }
  334. }
  335. }
  336. setTransparentPixel(trans);
  337. if (transparent_index >= 0) {
  338. if (transparency == OPAQUE) {
  339. transparency = BITMASK;
  340. }
  341. }
  342. checkAllGrayOpaque();
  343. }
  344. private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) {
  345. if (size < 1) {
  346. throw new IllegalArgumentException("Map size ("+size+
  347. ") must be >= 1");
  348. }
  349. map_size = size;
  350. rgb = new int[Math.max(size, 256)];
  351. int alpha = 0xff;
  352. transparency = OPAQUE;
  353. for (int i = 0; i < size; i++) {
  354. if (a != null) {
  355. alpha = (a[i] & 0xff);
  356. if (alpha != 0xff && transparency != TRANSLUCENT) {
  357. transparency = (alpha == 0x0
  358. ? BITMASK
  359. : TRANSLUCENT);
  360. }
  361. }
  362. rgb[i] = (alpha << 24)
  363. | ((r[i] & 0xff) << 16)
  364. | ((g[i] & 0xff) << 8)
  365. | (b[i] & 0xff);
  366. }
  367. nBits = new int[4];
  368. nBits[0] = nBits[1] = nBits[2] = nBits[3] = 8;
  369. maxBits = 8;
  370. }
  371. private void checkAllGrayOpaque() {
  372. int c;
  373. allgrayopaque = false;
  374. if ((transparent_index >= 0) || (transparency == TRANSLUCENT)) {
  375. return;
  376. }
  377. for (int i = 0; i < map_size; i++) {
  378. c = rgb[i];
  379. if (c == 0x0) {
  380. /* ignore transparent black */
  381. continue;
  382. }
  383. if ((c & 0xff000000) != 0xff000000) {
  384. return;
  385. }
  386. if ((((c >> 16) & 0xff) != ((c >> 8) & 0xff)) ||
  387. (((c >> 8) & 0xff) != (c & 0xff))) {
  388. return;
  389. }
  390. }
  391. allgrayopaque = true;
  392. transparency = OPAQUE;
  393. }
  394. /**
  395. * Returns the transparency. Returns either OPAQUE, BITMASK,
  396. * or TRANSLUCENT
  397. * @see Transparency#OPAQUE
  398. * @see Transparency#BITMASK
  399. * @see Transparency#TRANSLUCENT
  400. */
  401. public int getTransparency() {
  402. return transparency;
  403. }
  404. /**
  405. * Returns an array of the number of bits per color/alpha component.
  406. * The array contains the color components in the order red, green,
  407. * blue, followed by the alpha component, if present.
  408. */
  409. public int[] getComponentSize() {
  410. if (nBits == null) {
  411. if (supportsAlpha) {
  412. nBits = new int[4];
  413. nBits[3] = 8;
  414. }
  415. else {
  416. nBits = new int[3];
  417. }
  418. nBits[0] = nBits[1] = nBits[2] = 8;
  419. }
  420. return nBits;
  421. }
  422. /**
  423. * Returns the size of the color/alpha component arrays in this
  424. * IndexColorModel.
  425. */
  426. final public int getMapSize() {
  427. return map_size;
  428. }
  429. /**
  430. * Returns the index of the transparent pixel in this IndexColorModel
  431. * or -1 if there is no transparent pixel.
  432. */
  433. final public int getTransparentPixel() {
  434. return transparent_index;
  435. }
  436. /**
  437. * Copies the array of red color components into the given array. Only
  438. * the initial entries of the array as specified by getMapSize() are
  439. * written.
  440. */
  441. final public void getReds(byte r[]) {
  442. for (int i = 0; i < map_size; i++) {
  443. r[i] = (byte) (rgb[i] >> 16);
  444. }
  445. }
  446. /**
  447. * Copies the array of green color components into the given array. Only
  448. * the initial entries of the array as specified by getMapSize() are
  449. * written.
  450. */
  451. final public void getGreens(byte g[]) {
  452. for (int i = 0; i < map_size; i++) {
  453. g[i] = (byte) (rgb[i] >> 8);
  454. }
  455. }
  456. /**
  457. * Copies the array of blue color components into the given array. Only
  458. * the initial entries of the array as specified by getMapSize() will
  459. * be written.
  460. */
  461. final public void getBlues(byte b[]) {
  462. for (int i = 0; i < map_size; i++) {
  463. b[i] = (byte) rgb[i];
  464. }
  465. }
  466. /**
  467. * Copies the array of alpha transparency components into the given array.
  468. * Only the initial entries of the array as specified by getMapSize() will
  469. * be written.
  470. */
  471. final public void getAlphas(byte a[]) {
  472. for (int i = 0; i < map_size; i++) {
  473. a[i] = (byte) (rgb[i] >> 24);
  474. }
  475. }
  476. /**
  477. * Converts data for each index from the color and alpha component
  478. * arrays to an int in the default RGB ColorModel format and copies
  479. * the resulting 32-bit ARGB values into the given array. Only
  480. * the initial entries of the array as specified by getMapSize() will
  481. * be written.
  482. */
  483. final public void getRGBs(int rgb[]) {
  484. System.arraycopy(this.rgb, 0, rgb, 0, map_size);
  485. }
  486. private void setTransparentPixel(int trans) {
  487. if (trans >= map_size || trans < 0) {
  488. trans = -1;
  489. } else {
  490. rgb[trans] &= 0x00ffffff;
  491. }
  492. transparent_index = trans;
  493. }
  494. /**
  495. * Returns the red color component for the specified pixel, scaled
  496. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  497. * is specified as an int. The returned value will be a
  498. * non pre-multiplied value.
  499. */
  500. final public int getRed(int pixel) {
  501. return (rgb[pixel] >> 16) & 0xff;
  502. }
  503. /**
  504. * Returns the green color component for the specified pixel, scaled
  505. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  506. * is specified as an int. The returned value will be a
  507. * non pre-multiplied value.
  508. */
  509. final public int getGreen(int pixel) {
  510. return (rgb[pixel] >> 8) & 0xff;
  511. }
  512. /**
  513. * Returns the blue color component for the specified pixel, scaled
  514. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  515. * is specified as an int. The returned value will be a
  516. * non pre-multiplied value.
  517. */
  518. final public int getBlue(int pixel) {
  519. return rgb[pixel] & 0xff;
  520. }
  521. /**
  522. * Returns the alpha component for the specified pixel, scaled
  523. * from 0 to 255. The pixel value is specified as an int.
  524. */
  525. final public int getAlpha(int pixel) {
  526. return (rgb[pixel] >> 24) & 0xff;
  527. }
  528. /**
  529. * Returns the color/alpha components of the pixel in the default
  530. * RGB color model format. The pixel value is specified as an int.
  531. * The returned value will be in a non pre-multiplied format.
  532. * @see ColorModel#getRGBdefault
  533. */
  534. final public int getRGB(int pixel) {
  535. return rgb[pixel];
  536. }
  537. /**
  538. * Returns a data element array representation of a pixel in this
  539. * ColorModel, given an integer pixel representation in the
  540. * default RGB color model.
  541. * This array can then be passed to the setDataElements method of
  542. * a WritableRaster object. If the pixel variable is null, a new
  543. * array will be allocated. If pixel is not null, it must be
  544. * a primitive array of type transferType; otherwise, a
  545. * ClassCastException is thrown. An ArrayIndexOutOfBoundsException is
  546. * thrown if pixel is not large enough to hold a pixel value for this
  547. * ColorModel. The pixel array will be returned.
  548. * @see WritableRaster#setDataElements
  549. * @see SampleModel#setDataElements
  550. */
  551. public Object getDataElements(int rgb, Object pixel) {
  552. int red = (rgb>>16) & 0xff;
  553. int green = (rgb>>8) & 0xff;
  554. int blue = rgb & 0xff;
  555. int alpha = (rgb>>>24);
  556. int pix = 0;
  557. if (alpha == 0) {
  558. // Look for another transparent pixel
  559. if (transparent_index > -1) {
  560. pix = transparent_index;
  561. }
  562. else {
  563. // Search for one
  564. for (int i=0; i < map_size; i++) {
  565. if (this.rgb[i] < (1 << 24)) {
  566. transparent_index = i;
  567. pix = i;
  568. break;
  569. }
  570. }
  571. }
  572. } else {
  573. // a heuristic which says find the closest color,
  574. // after finding the closest alpha
  575. // if user wants different behavior, they can derive
  576. // a class and override this method
  577. // SLOW --- but accurate
  578. // REMIND - need a native implementation, and inverse color-map
  579. int smallestError = 255 * 255 * 255; // largest possible
  580. int smallestAlphaError = 255;
  581. for (int i=0; i < map_size; i++) {
  582. int lutrgb = this.rgb[i];
  583. int tmp = (lutrgb>>>24) - alpha;
  584. if (tmp < 0) {
  585. tmp = -tmp;
  586. }
  587. if (tmp <= smallestAlphaError) {
  588. smallestAlphaError = tmp;
  589. tmp = ((lutrgb>>16) & 0xff) - red;
  590. int currentError = tmp * tmp;
  591. if (currentError < smallestError) {
  592. tmp = ((lutrgb>>8) & 0xff) - green;
  593. currentError += tmp * tmp;
  594. if (currentError < smallestError) {
  595. tmp = (lutrgb & 0xff) - blue;
  596. currentError += tmp * tmp;
  597. if (currentError < smallestError) {
  598. pix = i;
  599. smallestError = currentError;
  600. }
  601. }
  602. }
  603. }
  604. }
  605. }
  606. if (red == green && green == blue) {
  607. // Grayscale
  608. }
  609. switch (transferType) {
  610. case DataBuffer.TYPE_INT:
  611. int[] intObj;
  612. if (pixel == null) {
  613. pixel = intObj = new int[1];
  614. } else {
  615. intObj = (int[]) pixel;
  616. }
  617. intObj[0] = pix;
  618. break;
  619. case DataBuffer.TYPE_BYTE:
  620. byte[] byteObj;
  621. if (pixel == null) {
  622. pixel = byteObj = new byte[1];
  623. } else {
  624. byteObj = (byte[]) pixel;
  625. }
  626. byteObj[0] = (byte) pix;
  627. break;
  628. case DataBuffer.TYPE_USHORT:
  629. short[] shortObj;
  630. if (pixel == null) {
  631. pixel = shortObj = new short[1];
  632. } else {
  633. shortObj = (short[]) pixel;
  634. }
  635. shortObj[0] = (short) pix;
  636. break;
  637. default:
  638. throw new IllegalArgumentException("This method has not been "+
  639. "implemented for transferType " + transferType);
  640. }
  641. return pixel;
  642. }
  643. /**
  644. * Returns an array of unnormalized color/alpha components given a pixel
  645. * in this ColorModel. The pixel value is specified as an int. If the
  646. * components array is null, a new array will be allocated. The
  647. * components array will be returned. Color/alpha components are
  648. * stored in the components array starting at offset (even if the
  649. * array is allocated by this method). An ArrayIndexOutOfBoundsException
  650. * is thrown if the components array is not null and is not large
  651. * enough to hold all the color and alpha components (starting at offset).
  652. */
  653. public int[] getComponents(int pixel, int[] components, int offset) {
  654. if (components == null) {
  655. components = new int[offset+numComponents];
  656. }
  657. // REMIND: Needs to change if different color space
  658. components[offset+0] = getRed(pixel);
  659. components[offset+1] = getGreen(pixel);
  660. components[offset+2] = getBlue(pixel);
  661. if (supportsAlpha && (components.length-offset) > 3) {
  662. components[offset+3] = getAlpha(pixel);
  663. }
  664. return components;
  665. }
  666. /**
  667. * Returns an array of unnormalized color/alpha components given a pixel
  668. * in this ColorModel. The pixel value is specified by an array of
  669. * data elements of type transferType passed in as an object reference.
  670. * If pixel is not a primitive array of type transferType, a
  671. * ClassCastException is thrown. An ArrayIndexOutOfBoundsException is
  672. * thrown if pixel is not large enough to hold a pixel value for this
  673. * ColorModel. If the components array is null, a new
  674. * array will be allocated. The components array will be returned.
  675. * Color/alpha components are
  676. * stored in the components array starting at offset (even if the
  677. * array is allocated by this method). An ArrayIndexOutOfBoundsException
  678. * is thrown if the components array is not null and is not large
  679. * enough to hold all the color and alpha components (starting at offset).
  680. */
  681. public int[] getComponents(Object pixel, int[] components, int offset) {
  682. int intpixel;
  683. switch (transferType) {
  684. case DataBuffer.TYPE_BYTE:
  685. byte bdata[] = (byte[])pixel;
  686. intpixel = bdata[0] & 0xff;
  687. break;
  688. case DataBuffer.TYPE_USHORT:
  689. short sdata[] = (short[])pixel;
  690. intpixel = sdata[0] & 0xffff;
  691. break;
  692. case DataBuffer.TYPE_INT:
  693. int idata[] = (int[])pixel;
  694. intpixel = idata[0];
  695. break;
  696. default:
  697. throw new UnsupportedOperationException("This method has not been "+
  698. "implemented for transferType " + transferType);
  699. }
  700. return getComponents(intpixel, components, offset);
  701. }
  702. /**
  703. * Returns a pixel value represented as an int in this ColorModel,
  704. * given an array of unnormalized color/alpha components. An
  705. * ArrayIndexOutOfBoundsException is thrown if the components array is
  706. * not large enough to hold all the color and alpha components (starting
  707. * at offset).
  708. */
  709. public int getDataElement(int[] components, int offset) {
  710. int rgb = (components[offset+0]<<16)
  711. | (components[offset+1]<<8) | (components[offset+2]);
  712. if (supportsAlpha) {
  713. rgb |= (components[offset+3]<<24);
  714. }
  715. else {
  716. rgb |= 0xff000000;
  717. }
  718. Object inData = getDataElements(rgb, null);
  719. int pixel;
  720. switch (transferType) {
  721. case DataBuffer.TYPE_BYTE:
  722. byte bdata[] = (byte[])inData;
  723. pixel = bdata[0] & 0xff;
  724. break;
  725. case DataBuffer.TYPE_USHORT:
  726. short sdata[] = (short[])inData;
  727. pixel = sdata[0];
  728. break;
  729. case DataBuffer.TYPE_INT:
  730. int idata[] = (int[])inData;
  731. pixel = idata[0];
  732. break;
  733. default:
  734. throw new UnsupportedOperationException("This method has not been "+
  735. "implemented for transferType " + transferType);
  736. }
  737. return pixel;
  738. }
  739. /**
  740. * Returns a data element array representation of a pixel in this
  741. * ColorModel, given an array of unnormalized color/alpha components.
  742. * This array can then be passed to the setDataElements method of
  743. * a WritableRaster object.
  744. * An ArrayIndexOutOfBoundsException is thrown if the components array
  745. * is not large enough to hold all the color and alpha components
  746. * (starting at offset). If the pixel variable is null, a new array
  747. * will be allocated. If pixel is not null, it must be a primitive array
  748. * of type transferType; otherwise, a ClassCastException is thrown.
  749. * An ArrayIndexOutOfBoundsException is thrown if pixel is not large
  750. * enough to hold a pixel value for this ColorModel.
  751. * @see WritableRaster#setDataElements
  752. * @see SampleModel#setDataElements
  753. */
  754. public Object getDataElements(int[] components, int offset, Object pixel) {
  755. int rgb = (components[offset+0]<<16) | (components[offset+1]<<8)
  756. | (components[offset+2]);
  757. if (supportsAlpha) {
  758. rgb |= (components[offset+3]<<24);
  759. }
  760. else {
  761. rgb &= 0xff000000;
  762. }
  763. return getDataElements(rgb, pixel);
  764. }
  765. /**
  766. * Creates a WritableRaster with the specified width and height that
  767. * has a data layout (SampleModel) compatible with this ColorModel.
  768. * @throws UnsupportedOperationException if the number of pixel bits
  769. * in this ColorModel is greater than 16.
  770. * @see WritableRaster
  771. * @see SampleModel
  772. */
  773. public WritableRaster createCompatibleWritableRaster(int w, int h) {
  774. WritableRaster raster;
  775. if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
  776. // TYPE_BINARY
  777. raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
  778. w, h, 1, pixel_bits, null);
  779. }
  780. else if (pixel_bits <= 8) {
  781. raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  782. w,h,1,null);
  783. }
  784. else if (pixel_bits <= 16) {
  785. raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
  786. w,h,1,null);
  787. }
  788. else {
  789. throw new
  790. UnsupportedOperationException("This method is not supported "+
  791. " for pixel bits > 16.");
  792. }
  793. return raster;
  794. }
  795. /**
  796. * Returns true if raster is compatible with this ColorModel and
  797. * false if it is not.
  798. */
  799. public boolean isCompatibleRaster(Raster raster) {
  800. int size = raster.getSampleModel().getSampleSize(0);
  801. return ((raster.getTransferType() == transferType) &&
  802. (raster.getNumBands() == 1) && ((1 << size) >= map_size));
  803. }
  804. /**
  805. * Creates a SampleModel with the specified width and height that
  806. * has a data layout compatible with this ColorModel.
  807. * @see SampleModel
  808. */
  809. public SampleModel createCompatibleSampleModel(int w, int h) {
  810. int[] off = new int[1];
  811. off[0] = 0;
  812. return new ComponentSampleModel(transferType, w, h, 1, w,
  813. off);
  814. }
  815. /** Checks if the SampleModel is compatible with this ColorModel.
  816. * @see SampleModel
  817. */
  818. public boolean isCompatibleSampleModel(SampleModel sm) {
  819. if (! (sm instanceof ComponentSampleModel)) {
  820. return false;
  821. }
  822. // Transfer type must be the same
  823. if (sm.getTransferType() != transferType) {
  824. return false;
  825. }
  826. if (numComponents != sm.getNumBands()) {
  827. return false;
  828. }
  829. return true;
  830. }
  831. /**
  832. * Returns a new BufferedImage of TYPE_INT_ARGB or TYPE_INT_RGB which
  833. * has a Raster with pixel data computed by expanding the indices
  834. * in the source Raster using the color/alpha component arrays of
  835. * this ColorModel. If forceARGB is true, a TYPE_INT_ARGB image is
  836. * returned regardless of whether this ColorModel has an alpha component
  837. * array or a transparent pixel.
  838. */
  839. public BufferedImage convertToIntDiscrete(Raster raster,
  840. boolean forceARGB) {
  841. ColorModel cm;
  842. if (forceARGB || transparency == TRANSLUCENT) {
  843. cm = ColorModel.getRGBdefault();
  844. }
  845. else if (transparency == BITMASK) {
  846. cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff,
  847. 0x1000000);
  848. }
  849. else {
  850. cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff);
  851. }
  852. int w = raster.getWidth();
  853. int h = raster.getHeight();
  854. WritableRaster discreteRaster =
  855. cm.createCompatibleWritableRaster(w, h);
  856. Object obj = null;
  857. int[] data = null;
  858. int rX = raster.getMinX();
  859. int rY = raster.getMinY();
  860. for (int y=0; y < h; y++, rY++) {
  861. obj = raster.getDataElements(rX, rY, w, 1, obj);
  862. if (obj instanceof int[]) {
  863. data = (int[])obj;
  864. } else {
  865. data = DataBuffer.toIntArray(obj);
  866. }
  867. for (int x=0; x < w; x++) {
  868. data[x] = rgb[data[x]];
  869. }
  870. discreteRaster.setDataElements(0, y, w, 1, data);
  871. }
  872. return new BufferedImage(cm, discreteRaster, false, null);
  873. }
  874. private static int[] setBits(int bits, boolean hasAlpha) {
  875. int[] b = new int[3+(hasAlpha ? 1 : 0)];
  876. b[0] = b[1] = b[2] = 8;
  877. if (hasAlpha) {
  878. b[3] = 8;
  879. }
  880. return b;
  881. }
  882. public void finalize() {
  883. ImageData.freeNativeICMData(this);
  884. }
  885. /**
  886. * Prints the contents of this object
  887. */
  888. public String toString() {
  889. return new String("IndexColorModel: #pixelBits = "+pixel_bits
  890. + " numComponents = "+numComponents
  891. + " color space = "+colorSpace
  892. + " transparency = "+transparency
  893. + " transIndex = "+transparent_index
  894. + " has alpha = "+supportsAlpha
  895. + " isAlphaPre = "+isAlphaPremultiplied
  896. );
  897. }
  898. }