1. /*
  2. * @(#)IndexColorModel.java 1.96 03/12/19
  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.math.BigInteger;
  11. /**
  12. * The <code>IndexColorModel</code> class is a <code>ColorModel</code>
  13. * class that works with pixel values consisting of a
  14. * single sample that is an index into a fixed colormap in the default
  15. * sRGB color space. The colormap specifies red, green, blue, and
  16. * optional alpha components corresponding to each index. All components
  17. * are represented in the colormap as 8-bit unsigned integral values.
  18. * Some constructors allow the caller to specify "holes" in the colormap
  19. * by indicating which colormap entries are valid and which represent
  20. * unusable colors via the bits set in a <code>BigInteger</code> object.
  21. * This color model is similar to an X11 PseudoColor visual.
  22. * <p>
  23. * Some constructors provide a means to specify an alpha component
  24. * for each pixel in the colormap, while others either provide no
  25. * such means or, in some cases, a flag to indicate whether the
  26. * colormap data contains alpha values. If no alpha is supplied to
  27. * the constructor, an opaque alpha component (alpha = 1.0) is
  28. * assumed for each entry.
  29. * An optional transparent pixel value can be supplied that indicates a
  30. * pixel to be made completely transparent, regardless of any alpha
  31. * component supplied or assumed for that pixel value.
  32. * Note that the color components in the colormap of an
  33. * <code>IndexColorModel</code> objects are never pre-multiplied with
  34. * the alpha components.
  35. * <p>
  36. * <a name="transparency">
  37. * The transparency of an <code>IndexColorModel</code> object is
  38. * determined by examining the alpha components of the colors in the
  39. * colormap and choosing the most specific value after considering
  40. * the optional alpha values and any transparent index specified.
  41. * The transparency value is <code>Transparency.OPAQUE</code>
  42. * only if all valid colors in
  43. * the colormap are opaque and there is no valid transparent pixel.
  44. * If all valid colors
  45. * in the colormap are either completely opaque (alpha = 1.0) or
  46. * completely transparent (alpha = 0.0), which typically occurs when
  47. * a valid transparent pixel is specified,
  48. * the value is <code>Transparency.BITMASK</code>.
  49. * Otherwise, the value is <code>Transparency.TRANSLUCENT</code>, indicating
  50. * that some valid color has an alpha component that is
  51. * neither completely transparent nor completely opaque (0.0 < alpha < 1.0).
  52. * </a>
  53. *
  54. * <p>
  55. * If an <code>IndexColorModel</code> object has
  56. * a transparency value of <code>Transparency.OPAQUE</code>,
  57. * then the <code>hasAlpha</code>
  58. * and <code>getNumComponents</code> methods
  59. * (both inherited from <code>ColorModel</code>)
  60. * return false and 3, respectively.
  61. * For any other transparency value,
  62. * <code>hasAlpha</code> returns true
  63. * and <code>getNumComponents</code> returns 4.
  64. *
  65. * <p>
  66. * The index represented by a pixel value is stored in the least
  67. * significant <em>n</em> bits of the pixel representations passed to the
  68. * methods of this class, where <em>n</em> is the pixel size specified to the
  69. * constructor for a particular <code>IndexColorModel</code> object;
  70. * <em>n</em> must be between 1 and 16, inclusive.
  71. * Higher order bits in pixel representations are assumed to be zero.
  72. * For those methods that use a primitive array pixel representation of
  73. * type <code>transferType</code>, the array length is always one.
  74. * The transfer types supported are <code>DataBuffer.TYPE_BYTE</code> and
  75. * <code>DataBuffer.TYPE_USHORT</code>. A single int pixel
  76. * representation is valid for all objects of this class, since it is
  77. * always possible to represent pixel values used with this class in a
  78. * single int. Therefore, methods that use this representation do
  79. * not throw an <code>IllegalArgumentException</code> due to an invalid
  80. * pixel value.
  81. * <p>
  82. * Many of the methods in this class are final. The reason for
  83. * this is that the underlying native graphics code makes assumptions
  84. * about the layout and operation of this class and those assumptions
  85. * are reflected in the implementations of the methods here that are
  86. * marked final. You can subclass this class for other reasons, but
  87. * you cannot override or modify the behaviour of those methods.
  88. *
  89. * @see ColorModel
  90. * @see ColorSpace
  91. * @see DataBuffer
  92. *
  93. * @version 10 Feb 1997
  94. */
  95. public class IndexColorModel extends ColorModel {
  96. private int rgb[];
  97. private int map_size;
  98. private int transparent_index = -1;
  99. private boolean allgrayopaque;
  100. private BigInteger validBits;
  101. private static int[] opaqueBits = {8, 8, 8};
  102. private static int[] alphaBits = {8, 8, 8, 8};
  103. static private native void initIDs();
  104. static {
  105. ColorModel.loadLibraries();
  106. initIDs();
  107. }
  108. /**
  109. * Constructs an <code>IndexColorModel</code> from the specified
  110. * arrays of red, green, and blue components. Pixels described
  111. * by this color model all have alpha components of 255
  112. * unnormalized (1.0 normalized), which means they
  113. * are fully opaque. All of the arrays specifying the color
  114. * components must have at least the specified number of entries.
  115. * The <code>ColorSpace</code> is the default sRGB space.
  116. * Since there is no alpha information in any of the arguments
  117. * to this constructor, the transparency value is always
  118. * <code>Transparency.OPAQUE</code>.
  119. * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
  120. * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
  121. * @param bits the number of bits each pixel occupies
  122. * @param size the size of the color component arrays
  123. * @param r the array of red color components
  124. * @param g the array of green color components
  125. * @param b the array of blue color components
  126. * @throws IllegalArgumentException if <code>bits</code> is less
  127. * than 1 or greater than 16
  128. * @throws IllegalArgumentException if <code>size</code> is less
  129. * than 1
  130. */
  131. public IndexColorModel(int bits, int size,
  132. byte r[], byte g[], byte b[]) {
  133. super(bits, opaqueBits,
  134. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  135. false, false, OPAQUE,
  136. ColorModel.getDefaultTransferType(bits));
  137. if (bits < 1 || bits > 16) {
  138. throw new IllegalArgumentException("Number of bits must be between"
  139. +" 1 and 16.");
  140. }
  141. setRGBs(size, r, g, b, null);
  142. }
  143. /**
  144. * Constructs an <code>IndexColorModel</code> from the given arrays
  145. * of red, green, and blue components. Pixels described by this color
  146. * model all have alpha components of 255 unnormalized
  147. * (1.0 normalized), which means they are fully opaque, except
  148. * for the indicated pixel to be made transparent. All of the arrays
  149. * specifying the color components must have at least the specified
  150. * number of entries.
  151. * The <code>ColorSpace</code> is the default sRGB space.
  152. * The transparency value may be <code>Transparency.OPAQUE</code> or
  153. * <code>Transparency.BITMASK</code> depending on the arguments, as
  154. * specified in the <a href="#transparency">class description</a> above.
  155. * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
  156. * or <code>DataBuffer.TYPE_USHORT</code> that can hold a
  157. * single pixel.
  158. * @param bits the number of bits each pixel occupies
  159. * @param size the size of the color component arrays
  160. * @param r the array of red color components
  161. * @param g the array of green color components
  162. * @param b the array of blue color components
  163. * @param trans the index of the transparent pixel
  164. * @throws IllegalArgumentException if <code>bits</code> is less than
  165. * 1 or greater than 16
  166. * @throws IllegalArgumentException if <code>size</code> is less than
  167. * 1
  168. */
  169. public IndexColorModel(int bits, int size,
  170. byte r[], byte g[], byte b[], int trans) {
  171. super(bits, opaqueBits,
  172. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  173. false, false, OPAQUE,
  174. ColorModel.getDefaultTransferType(bits));
  175. if (bits < 1 || bits > 16) {
  176. throw new IllegalArgumentException("Number of bits must be between"
  177. +" 1 and 16.");
  178. }
  179. setRGBs(size, r, g, b, null);
  180. setTransparentPixel(trans);
  181. }
  182. /**
  183. * Constructs an <code>IndexColorModel</code> from the given
  184. * arrays of red, green, blue and alpha components. All of the
  185. * arrays specifying the components must have at least the specified
  186. * number of entries.
  187. * The <code>ColorSpace</code> is the default sRGB space.
  188. * The transparency value may be any of <code>Transparency.OPAQUE</code>,
  189. * <code>Transparency.BITMASK</code>,
  190. * or <code>Transparency.TRANSLUCENT</code>
  191. * depending on the arguments, as specified
  192. * in the <a href="#transparency">class description</a> above.
  193. * The transfer type is the smallest of <code>DataBuffer.TYPE_BYTE</code>
  194. * or <code>DataBuffer.TYPE_USHORT</code> that can hold a single pixel.
  195. * @param bits the number of bits each pixel occupies
  196. * @param size the size of the color component arrays
  197. * @param r the array of red color components
  198. * @param g the array of green color components
  199. * @param b the array of blue color components
  200. * @param a the array of alpha value components
  201. * @throws IllegalArgumentException if <code>bits</code> is less
  202. * than 1 or greater than 16
  203. * @throws IllegalArgumentException if <code>size</code> is less
  204. * than 1
  205. */
  206. public IndexColorModel(int bits, int size,
  207. byte r[], byte g[], byte b[], byte a[]) {
  208. super (bits, alphaBits,
  209. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  210. true, false, TRANSLUCENT,
  211. ColorModel.getDefaultTransferType(bits));
  212. if (bits < 1 || bits > 16) {
  213. throw new IllegalArgumentException("Number of bits must be between"
  214. +" 1 and 16.");
  215. }
  216. setRGBs (size, r, g, b, a);
  217. }
  218. /**
  219. * Constructs an <code>IndexColorModel</code> from a single
  220. * array of interleaved red, green, blue and optional alpha
  221. * components. The array must have enough values in it to
  222. * fill all of the needed component arrays of the specified
  223. * size. The <code>ColorSpace</code> is the default sRGB space.
  224. * The transparency value may be any of <code>Transparency.OPAQUE</code>,
  225. * <code>Transparency.BITMASK</code>,
  226. * or <code>Transparency.TRANSLUCENT</code>
  227. * depending on the arguments, as specified
  228. * in the <a href="#transparency">class description</a> above.
  229. * The transfer type is the smallest of
  230. * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
  231. * that can hold a single pixel.
  232. *
  233. * @param bits the number of bits each pixel occupies
  234. * @param size the size of the color component arrays
  235. * @param cmap the array of color components
  236. * @param start the starting offset of the first color component
  237. * @param hasalpha indicates whether alpha values are contained in
  238. * the <code>cmap</code> array
  239. * @throws IllegalArgumentException if <code>bits</code> is less
  240. * than 1 or greater than 16
  241. * @throws IllegalArgumentException if <code>size</code> is less
  242. * than 1
  243. */
  244. public IndexColorModel(int bits, int size, byte cmap[], int start,
  245. boolean hasalpha) {
  246. this(bits, size, cmap, start, hasalpha, -1);
  247. if (bits < 1 || bits > 16) {
  248. throw new IllegalArgumentException("Number of bits must be between"
  249. +" 1 and 16.");
  250. }
  251. }
  252. /**
  253. * Constructs an <code>IndexColorModel</code> from a single array of
  254. * interleaved red, green, blue and optional alpha components. The
  255. * specified transparent index represents a pixel that is made
  256. * entirely transparent regardless of any alpha value specified
  257. * for it. The array must have enough values in it to fill all
  258. * of the needed component arrays of the specified size.
  259. * The <code>ColorSpace</code> is the default sRGB space.
  260. * The transparency value may be any of <code>Transparency.OPAQUE</code>,
  261. * <code>Transparency.BITMASK</code>,
  262. * or <code>Transparency.TRANSLUCENT</code>
  263. * depending on the arguments, as specified
  264. * in the <a href="#transparency">class description</a> above.
  265. * The transfer type is the smallest of
  266. * <code>DataBuffer.TYPE_BYTE</code> or <code>DataBuffer.TYPE_USHORT</code>
  267. * that can hold a single pixel.
  268. * @param bits the number of bits each pixel occupies
  269. * @param size the size of the color component arrays
  270. * @param cmap the array of color components
  271. * @param start the starting offset of the first color component
  272. * @param hasalpha indicates whether alpha values are contained in
  273. * the <code>cmap</code> array
  274. * @param trans the index of the fully transparent pixel
  275. * @throws IllegalArgumentException if <code>bits</code> is less than
  276. * 1 or greater than 16
  277. * @throws IllegalArgumentException if <code>size</code> is less than
  278. * 1
  279. */
  280. public IndexColorModel(int bits, int size, byte cmap[], int start,
  281. boolean hasalpha, int trans) {
  282. // REMIND: This assumes the ordering: RGB[A]
  283. super(bits, opaqueBits,
  284. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  285. false, false, OPAQUE,
  286. ColorModel.getDefaultTransferType(bits));
  287. if (bits < 1 || bits > 16) {
  288. throw new IllegalArgumentException("Number of bits must be between"
  289. +" 1 and 16.");
  290. }
  291. if (size < 1) {
  292. throw new IllegalArgumentException("Map size ("+size+
  293. ") must be >= 1");
  294. }
  295. map_size = size;
  296. rgb = new int[calcRealMapSize(bits, size)];
  297. int j = start;
  298. int alpha = 0xff;
  299. boolean allgray = true;
  300. int transparency = OPAQUE;
  301. for (int i = 0; i < size; i++) {
  302. int r = cmap[j++] & 0xff;
  303. int g = cmap[j++] & 0xff;
  304. int b = cmap[j++] & 0xff;
  305. allgray = allgray && (r == g) && (g == b);
  306. if (hasalpha) {
  307. alpha = cmap[j++] & 0xff;
  308. if (alpha != 0xff) {
  309. if (alpha == 0x00) {
  310. if (transparency == OPAQUE) {
  311. transparency = BITMASK;
  312. }
  313. if (transparent_index < 0) {
  314. transparent_index = i;
  315. }
  316. } else {
  317. transparency = TRANSLUCENT;
  318. }
  319. allgray = false;
  320. }
  321. }
  322. rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b;
  323. }
  324. this.allgrayopaque = allgray;
  325. setTransparency(transparency);
  326. setTransparentPixel(trans);
  327. }
  328. /**
  329. * Constructs an <code>IndexColorModel</code> from an array of
  330. * ints where each int is comprised of red, green, blue, and
  331. * optional alpha components in the default RGB color model format.
  332. * The specified transparent index represents a pixel that is made
  333. * entirely transparent regardless of any alpha value specified
  334. * for it. The array must have enough values in it to fill all
  335. * of the needed component arrays of the specified size.
  336. * The <code>ColorSpace</code> is the default sRGB space.
  337. * The transparency value may be any of <code>Transparency.OPAQUE</code>,
  338. * <code>Transparency.BITMASK</code>,
  339. * or <code>Transparency.TRANSLUCENT</code>
  340. * depending on the arguments, as specified
  341. * in the <a href="#transparency">class description</a> above.
  342. * @param bits the number of bits each pixel occupies
  343. * @param size the size of the color component arrays
  344. * @param cmap the array of color components
  345. * @param start the starting offset of the first color component
  346. * @param hasalpha indicates whether alpha values are contained in
  347. * the <code>cmap</code> array
  348. * @param trans the index of the fully transparent pixel
  349. * @param transferType the data type of the array used to represent
  350. * pixel values. The data type must be either
  351. * <code>DataBuffer.TYPE_BYTE</code> or
  352. * <code>DataBuffer.TYPE_USHORT</code>.
  353. * @throws IllegalArgumentException if <code>bits</code> is less
  354. * than 1 or greater than 16
  355. * @throws IllegalArgumentException if <code>size</code> is less
  356. * than 1
  357. * @throws IllegalArgumentException if <code>transferType</code> is not
  358. * one of <code>DataBuffer.TYPE_BYTE</code> or
  359. * <code>DataBuffer.TYPE_USHORT</code>
  360. */
  361. public IndexColorModel(int bits, int size,
  362. int cmap[], int start,
  363. boolean hasalpha, int trans, int transferType) {
  364. // REMIND: This assumes the ordering: RGB[A]
  365. super(bits, opaqueBits,
  366. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  367. false, false, OPAQUE,
  368. transferType);
  369. if (bits < 1 || bits > 16) {
  370. throw new IllegalArgumentException("Number of bits must be between"
  371. +" 1 and 16.");
  372. }
  373. if (size < 1) {
  374. throw new IllegalArgumentException("Map size ("+size+
  375. ") must be >= 1");
  376. }
  377. if ((transferType != DataBuffer.TYPE_BYTE) &&
  378. (transferType != DataBuffer.TYPE_USHORT)) {
  379. throw new IllegalArgumentException("transferType must be either" +
  380. "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
  381. }
  382. setRGBs(size, cmap, start, hasalpha);
  383. setTransparentPixel(trans);
  384. }
  385. /**
  386. * Constructs an <code>IndexColorModel</code> from an
  387. * <code>int</code> array where each <code>int</code> is
  388. * comprised of red, green, blue, and alpha
  389. * components in the default RGB color model format.
  390. * The array must have enough values in it to fill all
  391. * of the needed component arrays of the specified size.
  392. * The <code>ColorSpace</code> is the default sRGB space.
  393. * The transparency value may be any of <code>Transparency.OPAQUE</code>,
  394. * <code>Transparency.BITMASK</code>,
  395. * or <code>Transparency.TRANSLUCENT</code>
  396. * depending on the arguments, as specified
  397. * in the <a href="#transparency">class description</a> above.
  398. * The transfer type must be one of <code>DataBuffer.TYPE_BYTE</code>
  399. * <code>DataBuffer.TYPE_USHORT</code>.
  400. * The <code>BigInteger</code> object specifies the valid/invalid pixels
  401. * in the <code>cmap</code> array. A pixel is valid if the
  402. * <code>BigInteger</code> value at that index is set, and is invalid
  403. * if the <code>BigInteger</code> bit at that index is not set.
  404. * @param bits the number of bits each pixel occupies
  405. * @param size the size of the color component array
  406. * @param cmap the array of color components
  407. * @param start the starting offset of the first color component
  408. * @param transferType the specified data type
  409. * @param validBits a <code>BigInteger</code> object. If a bit is
  410. * set in the BigInteger, the pixel at that index is valid.
  411. * If a bit is not set, the pixel at that index
  412. * is considered invalid. If null, all pixels are valid.
  413. * Only bits from 0 to the map size are considered.
  414. * @throws IllegalArgumentException if <code>bits</code> is less
  415. * than 1 or greater than 16
  416. * @throws IllegalArgumentException if <code>size</code> is less
  417. * than 1
  418. * @throws IllegalArgumentException if <code>transferType</code> is not
  419. * one of <code>DataBuffer.TYPE_BYTE</code> or
  420. * <code>DataBuffer.TYPE_USHORT</code>
  421. *
  422. */
  423. public IndexColorModel(int bits, int size, int cmap[], int start,
  424. int transferType, BigInteger validBits) {
  425. super (bits, alphaBits,
  426. ColorSpace.getInstance(ColorSpace.CS_sRGB),
  427. true, false, TRANSLUCENT,
  428. transferType);
  429. if (bits < 1 || bits > 16) {
  430. throw new IllegalArgumentException("Number of bits must be between"
  431. +" 1 and 16.");
  432. }
  433. if (size < 1) {
  434. throw new IllegalArgumentException("Map size ("+size+
  435. ") must be >= 1");
  436. }
  437. if ((transferType != DataBuffer.TYPE_BYTE) &&
  438. (transferType != DataBuffer.TYPE_USHORT)) {
  439. throw new IllegalArgumentException("transferType must be either" +
  440. "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT");
  441. }
  442. if (validBits != null) {
  443. // Check to see if it is all valid
  444. for (int i=0; i < size; i++) {
  445. if (!validBits.testBit(i)) {
  446. this.validBits = validBits;
  447. break;
  448. }
  449. }
  450. }
  451. setRGBs(size, cmap, start, true);
  452. }
  453. private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) {
  454. if (size < 1) {
  455. throw new IllegalArgumentException("Map size ("+size+
  456. ") must be >= 1");
  457. }
  458. map_size = size;
  459. rgb = new int[calcRealMapSize(pixel_bits, size)];
  460. int alpha = 0xff;
  461. int transparency = OPAQUE;
  462. boolean allgray = true;
  463. for (int i = 0; i < size; i++) {
  464. int rc = r[i] & 0xff;
  465. int gc = g[i] & 0xff;
  466. int bc = b[i] & 0xff;
  467. allgray = allgray && (rc == gc) && (gc == bc);
  468. if (a != null) {
  469. alpha = a[i] & 0xff;
  470. if (alpha != 0xff) {
  471. if (alpha == 0x00) {
  472. if (transparency == OPAQUE) {
  473. transparency = BITMASK;
  474. }
  475. if (transparent_index < 0) {
  476. transparent_index = i;
  477. }
  478. } else {
  479. transparency = TRANSLUCENT;
  480. }
  481. allgray = false;
  482. }
  483. }
  484. rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc;
  485. }
  486. this.allgrayopaque = allgray;
  487. setTransparency(transparency);
  488. }
  489. private void setRGBs(int size, int cmap[], int start, boolean hasalpha) {
  490. map_size = size;
  491. rgb = new int[calcRealMapSize(pixel_bits, size)];
  492. int j = start;
  493. int transparency = OPAQUE;
  494. boolean allgray = true;
  495. BigInteger validBits = this.validBits;
  496. for (int i = 0; i < size; i++, j++) {
  497. if (validBits != null && !validBits.testBit(i)) {
  498. continue;
  499. }
  500. int cmaprgb = cmap[j];
  501. int r = (cmaprgb >> 16) & 0xff;
  502. int g = (cmaprgb >> 8) & 0xff;
  503. int b = (cmaprgb ) & 0xff;
  504. allgray = allgray && (r == g) && (g == b);
  505. if (hasalpha) {
  506. int alpha = cmaprgb >>> 24;
  507. if (alpha != 0xff) {
  508. if (alpha == 0x00) {
  509. if (transparency == OPAQUE) {
  510. transparency = BITMASK;
  511. }
  512. if (transparent_index < 0) {
  513. transparent_index = i;
  514. }
  515. } else {
  516. transparency = TRANSLUCENT;
  517. }
  518. allgray = false;
  519. }
  520. } else {
  521. cmaprgb |= 0xff000000;
  522. }
  523. rgb[i] = cmaprgb;
  524. }
  525. this.allgrayopaque = allgray;
  526. setTransparency(transparency);
  527. }
  528. private int calcRealMapSize(int bits, int size) {
  529. int newSize = Math.max(1 << bits, size);
  530. return Math.max(newSize, 256);
  531. }
  532. private BigInteger getAllValid() {
  533. int numbytes = (map_size+7)/8;
  534. byte[] valid = new byte[numbytes];
  535. java.util.Arrays.fill(valid, (byte)0xff);
  536. valid[0] = (byte)(0xff >>> (numbytes*8 - map_size));
  537. return new BigInteger(1, valid);
  538. }
  539. /**
  540. * Returns the transparency. Returns either OPAQUE, BITMASK,
  541. * or TRANSLUCENT
  542. * @return the transparency of this <code>IndexColorModel</code>
  543. * @see Transparency#OPAQUE
  544. * @see Transparency#BITMASK
  545. * @see Transparency#TRANSLUCENT
  546. */
  547. public int getTransparency() {
  548. return transparency;
  549. }
  550. /**
  551. * Returns an array of the number of bits for each color/alpha component.
  552. * The array contains the color components in the order red, green,
  553. * blue, followed by the alpha component, if present.
  554. * @return an array containing the number of bits of each color
  555. * and alpha component of this <code>IndexColorModel</code>
  556. */
  557. public int[] getComponentSize() {
  558. if (nBits == null) {
  559. if (supportsAlpha) {
  560. nBits = new int[4];
  561. nBits[3] = 8;
  562. }
  563. else {
  564. nBits = new int[3];
  565. }
  566. nBits[0] = nBits[1] = nBits[2] = 8;
  567. }
  568. return nBits;
  569. }
  570. /**
  571. * Returns the size of the color/alpha component arrays in this
  572. * <code>IndexColorModel</code>.
  573. * @return the size of the color and alpha component arrays.
  574. */
  575. final public int getMapSize() {
  576. return map_size;
  577. }
  578. /**
  579. * Returns the index of a transparent pixel in this
  580. * <code>IndexColorModel</code> or -1 if there is no pixel
  581. * with an alpha value of 0. If a transparent pixel was
  582. * explicitly specified in one of the constructors by its
  583. * index, then that index will be preferred, otherwise,
  584. * the index of any pixel which happens to be fully transparent
  585. * may be returned.
  586. * @return the index of a transparent pixel in this
  587. * <code>IndexColorModel</code> object, or -1 if there
  588. * is no such pixel
  589. */
  590. final public int getTransparentPixel() {
  591. return transparent_index;
  592. }
  593. /**
  594. * Copies the array of red color components into the specified array.
  595. * Only the initial entries of the array as specified by
  596. * {@link #getMapSize() getMapSize} are written.
  597. * @param r the specified array into which the elements of the
  598. * array of red color components are copied
  599. */
  600. final public void getReds(byte r[]) {
  601. for (int i = 0; i < map_size; i++) {
  602. r[i] = (byte) (rgb[i] >> 16);
  603. }
  604. }
  605. /**
  606. * Copies the array of green color components into the specified array.
  607. * Only the initial entries of the array as specified by
  608. * <code>getMapSize</code> are written.
  609. * @param g the specified array into which the elements of the
  610. * array of green color components are copied
  611. */
  612. final public void getGreens(byte g[]) {
  613. for (int i = 0; i < map_size; i++) {
  614. g[i] = (byte) (rgb[i] >> 8);
  615. }
  616. }
  617. /**
  618. * Copies the array of blue color components into the specified array.
  619. * Only the initial entries of the array as specified by
  620. * <code>getMapSize</code> are written.
  621. * @param b the specified array into which the elements of the
  622. * array of blue color components are copied
  623. */
  624. final public void getBlues(byte b[]) {
  625. for (int i = 0; i < map_size; i++) {
  626. b[i] = (byte) rgb[i];
  627. }
  628. }
  629. /**
  630. * Copies the array of alpha transparency components into the
  631. * specified array. Only the initial entries of the array as specified
  632. * by <code>getMapSize</code> are written.
  633. * @param a the specified array into which the elements of the
  634. * array of alpha components are copied
  635. */
  636. final public void getAlphas(byte a[]) {
  637. for (int i = 0; i < map_size; i++) {
  638. a[i] = (byte) (rgb[i] >> 24);
  639. }
  640. }
  641. /**
  642. * Converts data for each index from the color and alpha component
  643. * arrays to an int in the default RGB ColorModel format and copies
  644. * the resulting 32-bit ARGB values into the specified array. Only
  645. * the initial entries of the array as specified by
  646. * <code>getMapSize</code> are
  647. * written.
  648. * @param rgb the specified array into which the converted ARGB
  649. * values from this array of color and alpha components
  650. * are copied.
  651. */
  652. final public void getRGBs(int rgb[]) {
  653. System.arraycopy(this.rgb, 0, rgb, 0, map_size);
  654. }
  655. private void setTransparentPixel(int trans) {
  656. if (trans >= 0 && trans < map_size) {
  657. rgb[trans] &= 0x00ffffff;
  658. transparent_index = trans;
  659. allgrayopaque = false;
  660. if (this.transparency == OPAQUE) {
  661. setTransparency(BITMASK);
  662. }
  663. }
  664. }
  665. private void setTransparency(int transparency) {
  666. if (this.transparency != transparency) {
  667. this.transparency = transparency;
  668. if (transparency == OPAQUE) {
  669. supportsAlpha = false;
  670. numComponents = 3;
  671. nBits = opaqueBits;
  672. } else {
  673. supportsAlpha = true;
  674. numComponents = 4;
  675. nBits = alphaBits;
  676. }
  677. }
  678. }
  679. /**
  680. * Returns the red color component for the specified pixel, scaled
  681. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  682. * is specified as an int. The returned value is a
  683. * non pre-multiplied value.
  684. * @param pixel the specified pixel
  685. * @return the value of the red color component for the specified pixel
  686. */
  687. final public int getRed(int pixel) {
  688. return (rgb[pixel] >> 16) & 0xff;
  689. }
  690. /**
  691. * Returns the green color component for the specified pixel, scaled
  692. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  693. * is specified as an int. The returned value is a
  694. * non pre-multiplied value.
  695. * @param pixel the specified pixel
  696. * @return the value of the green color component for the specified pixel
  697. */
  698. final public int getGreen(int pixel) {
  699. return (rgb[pixel] >> 8) & 0xff;
  700. }
  701. /**
  702. * Returns the blue color component for the specified pixel, scaled
  703. * from 0 to 255 in the default RGB ColorSpace, sRGB. The pixel value
  704. * is specified as an int. The returned value is a
  705. * non pre-multiplied value.
  706. * @param pixel the specified pixel
  707. * @return the value of the blue color component for the specified pixel
  708. */
  709. final public int getBlue(int pixel) {
  710. return rgb[pixel] & 0xff;
  711. }
  712. /**
  713. * Returns the alpha component for the specified pixel, scaled
  714. * from 0 to 255. The pixel value is specified as an int.
  715. * @param pixel the specified pixel
  716. * @return the value of the alpha component for the specified pixel
  717. */
  718. final public int getAlpha(int pixel) {
  719. return (rgb[pixel] >> 24) & 0xff;
  720. }
  721. /**
  722. * Returns the color/alpha components of the pixel in the default
  723. * RGB color model format. The pixel value is specified as an int.
  724. * The returned value is in a non pre-multiplied format.
  725. * @param pixel the specified pixel
  726. * @return the color and alpha components of the specified pixel
  727. * @see ColorModel#getRGBdefault
  728. */
  729. final public int getRGB(int pixel) {
  730. return rgb[pixel];
  731. }
  732. private static final int CACHESIZE = 40;
  733. private int lookupcache[] = new int[CACHESIZE];
  734. /**
  735. * Returns a data element array representation of a pixel in this
  736. * ColorModel, given an integer pixel representation in the
  737. * default RGB color model. This array can then be passed to the
  738. * {@link WritableRaster#setDataElements(int, int, java.lang.Object) setDataElements}
  739. * method of a {@link WritableRaster} object. If the pixel variable is
  740. * <code>null</code>, a new array is allocated. If <code>pixel</code>
  741. * is not <code>null</code>, it must be
  742. * a primitive array of type <code>transferType</code> otherwise, a
  743. * <code>ClassCastException</code> is thrown. An
  744. * <code>ArrayIndexOutOfBoundsException</code> is
  745. * thrown if <code>pixel</code> is not large enough to hold a pixel
  746. * value for this <code>ColorModel</code>. The pixel array is returned.
  747. * <p>
  748. * Since <code>IndexColorModel</code> can be subclassed, subclasses
  749. * inherit the implementation of this method and if they don't
  750. * override it then they throw an exception if they use an
  751. * unsupported <code>transferType</code>.
  752. *
  753. * @param rgb the integer pixel representation in the default RGB
  754. * color model
  755. * @param pixel the specified pixel
  756. * @return an array representation of the specified pixel in this
  757. * <code>IndexColorModel</code>.
  758. * @throws ClassCastException if <code>pixel</code>
  759. * is not a primitive array of type <code>transferType</code>
  760. * @throws ArrayIndexOutOfBoundsException if
  761. * <code>pixel</code> is not large enough to hold a pixel value
  762. * for this <code>ColorModel</code>
  763. * @throws UnsupportedOperationException if <code>transferType</code>
  764. * is invalid
  765. * @see WritableRaster#setDataElements
  766. * @see SampleModel#setDataElements
  767. */
  768. public synchronized Object getDataElements(int rgb, Object pixel) {
  769. int red = (rgb>>16) & 0xff;
  770. int green = (rgb>>8) & 0xff;
  771. int blue = rgb & 0xff;
  772. int alpha = (rgb>>>24);
  773. int pix = 0;
  774. for (int i = CACHESIZE - 2; i >= 0; i -= 2) {
  775. if ((pix = lookupcache[i]) == 0) {
  776. break;
  777. }
  778. if (rgb == lookupcache[i+1]) {
  779. return installpixel(pixel, ~pix);
  780. }
  781. }
  782. if (allgrayopaque) {
  783. int minDist = 256;
  784. int d;
  785. int gray = (int) (red*77 + green*150 + blue*29 + 128)/256;
  786. for (int i = 0; i < map_size; i++) {
  787. if (this.rgb[i] == 0x0) {
  788. // For allgrayopaque colormaps, entries are 0
  789. // iff they are an invalid color and should be
  790. // ignored during color searches.
  791. continue;
  792. }
  793. d = (this.rgb[i] & 0xff) - gray;
  794. if (d < 0) d = -d;
  795. if (d < minDist) {
  796. pix = i;
  797. if (d == 0) {
  798. break;
  799. }
  800. minDist = d;
  801. }
  802. }
  803. } else if (alpha == 0) {
  804. // Return transparent pixel if we have one
  805. if (transparent_index >= 0) {
  806. pix = transparent_index;
  807. }
  808. else {
  809. // Search for smallest alpha
  810. int smallestAlpha = 256;
  811. for (int i = 0; i < map_size; i++) {
  812. int a = this.rgb[i] >>> 24;
  813. if (smallestAlpha > alpha &&
  814. (validBits == null || validBits.testBit(i)))
  815. {
  816. smallestAlpha = alpha;
  817. pix = i;
  818. }
  819. }
  820. }
  821. } else {
  822. // a heuristic which says find the closest color,
  823. // after finding the closest alpha
  824. // if user wants different behavior, they can derive
  825. // a class and override this method
  826. // SLOW --- but accurate
  827. // REMIND - need a native implementation, and inverse color-map
  828. int smallestError = 255 * 255 * 255; // largest possible
  829. int smallestAlphaError = 255;
  830. if (false && red == green && green == blue) {
  831. // Grayscale
  832. }
  833. for (int i=0; i < map_size; i++) {
  834. int lutrgb = this.rgb[i];
  835. if (lutrgb == rgb) {
  836. pix = i;
  837. break;
  838. }
  839. int tmp = (lutrgb>>>24) - alpha;
  840. if (tmp < 0) {
  841. tmp = -tmp;
  842. }
  843. if (tmp <= smallestAlphaError) {
  844. smallestAlphaError = tmp;
  845. tmp = ((lutrgb>>16) & 0xff) - red;
  846. int currentError = tmp * tmp;
  847. if (currentError < smallestError) {
  848. tmp = ((lutrgb>>8) & 0xff) - green;
  849. currentError += tmp * tmp;
  850. if (currentError < smallestError) {
  851. tmp = (lutrgb & 0xff) - blue;
  852. currentError += tmp * tmp;
  853. if (currentError < smallestError &&
  854. (validBits == null || validBits.testBit(i)))
  855. {
  856. pix = i;
  857. smallestError = currentError;
  858. }
  859. }
  860. }
  861. }
  862. }
  863. }
  864. System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2);
  865. lookupcache[CACHESIZE - 1] = rgb;
  866. lookupcache[CACHESIZE - 2] = ~pix;
  867. return installpixel(pixel, pix);
  868. }
  869. private Object installpixel(Object pixel, int pix) {
  870. switch (transferType) {
  871. case DataBuffer.TYPE_INT:
  872. int[] intObj;
  873. if (pixel == null) {
  874. pixel = intObj = new int[1];
  875. } else {
  876. intObj = (int[]) pixel;
  877. }
  878. intObj[0] = pix;
  879. break;
  880. case DataBuffer.TYPE_BYTE:
  881. byte[] byteObj;
  882. if (pixel == null) {
  883. pixel = byteObj = new byte[1];
  884. } else {
  885. byteObj = (byte[]) pixel;
  886. }
  887. byteObj[0] = (byte) pix;
  888. break;
  889. case DataBuffer.TYPE_USHORT:
  890. short[] shortObj;
  891. if (pixel == null) {
  892. pixel = shortObj = new short[1];
  893. } else {
  894. shortObj = (short[]) pixel;
  895. }
  896. shortObj[0] = (short) pix;
  897. break;
  898. default:
  899. throw new UnsupportedOperationException("This method has not been "+
  900. "implemented for transferType " + transferType);
  901. }
  902. return pixel;
  903. }
  904. /**
  905. * Returns an array of unnormalized color/alpha components for a
  906. * specified pixel in this <code>ColorModel</code>. The pixel value
  907. * is specified as an int. If the <code>components</code> array is <code>null</code>,
  908. * a new array is allocated that contains
  909. * <code>offset + getNumComponents()</code> elements.
  910. * The <code>components</code> array is returned,
  911. * with the alpha component included
  912. * only if <code>hasAlpha</code> returns true.
  913. * Color/alpha components are stored in the <code>components</code> array starting
  914. * at <code>offset</code> even if the array is allocated by this method.
  915. * An <code>ArrayIndexOutOfBoundsException</code>
  916. * is thrown if the <code>components</code> array is not <code>null</code> and is
  917. * not large enough to hold all the color and alpha components
  918. * starting at <code>offset</code>.
  919. * @param pixel the specified pixel
  920. * @param components the array to receive the color and alpha
  921. * components of the specified pixel
  922. * @param offset the offset into the <code>components</code> array at
  923. * which to start storing the color and alpha components
  924. * @return an array containing the color and alpha components of the
  925. * specified pixel starting at the specified offset.
  926. * @see ColorModel#hasAlpha
  927. * @see ColorModel#getNumComponents
  928. */
  929. public int[] getComponents(int pixel, int[] components, int offset) {
  930. if (components == null) {
  931. components = new int[offset+numComponents];
  932. }
  933. // REMIND: Needs to change if different color space
  934. components[offset+0] = getRed(pixel);
  935. components[offset+1] = getGreen(pixel);
  936. components[offset+2] = getBlue(pixel);
  937. if (supportsAlpha && (components.length-offset) > 3) {
  938. components[offset+3] = getAlpha(pixel);
  939. }
  940. return components;
  941. }
  942. /**
  943. * Returns an array of unnormalized color/alpha components for
  944. * a specified pixel in this <code>ColorModel</code>. The pixel
  945. * value is specified by an array of data elements of type
  946. * <code>transferType</code> passed in as an object reference.
  947. * If <code>pixel</code> is not a primitive array of type
  948. * <code>transferType</code>, a <code>ClassCastException</code>
  949. * is thrown. An <code>ArrayIndexOutOfBoundsException</code>
  950. * is thrown if <code>pixel</code> is not large enough to hold
  951. * a pixel value for this <code>ColorModel</code>. If the
  952. * <code>components</code> array is <code>null</code>, a new array
  953. * is allocated that contains
  954. * <code>offset + getNumComponents()</code> elements.
  955. * The <code>components</code> array is returned,
  956. * with the alpha component included
  957. * only if <code>hasAlpha</code> returns true.
  958. * Color/alpha components are stored in the <code>components</code>
  959. * array starting at <code>offset</code> even if the array is
  960. * allocated by this method. An
  961. * <code>ArrayIndexOutOfBoundsException</code> is also
  962. * thrown if the <code>components</code> array is not
  963. * <code>null</code> and is not large enough to hold all the color
  964. * and alpha components starting at <code>offset</code>.
  965. * <p>
  966. * Since <code>IndexColorModel</code> can be subclassed, subclasses
  967. * inherit the implementation of this method and if they don't
  968. * override it then they throw an exception if they use an
  969. * unsupported <code>transferType</code>.
  970. *
  971. * @param pixel the specified pixel
  972. * @param components an array that receives the color and alpha
  973. * components of the specified pixel
  974. * @param offset the index into the <code>components</code> array at
  975. * which to begin storing the color and alpha components of the
  976. * specified pixel
  977. * @return an array containing the color and alpha components of the
  978. * specified pixel starting at the specified offset.
  979. * @throws ArrayIndexOutOfBoundsException if <code>pixel</code>
  980. * is not large enough to hold a pixel value for this
  981. * <code>ColorModel</code> or if the
  982. * <code>components</code> array is not <code>null</code>
  983. * and is not large enough to hold all the color
  984. * and alpha components starting at <code>offset</code>
  985. * @throws ClassCastException if <code>pixel</code> is not a
  986. * primitive array of type <code>transferType</code>
  987. * @throws UnsupportedOperationException if <code>transferType</code>
  988. * is not one of the supported transer types
  989. * @see ColorModel#hasAlpha
  990. * @see ColorModel#getNumComponents
  991. */
  992. public int[] getComponents(Object pixel, int[] components, int offset) {
  993. int intpixel;
  994. switch (transferType) {
  995. case DataBuffer.TYPE_BYTE:
  996. byte bdata[] = (byte[])pixel;
  997. intpixel = bdata[0] & 0xff;
  998. break;
  999. case DataBuffer.TYPE_USHORT:
  1000. short sdata[] = (short[])pixel;
  1001. intpixel = sdata[0] & 0xffff;
  1002. break;
  1003. case DataBuffer.TYPE_INT:
  1004. int idata[] = (int[])pixel;
  1005. intpixel = idata[0];
  1006. break;
  1007. default:
  1008. throw new UnsupportedOperationException("This method has not been "+
  1009. "implemented for transferType " + transferType);
  1010. }
  1011. return getComponents(intpixel, components, offset);
  1012. }
  1013. /**
  1014. * Returns a pixel value represented as an int in this
  1015. * <code>ColorModel</code> given an array of unnormalized
  1016. * color/alpha components. An
  1017. * <code>ArrayIndexOutOfBoundsException</code>
  1018. * is thrown if the <code>components</code> array is not large
  1019. * enough to hold all of the color and alpha components starting
  1020. * at <code>offset</code>. Since
  1021. * <code>ColorModel</code> can be subclassed, subclasses inherit the
  1022. * implementation of this method and if they don't override it then
  1023. * they throw an exception if they use an unsupported transferType.
  1024. * @param components an array of unnormalized color and alpha
  1025. * components
  1026. * @param offset the index into <code>components</code> at which to
  1027. * begin retrieving the color and alpha components
  1028. * @return an <code>int</code> pixel value in this
  1029. * <code>ColorModel</code> corresponding to the specified components.
  1030. * @throws ArrayIndexOutOfBoundsException if
  1031. * the <code>components</code> array is not large enough to
  1032. * hold all of the color and alpha components starting at
  1033. * <code>offset</code>
  1034. * @throws UnsupportedOperationException if <code>transferType</code>
  1035. * is invalid
  1036. */
  1037. public int getDataElement(int[] components, int offset) {
  1038. int rgb = (components[offset+0]<<16)
  1039. | (components[offset+1]<<8) | (components[offset+2]);
  1040. if (supportsAlpha) {
  1041. rgb |= (components[offset+3]<<24);
  1042. }
  1043. else {
  1044. rgb |= 0xff000000;
  1045. }
  1046. Object inData = getDataElements(rgb, null);
  1047. int pixel;
  1048. switch (transferType) {
  1049. case DataBuffer.TYPE_BYTE:
  1050. byte bdata[] = (byte[])inData;
  1051. pixel = bdata[0] & 0xff;
  1052. break;
  1053. case DataBuffer.TYPE_USHORT:
  1054. short sdata[] = (short[])inData;
  1055. pixel = sdata[0];
  1056. break;
  1057. case DataBuffer.TYPE_INT:
  1058. int idata[] = (int[])inData;
  1059. pixel = idata[0];
  1060. break;
  1061. default:
  1062. throw new UnsupportedOperationException("This method has not been "+
  1063. "implemented for transferType " + transferType);
  1064. }
  1065. return pixel;
  1066. }
  1067. /**
  1068. * Returns a data element array representation of a pixel in this
  1069. * <code>ColorModel</code> given an array of unnormalized color/alpha
  1070. * components. This array can then be passed to the
  1071. * <code>setDataElements</code> method of a <code>WritableRaster</code>
  1072. * object. An <code>ArrayIndexOutOfBoundsException</code> is
  1073. * thrown if the
  1074. * <code>components</code> array is not large enough to hold all of the
  1075. * color and alpha components starting at <code>offset</code>.
  1076. * If the pixel variable is <code>null</code>, a new array
  1077. * is allocated. If <code>pixel</code> is not <code>null</code>,
  1078. * it must be a primitive array of type <code>transferType</code>
  1079. * otherwise, a <code>ClassCastException</code> is thrown.
  1080. * An <code>ArrayIndexOutOfBoundsException</code> is thrown if pixel
  1081. * is not large enough to hold a pixel value for this
  1082. * <code>ColorModel</code>.
  1083. * <p>
  1084. * Since <code>IndexColorModel</code> can be subclassed, subclasses
  1085. * inherit the implementation of this method and if they don't
  1086. * override it then they throw an exception if they use an
  1087. * unsupported <code>transferType</code>
  1088. *
  1089. * @param components an array of unnormalized color and alpha
  1090. * components
  1091. * @param offset the index into <code>components</code> at which to
  1092. * begin retrieving color and alpha components
  1093. * @param pixel the <code>Object</code> representing an array of color
  1094. * and alpha components
  1095. * @return an <code>Object</code> representing an array of color and
  1096. * alpha components.
  1097. * @throws ClassCastException if <code>pixel</code>
  1098. * is not a primitive array of type <code>transferType</code>
  1099. * @throws ArrayIndexOutOfBoundsException if
  1100. * <code>pixel</code> is not large enough to hold a pixel value
  1101. * for this <code>ColorModel</code> or the <code>components</code>
  1102. * array is not large enough to hold all of the color and alpha
  1103. * components starting at <code>offset</code>
  1104. * @throws UnsupportedOperationException if <code>transferType</code>
  1105. * is not one of the supported transer types
  1106. * @see WritableRaster#setDataElements
  1107. * @see SampleModel#setDataElements
  1108. */
  1109. public Object getDataElements(int[] components, int offset, Object pixel) {
  1110. int rgb = (components[offset+0]<<16) | (components[offset+1]<<8)
  1111. | (components[offset+2]);
  1112. if (supportsAlpha) {
  1113. rgb |= (components[offset+3]<<24);
  1114. }
  1115. else {
  1116. rgb &= 0xff000000;
  1117. }
  1118. return getDataElements(rgb, pixel);
  1119. }
  1120. /**
  1121. * Creates a <code>WritableRaster</code> with the specified width
  1122. * and height that has a data layout (<code>SampleModel</code>)
  1123. * compatible with this <code>ColorModel</code>. This method
  1124. * only works for color models with 16 or fewer bits per pixel.
  1125. * <p>
  1126. * Since <code>IndexColorModel</code> can be subclassed, any
  1127. * subclass that supports greater than 16 bits per pixel must
  1128. * override this method.
  1129. *
  1130. * @param w the width to apply to the new <code>WritableRaster</code>
  1131. * @param h the height to apply to the new <code>WritableRaster</code>
  1132. * @return a <code>WritableRaster</code> object with the specified
  1133. * width and height.
  1134. * @throws UnsupportedOperationException if the number of bits in a
  1135. * pixel is greater than 16
  1136. * @see WritableRaster
  1137. * @see SampleModel
  1138. */
  1139. public WritableRaster createCompatibleWritableRaster(int w, int h) {
  1140. WritableRaster raster;
  1141. if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
  1142. // TYPE_BINARY
  1143. raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
  1144. w, h, 1, pixel_bits, null);
  1145. }
  1146. else if (pixel_bits <= 8) {
  1147. raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
  1148. w,h,1,null);
  1149. }
  1150. else if (pixel_bits <= 16) {
  1151. raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
  1152. w,h,1,null);
  1153. }
  1154. else {
  1155. throw new
  1156. UnsupportedOperationException("This method is not supported "+
  1157. " for pixel bits > 16.");
  1158. }
  1159. return raster;
  1160. }
  1161. /**
  1162. * Returns <code>true</code> if <code>raster</code> is compatible
  1163. * with this <code>ColorModel</code> or <code>false</code> if it
  1164. * is not compatible with this <code>ColorModel</code>.
  1165. * @param raster the {@link Raster} object to test for compatibility
  1166. * @return <code>true</code> if <code>raster</code> is compatible
  1167. * with this <code>ColorModel</code> <code>false</code> otherwise.
  1168. *
  1169. */
  1170. public boolean isCompatibleRaster(Raster raster) {
  1171. int size = raster.getSampleModel().getSampleSize(0);
  1172. return ((raster.getTransferType() == transferType) &&
  1173. (raster.getNumBands() == 1) && ((1 << size) >= map_size));
  1174. }
  1175. /**
  1176. * Creates a <code>SampleModel</code> with the specified
  1177. * width and height that has a data layout compatible with
  1178. * this <code>ColorModel</code>.
  1179. * @param w the width to apply to the new <code>SampleModel</code>
  1180. * @param h the height to apply to the new <code>SampleModel</code>
  1181. * @return a <code>SampleModel</code> object with the specified
  1182. * width and height.
  1183. * @throws IllegalArgumentException if <code>w</code> or
  1184. * <code>h</code> is not greater than 0
  1185. * @see SampleModel
  1186. */
  1187. public SampleModel createCompatibleSampleModel(int w, int h) {
  1188. int[] off = new int[1];
  1189. off[0] = 0;
  1190. if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
  1191. return new MultiPixelPackedSampleModel(transferType, w, h,
  1192. pixel_bits);
  1193. }
  1194. else {
  1195. return new ComponentSampleModel(transferType, w, h, 1, w,
  1196. off);
  1197. }
  1198. }
  1199. /**
  1200. * Checks if the specified <code>SampleModel</code> is compatible
  1201. * with this <code>ColorModel</code>. If <code>sm</code> is
  1202. * <code>null</code>, this method returns <code>false</code>.
  1203. * @param sm the specified <code>SampleModel</code>,
  1204. * or <code>null</code>
  1205. * @return <code>true</code> if the specified <code>SampleModel</code>
  1206. * is compatible with this <code>ColorModel</code> <code>false</code>
  1207. * otherwise.
  1208. * @see SampleModel
  1209. */
  1210. public boolean isCompatibleSampleModel(SampleModel sm) {
  1211. // fix 4238629
  1212. if (! (sm instanceof ComponentSampleModel) &&
  1213. ! (sm instanceof MultiPixelPackedSampleModel) ) {
  1214. return false;
  1215. }
  1216. // Transfer type must be the same
  1217. if (sm.getTransferType() != transferType) {
  1218. return false;
  1219. }
  1220. if (sm.getNumBands() != 1) {
  1221. return false;
  1222. }
  1223. return true;
  1224. }
  1225. /**
  1226. * Returns a new <code>BufferedImage</code> of TYPE_INT_ARGB or
  1227. * TYPE_INT_RGB that has a <code>Raster</code> with pixel data
  1228. * computed by expanding the indices in the source <code>Raster</code>
  1229. * using the color/alpha component arrays of this <code>ColorModel</code>.
  1230. * If <code>forceARGB</code> is <code>true</code>, a TYPE_INT_ARGB image is
  1231. * returned regardless of whether or not this <code>ColorModel</code>
  1232. * has an alpha component array or a transparent pixel.
  1233. * @param raster the specified <code>Raster</code>
  1234. * @param forceARGB if <code>true</code>, the returned
  1235. * <code>BufferedImage</code> is TYPE_INT_ARGB; otherwise it is
  1236. * TYPE_INT_RGB
  1237. * @return a <code>BufferedImage</code> created with the specified
  1238. * <code>Raster</code>
  1239. * @throws IllegalArgumentException if the raster argument is not
  1240. * compatible with this IndexColorModel
  1241. */
  1242. public BufferedImage convertToIntDiscrete(Raster raster,
  1243. boolean forceARGB) {
  1244. ColorModel cm;
  1245. if (!isCompatibleRaster(raster)) {
  1246. throw new IllegalArgumentException("This raster is not compatible" +
  1247. "with this IndexColorModel.");
  1248. }
  1249. if (forceARGB || transparency == TRANSLUCENT) {
  1250. cm = ColorModel.getRGBdefault();
  1251. }
  1252. else if (transparency == BITMASK) {
  1253. cm = new DirectColorModel(25, 0xff0000, 0x00ff00, 0x0000ff,
  1254. 0x1000000);
  1255. }
  1256. else {
  1257. cm = new DirectColorModel(24, 0xff0000, 0x00ff00, 0x0000ff);
  1258. }
  1259. int w = raster.getWidth();
  1260. int h = raster.getHeight();
  1261. WritableRaster discreteRaster =
  1262. cm.createCompatibleWritableRaster(w, h);
  1263. Object obj = null;
  1264. int[] data = null;
  1265. int rX = raster.getMinX();
  1266. int rY = raster.getMinY();
  1267. for (int y=0; y < h; y++, rY++) {
  1268. obj = raster.getDataElements(rX, rY, w, 1, obj);
  1269. if (obj instanceof int[]) {
  1270. data = (int[])obj;
  1271. } else {
  1272. data = DataBuffer.toIntArray(obj);
  1273. }
  1274. for (int x=0; x < w; x++) {
  1275. data[x] = rgb[data[x]];
  1276. }
  1277. discreteRaster.setDataElements(0, y, w, 1, data);
  1278. }
  1279. return new BufferedImage(cm, discreteRaster, false, null);
  1280. }
  1281. /**
  1282. * Returns whether or not the pixel is valid.
  1283. * @param pixel the specified pixel value
  1284. * @return <code>true</code> if <code>pixel</code>
  1285. * is valid; <code>false</code> otherwise.
  1286. */
  1287. public boolean isValid(int pixel) {
  1288. return ((pixel >= 0 && pixel < map_size) &&
  1289. (validBits == null || validBits.testBit(pixel)));
  1290. }
  1291. /**
  1292. * Returns whether or not all of the pixels are valid.
  1293. * @return <code>true</code> if all pixels are valid;
  1294. * <code>false</code> otherwise.
  1295. */
  1296. public boolean isValid() {
  1297. return (validBits == null);
  1298. }
  1299. /**
  1300. * Returns a <code>BigInteger</code> that indicates the valid/invalid
  1301. * pixels in the colormap. A bit is valid if the
  1302. * <code>BigInteger</code> value at that index is set, and is invalid
  1303. * if the <code>BigInteger</code> value at that index is not set.
  1304. * The only valid ranges to query in the <code>BigInteger</code> are
  1305. * between 0 and the map size.
  1306. * @return a <code>BigInteger</code> indicating the valid/invalid pixels.
  1307. */
  1308. public BigInteger getValidPixels() {
  1309. if (validBits == null) {
  1310. return getAllValid();
  1311. }
  1312. else {
  1313. return validBits;
  1314. }
  1315. }
  1316. /**
  1317. * Disposes of system resources associated with this
  1318. * <code>ColorModel</code> once this <code>ColorModel</code> is no
  1319. * longer referenced.
  1320. */
  1321. public void finalize() {
  1322. sun.awt.image.BufImgSurfaceData.freeNativeICMData(this);
  1323. }
  1324. /**
  1325. * Returns the <code>String</code> representation of the contents of
  1326. * this <code>ColorModel</code>object.
  1327. * @return a <code>String</code> representing the contents of this
  1328. * <code>ColorModel</code> object.
  1329. */
  1330. public String toString() {
  1331. return new String("IndexColorModel: #pixelBits = "+pixel_bits
  1332. + " numComponents = "+numComponents
  1333. + " color space = "+colorSpace
  1334. + " transparency = "+transparency
  1335. + " transIndex = "+transparent_index
  1336. + " has alpha = "+supportsAlpha
  1337. + " isAlphaPre = "+isAlphaPremultiplied
  1338. );
  1339. }
  1340. }