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