1. /*
  2. * @(#)ComponentColorModel.java 1.47 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.image;
  8. import java.awt.color.ColorSpace;
  9. /**
  10. * A <CODE>ColorModel</CODE> class that works with pixel values that
  11. * represent color and alpha information as separate samples and that
  12. * store each sample in a separate data element. This class can be
  13. * used with an arbitrary <CODE>ColorSpace</CODE>. The number of
  14. * color samples in the pixel values must be same as the number of
  15. * color components in the <CODE>ColorSpace</CODE>. There may be a
  16. * single alpha sample.
  17. * <p>
  18. * For those methods that use
  19. * a primitive array pixel representation of type <CODE>transferType</CODE>,
  20. * the array length is the same as the number of color and alpha samples.
  21. * Color samples are stored first in the array followed by the alpha
  22. * sample, if present. The order of the color samples is specified
  23. * by the <CODE>ColorSpace</CODE>. Typically, this order reflects the
  24. * name of the color space type. For example, for <CODE>TYPE_RGB</CODE>,
  25. * index 0 corresponds to red, index 1 to green, and index 2 to blue.
  26. * The transfer types supported are <CODE>DataBuffer.TYPE_BYTE</CODE>,
  27. * <CODE>DataBuffer.TYPE_USHORT</CODE>, and <CODE>DataBuffer.TYPE_INT</CODE>.
  28. * <p>
  29. * The translation from pixel values to color/alpha components for
  30. * display or processing purposes is a one-to-one correspondence of
  31. * samples to components.
  32. * The number of bits in a color or alpha sample of a pixel value might not
  33. * be the same as the number of bits for the corresponding color or alpha
  34. * component passed to the <CODE>ComponentColorModel</CODE> constructor.
  35. * This class assumes that the least significant n bits of a sample value
  36. * hold the component value, where n is the number of significant bits
  37. * for the component passed to the constructor. It also assumes that
  38. * any higher-order bits in a sample value are zero.
  39. * <p>
  40. * Methods that use a single int pixel representation throw
  41. * an <CODE>IllegalArgumentException</CODE>, unless the number of components
  42. * for the <CODE>ComponentColorModel</CODE> is one--in other words, a single
  43. * color component and no alpha.
  44. * <p>
  45. * A <CODE>ComponentColorModel</CODE> can be used in conjunction with a
  46. * <CODE>ComponentSampleModel</CODE>, a <CODE>BandedSampleModel</CODE>,
  47. * or a <CODE>PixelInterleavedSampleModel</CODE> to construct a
  48. * <CODE>BufferedImage</CODE>.
  49. *
  50. * @see ColorModel
  51. * @see ColorSpace
  52. * @see ComponentSampleModel
  53. * @see BandedSampleModel
  54. * @see PixelInterleavedSampleModel
  55. * @see BufferedImage
  56. *
  57. * @version 10 Feb 1997
  58. */
  59. public class ComponentColorModel extends ColorModel {
  60. /**
  61. * Constructs a <CODE>ComponentColorModel</CODE> from the specified
  62. * parameters. Color components will be in the specified <CODE>ColorSpace</CODE>.
  63. * The <CODE>bits</CODE> array specifies the number of significant bits
  64. * per color and alpha component. Its length should be the number
  65. * of components in the <CODE>ColorSpace</CODE> if there is no alpha
  66. * information in the pixel values, or one more than this number if
  67. * there is alpha information. An <CODE>IllegalArgumentException</CODE>
  68. * is thrown if the length of the array does not match the number of components.
  69. * <CODE>hasAlpha</CODE> indicates whether alpha information is present. If
  70. * <CODE>hasAlpha</CODE> is true, then the boolean <CODE>isAlphaPremultiplied</CODE>
  71. * specifies how to interpret color and alpha samples in pixel values.
  72. * If the boolean is true, color samples are assumed to have been multiplied
  73. * by the alpha sample. The <CODE>transparency</CODE> specifies what alpha
  74. * values can be represented by this color model. The <CODE>transferType</CODE>
  75. * is the type of primitive array used to represent pixel values. Note that
  76. * the <CODE>bits</CODE> array contains the number of significant bits per
  77. * color/alpha component after the translation from pixel values.
  78. *
  79. * @param colorSpace The <CODE>ColorSpace</CODE> associated with this color model.
  80. * @param bits The number of significant bits per component.
  81. * @param hasAlpha If true, this color model supports alpha.
  82. * @param isAlphaPremultiplied If true, alpha is premultiplied.
  83. * @param transparency Specifies what alpha values can be represented
  84. * by this color model.
  85. * @param transferType Specifies the type of primitive array used to
  86. * represent pixel values.
  87. *
  88. * @throws IllegalArgumentException If the length of the length of the <CODE>bits</CODE>
  89. * array does not match the number of components.
  90. *
  91. * @see ColorSpace
  92. * @see java.awt.Transparency
  93. */
  94. public ComponentColorModel (ColorSpace colorSpace,
  95. int[] bits,
  96. boolean hasAlpha,
  97. boolean isAlphaPremultiplied,
  98. int transparency,
  99. int transferType) {
  100. super (DataBuffer.getDataTypeSize(transferType)*bits.length,
  101. bits, colorSpace, hasAlpha, isAlphaPremultiplied, transparency,
  102. transferType);
  103. }
  104. /**
  105. * Returns the red color component for the specified pixel, scaled
  106. * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
  107. * is done if necessary. The pixel value is specified as an int.
  108. * The returned value will be a non pre-multiplied value.
  109. * If the alpha is premultiplied, this method divides
  110. * it out before returning the value (if the alpha value is 0,
  111. * the red value will be 0).
  112. *
  113. * @param pixel The pixel from which you want to get the red color component.
  114. *
  115. * @return The red color component for the specified pixel, as an int.
  116. *
  117. * @throws IllegalArgumentException If there is more than
  118. * one component in this <CODE>ColorModel</CODE>.
  119. */
  120. public int getRed(int pixel) {
  121. if (numComponents > 1) {
  122. throw new
  123. IllegalArgumentException("More than one component per pixel");
  124. }
  125. // Since there is only 1 component, there is no alpha
  126. // Normalize the pixel in order to convert it
  127. float[] norm = { (float) pixel / ((1<<nBits[0]) - 1) };
  128. float[] rgb = colorSpace.toRGB(norm);
  129. return (int) rgb[0]*255;
  130. }
  131. /**
  132. * Returns the green color component for the specified pixel, scaled
  133. * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
  134. * is done if necessary. The pixel value is specified as an int.
  135. * The returned value will be a non
  136. * pre-multiplied value. If the alpha is premultiplied, this method
  137. * divides it out before returning the value (if the alpha value is 0,
  138. * the green value will be 0).
  139. *
  140. * @param pixel The pixel from which you want to get the green color component.
  141. *
  142. * @return The green color component for the specified pixel, as an int.
  143. *
  144. * @throws IllegalArgumentException If there is more than
  145. * one component in this <CODE>ColorModel</CODE>.
  146. */
  147. public int getGreen(int pixel) {
  148. if (numComponents > 1) {
  149. throw new
  150. IllegalArgumentException("More than one component per pixel");
  151. }
  152. // Since there is only 1 component, there is no alpha
  153. // Normalize the pixel in order to convert it
  154. float[] norm = { (float) pixel / ((1<<nBits[0]) - 1) };
  155. float[] rgb = colorSpace.toRGB(norm);
  156. return (int) rgb[1]*255;
  157. }
  158. /**
  159. * Returns the blue color component for the specified pixel, scaled
  160. * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
  161. * is done if necessary. The pixel value is specified as an int.
  162. * The returned value will be a non
  163. * pre-multiplied value. If the alpha is premultiplied, this method
  164. * divides it out before returning the value (if the alpha value is 0,
  165. * the blue value will be 0).
  166. *
  167. * @param pixel The pixel from which you want to get the blue color component.
  168. *
  169. * @return The blue color component for the specified pixel, as an int.
  170. *
  171. * @throws IllegalArgumentException If there is more than
  172. * one component in this <CODE>ColorModel</CODE>.
  173. */
  174. public int getBlue(int pixel) {
  175. if (numComponents > 1) {
  176. throw new
  177. IllegalArgumentException("More than one component per pixel");
  178. }
  179. // Since there is only 1 component, there is no alpha
  180. // Normalize the pixel in order to convert it
  181. float[] norm = { (float) pixel / ((1<<nBits[0]) - 1) };
  182. float[] rgb = colorSpace.toRGB(norm);
  183. return (int) rgb[2]*255;
  184. }
  185. /**
  186. * Returns the alpha component for the specified pixel, scaled
  187. * from 0 to 255. The pixel value is specified as an int.
  188. *
  189. * @param pixel The pixel from which you want to get the alpha component.
  190. *
  191. * @return The alpha component for the specified pixel, as an int.
  192. *
  193. * @throws IllegalArgumentException If there is more than
  194. * one component in this <CODE>ColorModel</CODE>.
  195. */
  196. public int getAlpha(int pixel) {
  197. if (supportsAlpha == false) {
  198. return 255;
  199. }
  200. if (numComponents > 1) {
  201. throw new
  202. IllegalArgumentException("More than one component per pixel");
  203. }
  204. return (pixel((1<<nBits[0])-1))*255;
  205. }
  206. /**
  207. * Returns the color/alpha components of the pixel in the default
  208. * RGB color model format. A color conversion is done if necessary.
  209. * The returned value will be in a non pre-multiplied format. If
  210. * the alpha is premultiplied, this method divides it out of the
  211. * color components (if the alpha value is 0, the color values will be 0).
  212. *
  213. * @param pixel The pixel from which you want to get the color/alpha components.
  214. *
  215. * @return The color/alpha components for the specified pixel, as an int.
  216. *
  217. * @throws IllegalArgumentException If there is more than
  218. * one component in this <CODE>ColorModel</CODE>.
  219. */
  220. public int getRGB(int pixel) {
  221. if (numComponents > 1) {
  222. throw new
  223. IllegalArgumentException("More than one component per pixel");
  224. }
  225. return (getAlpha(pixel) << 24)
  226. | (getRed(pixel) << 16)
  227. | (getGreen(pixel) << 8)
  228. | (getBlue(pixel) << 0);
  229. }
  230. /**
  231. * Returns the red color component for the specified pixel, scaled
  232. * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion
  233. * is done if necessary. The <CODE>pixel</CODE> value is specified by an array
  234. * of data elements of type <CODE>transferType</CODE> passed in as an object
  235. * reference. The returned value will be a non pre-multiplied value. If the
  236. * alpha is premultiplied, this method divides it out before returning
  237. * the value (if the alpha value is 0, the red value will be 0).
  238. *
  239. * @param inData The pixel from which you want to get the red color component,
  240. * specified by an array of data elements of type <CODE>transferType</CODE>.
  241. *
  242. * @return The red color component for the specified pixel, as an int.
  243. *
  244. * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
  245. * of type <CODE>transferType</CODE>.
  246. * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
  247. * large enough to hold a pixel value for this
  248. * <CODE>ColorModel</CODE>.
  249. * @throws UnsupportedOperationException If the transfer type of
  250. * this <CODE>ComponentColorModel</CODE> is not one of the supported transfer
  251. * types: <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  252. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  253. */
  254. public int getRed(Object inData) {
  255. // REMIND: Should this be CS_sRGB or TYPE_RGB?
  256. if (colorSpaceType == ColorSpace.TYPE_RGB) {
  257. boolean needAlpha = (supportsAlpha && isAlphaPremultiplied);
  258. int alp = 0;
  259. int red = 0;
  260. switch (transferType) {
  261. case DataBuffer.TYPE_BYTE:
  262. byte bdata[] = (byte[])inData;
  263. red = bdata[0] & 0xff;
  264. if (needAlpha) {
  265. alp = bdata[numColorComponents] & 0xff;
  266. }
  267. break;
  268. case DataBuffer.TYPE_USHORT:
  269. short sdata[] = (short[])inData;
  270. red = sdata[0]&0xffff;
  271. if (needAlpha) {
  272. alp = sdata[numColorComponents] & 0xffff;
  273. }
  274. break;
  275. case DataBuffer.TYPE_INT:
  276. int idata[] = (int[])inData;
  277. red = idata[0];
  278. if (needAlpha) {
  279. alp = idata[numColorComponents];
  280. }
  281. break;
  282. default:
  283. throw new
  284. UnsupportedOperationException("This method has not "+
  285. "been implemented for transferType " + transferType);
  286. }
  287. if (nBits[0] != 8) {
  288. int shift = nBits[0] - 8;
  289. red = ((shift > 0)
  290. ? (red>>shift)
  291. : (red<<(-shift)));
  292. }
  293. if (needAlpha) {
  294. return (int) (red*((1<<nBits[numColorComponents])-1.f)/alp);
  295. }
  296. else {
  297. return red;
  298. }
  299. }
  300. else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
  301. return getGray(inData);
  302. }
  303. // Not TYPE_GRAY or TYPE_RGB ColorSpace
  304. int pixel[];
  305. if (inData instanceof int[]) {
  306. pixel = (int[])inData;
  307. } else {
  308. pixel = DataBuffer.toIntArray(inData);
  309. if (pixel == null) {
  310. throw new UnsupportedOperationException("This method has not been "+
  311. "implemented for transferType " + transferType);
  312. }
  313. }
  314. // Normalize the pixel in order to convert it
  315. float[] norm = getNormalizedComponents(pixel, 0, null, 0);
  316. float[] rgb = colorSpace.toRGB(norm);
  317. int color;
  318. if (isAlphaPremultiplied && supportsAlpha) {
  319. color = (int) (rgb[0]*255*norm[numColorComponents]);
  320. }
  321. else {
  322. color = (int) rgb[0]*255;
  323. }
  324. return color;
  325. }
  326. /**
  327. * Returns the green color component for the specified pixel, scaled
  328. * from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB.
  329. * A color conversion is done if necessary. The <CODE>pixel</CODE> value
  330. * is specified by an array of data elements of type <CODE>transferType</CODE>
  331. * passed in as an object reference. The returned value is a non pre-multiplied
  332. * value. If the alpha is premultiplied, this method divides it out before
  333. * returning the value (if the alpha value is 0, the green value will be 0).
  334. *
  335. * @param inData The pixel from which you want to get the green color component,
  336. * specified by an array of data elements of type <CODE>transferType</CODE>.
  337. *
  338. * @return The green color component for the specified pixel, as an int.
  339. *
  340. * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
  341. * of type <CODE>transferType</CODE>.
  342. * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
  343. * large enough to hold a pixel value for this
  344. * <CODE>ColorModel</CODE>.
  345. * @throws UnsupportedOperationException If the transfer type of
  346. * this <CODE>ComponentColorModel</CODE>
  347. * is not one of the supported transfer types:
  348. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  349. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  350. */
  351. public int getGreen(Object inData) {
  352. // REMIND: Should this be CS_sRGB or TYPE_RGB?
  353. if (colorSpaceType == ColorSpace.TYPE_RGB) {
  354. boolean needAlpha = (supportsAlpha && isAlphaPremultiplied);
  355. int alp = 0;
  356. int green = 0;
  357. switch (transferType) {
  358. case DataBuffer.TYPE_BYTE:
  359. byte bdata[] = (byte[])inData;
  360. green = bdata[1] & 0xff;
  361. if (needAlpha) {
  362. alp = bdata[numColorComponents] & 0xff;
  363. }
  364. break;
  365. case DataBuffer.TYPE_USHORT:
  366. short sdata[] = (short[])inData;
  367. green = sdata[1] & 0xffff;
  368. if (needAlpha) {
  369. alp = sdata[numColorComponents] & 0xffff;
  370. }
  371. break;
  372. case DataBuffer.TYPE_INT:
  373. int idata[] = (int[])inData;
  374. green = idata[1];
  375. if (needAlpha) {
  376. alp = idata[numColorComponents];
  377. }
  378. break;
  379. default:
  380. throw new
  381. UnsupportedOperationException("This method has not "+
  382. "been implemented for transferType " + transferType);
  383. }
  384. if (nBits[1] != 8) {
  385. int shift = nBits[1] - 8;
  386. green = ((shift > 0)
  387. ? (green>>shift)
  388. : (green<<(-shift)));
  389. }
  390. if (needAlpha) {
  391. return (int) (green*((1<<nBits[numColorComponents])-1.f)/alp);
  392. }
  393. else {
  394. return green;
  395. }
  396. }
  397. else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
  398. return getGray(inData);
  399. }
  400. int pixel[];
  401. if (inData instanceof int[]) {
  402. pixel = (int[])inData;
  403. } else {
  404. pixel = DataBuffer.toIntArray(inData);
  405. if (pixel == null) {
  406. throw new UnsupportedOperationException("This method has not been "+
  407. "implemented for transferType " + transferType);
  408. }
  409. }
  410. // Normalize the pixel in order to convert it
  411. float[] norm = getNormalizedComponents(pixel, 0, null, 0);
  412. float[] rgb = colorSpace.toRGB(norm);
  413. int color;
  414. if (isAlphaPremultiplied && supportsAlpha) {
  415. color = (int) (rgb[1]*255*norm[numColorComponents]);
  416. }
  417. else {
  418. color = (int) rgb[1]*255;
  419. }
  420. return color;
  421. }
  422. /**
  423. * Returns the blue color component for the specified pixel, scaled
  424. * from 0 to 255 in the default RGB <CODE>ColorSpace</CODE>, sRGB.
  425. * A color conversion is done if necessary. The <CODE>pixel</CODE> value is
  426. * specified by an array of data elements of type <CODE>transferType</CODE>
  427. * passed in as an object reference. The returned value is a non pre-multiplied
  428. * value. If the alpha is premultiplied, this method divides it out before
  429. * returning the value (if the alpha value is 0, the blue value will be 0).
  430. *
  431. * @param inData The pixel from which you want to get the blue color component,
  432. * specified by an array of data elements of type <CODE>transferType</CODE>.
  433. *
  434. * @return The blue color component for the specified pixel, as an int.
  435. *
  436. * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
  437. * of type <CODE>transferType</CODE>.
  438. * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
  439. * large enough to hold a pixel value for this
  440. * <CODE>ColorModel</CODE>.
  441. * @throws UnsupportedOperationException If the transfer type of
  442. * this <CODE>ComponentColorModel</CODE>
  443. * is not one of the supported transfer types:
  444. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  445. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  446. */
  447. public int getBlue(Object inData) {
  448. // REMIND: Should this be CS_sRGB or TYPE_RGB?
  449. if (colorSpaceType == ColorSpace.TYPE_RGB) {
  450. boolean needAlpha = (supportsAlpha && isAlphaPremultiplied);
  451. int alp = 0;
  452. int blue = 0;
  453. switch (transferType) {
  454. case DataBuffer.TYPE_BYTE:
  455. byte bdata[] = (byte[])inData;
  456. blue = bdata[2] & 0xff;
  457. if (needAlpha) {
  458. alp = bdata[numColorComponents] & 0xff;
  459. }
  460. break;
  461. case DataBuffer.TYPE_USHORT:
  462. short sdata[] = (short[])inData;
  463. blue = sdata[2] & 0xffff;
  464. if (needAlpha) {
  465. alp = sdata[numColorComponents] & 0xffff;
  466. }
  467. break;
  468. case DataBuffer.TYPE_INT:
  469. int idata[] = (int[])inData;
  470. blue = idata[2];
  471. if (needAlpha) {
  472. alp = idata[numColorComponents];
  473. }
  474. break;
  475. default:
  476. throw new
  477. UnsupportedOperationException("This method has not "+
  478. "been implemented for transferType " + transferType);
  479. }
  480. if (nBits[2] != 8) {
  481. int shift = nBits[2] - 8;
  482. return ((shift > 0)
  483. ? (blue>>shift)
  484. : (blue<<(-shift)));
  485. }
  486. if (needAlpha) {
  487. return (int) (blue*((1<<nBits[numColorComponents])-1.f)/alp);
  488. }
  489. else {
  490. return blue;
  491. }
  492. }
  493. else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
  494. return getGray(inData);
  495. }
  496. int pixel[];
  497. if (inData instanceof int[]) {
  498. pixel = (int[])inData;
  499. } else {
  500. pixel = DataBuffer.toIntArray(inData);
  501. if (pixel == null) {
  502. throw new UnsupportedOperationException("This method has not been "+
  503. "implemented for transferType " + transferType);
  504. }
  505. }
  506. // Normalize the pixel in order to convert it
  507. float[] norm = getNormalizedComponents(pixel, 0, null, 0);
  508. float[] rgb = colorSpace.toRGB(norm);
  509. int color;
  510. if (isAlphaPremultiplied && supportsAlpha) {
  511. color = (int) (rgb[2]*255*norm[numColorComponents]);
  512. }
  513. else {
  514. color = (int) rgb[2]*255;
  515. }
  516. return color;
  517. }
  518. /**
  519. * Returns the alpha component for the specified pixel, scaled from
  520. * 0 to 255. The pixel value is specified by an array of data
  521. * elements of type <CODE>transferType</CODE> passed in as an
  522. * object reference.
  523. *
  524. * @param inData The pixel from which you want to get the alpha component,
  525. * specified by an array of data elements of type <CODE>transferType</CODE>.
  526. *
  527. * @return The alpha component for the specified pixel, as an int.
  528. *
  529. * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
  530. * of type <CODE>transferType</CODE>.
  531. * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
  532. * large enough to hold a pixel value for this
  533. * <CODE>ColorModel</CODE>.
  534. * @throws UnsupportedOperationException If the transfer type of
  535. * this <CODE>ComponentColorModel</CODE>
  536. * is not one of the supported transfer types:
  537. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  538. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  539. */
  540. public int getAlpha(Object inData) {
  541. if (supportsAlpha == false) {
  542. return 255;
  543. }
  544. int alpha = 0;
  545. int aIdx = numColorComponents;
  546. switch (transferType) {
  547. case DataBuffer.TYPE_BYTE:
  548. byte bdata[] = (byte[])inData;
  549. alpha = bdata[aIdx] & 0xff;
  550. break;
  551. case DataBuffer.TYPE_USHORT:
  552. short sdata[] = (short[])inData;
  553. alpha = sdata[aIdx]&0xffff;
  554. break;
  555. case DataBuffer.TYPE_INT:
  556. int idata[] = (int[])inData;
  557. alpha = idata[aIdx];
  558. break;
  559. default:
  560. throw new
  561. UnsupportedOperationException("This method has not "+
  562. "been implemented for transferType " + transferType);
  563. }
  564. if (nBits[aIdx] == 8) {
  565. return alpha;
  566. }
  567. else {
  568. int shift = nBits[aIdx] - 8;
  569. return ((shift > 0)
  570. ? (alpha>>shift)
  571. : (alpha<<(-shift)));
  572. }
  573. }
  574. // This method returns a gray color that can be mapped to
  575. // RGB values in getRGB(). It assumes that the colorspace is TYPE_GRAY.
  576. private int getGray(Object inData) {
  577. boolean needAlpha = (supportsAlpha && isAlphaPremultiplied);
  578. int alp = 0;
  579. int gray;
  580. switch (transferType) {
  581. case DataBuffer.TYPE_BYTE:
  582. byte bdata[] = (byte[])inData;
  583. gray = bdata[0] & 0xff;
  584. if (needAlpha) {
  585. alp = bdata[1]&0xff;
  586. }
  587. break;
  588. case DataBuffer.TYPE_USHORT:
  589. short sdata[] = (short[])inData;
  590. gray = sdata[0] & 0xffff;
  591. if (needAlpha) {
  592. alp = sdata[1]&0xff;
  593. }
  594. break;
  595. case DataBuffer.TYPE_INT:
  596. int idata[] = (int[])inData;
  597. gray = idata[0];
  598. if (needAlpha) {
  599. alp = idata[1]&0xff;
  600. }
  601. break;
  602. default:
  603. throw new UnsupportedOperationException("This method has not been"+
  604. " implemented for transferType " +
  605. transferType);
  606. }
  607. if (nBits[0] != 8) {
  608. int shift = nBits[0] - 8;
  609. gray = ((shift > 0)
  610. ? (gray>>shift)
  611. : (gray<<(-shift)));
  612. }
  613. return (!needAlpha
  614. ? gray
  615. : (int)(gray*(1<<nBits[numColorComponents])-1.f)/alp
  616. );
  617. }
  618. private float getNormAlpha(int pixel[]) {
  619. return (float) (pixel[numColorComponents] /
  620. ((1<<nBits[numColorComponents])-1.f));
  621. }
  622. /**
  623. * Returns the color/alpha components for the specified pixel in the
  624. * default RGB color model format. A color conversion is done if
  625. * necessary. The pixel value is specified by an
  626. * array of data elements of type <CODE>transferType</CODE> passed
  627. * in as an object reference.
  628. * The returned value is in a non pre-multiplied format. If
  629. * the alpha is premultiplied, this method divides it out of the
  630. * color components (if the alpha value is 0, the color values will be 0).
  631. *
  632. * @param inData The pixel from which you want to get the color/alpha components,
  633. * specified by an array of data elements of type <CODE>transferType</CODE>.
  634. *
  635. * @return The color/alpha components for the specified pixel, as an int.
  636. *
  637. * @throws ClassCastException If <CODE>inData</CODE> is not a primitive array
  638. * of type <CODE>transferType</CODE>.
  639. * @throws ArrayIndexOutOfBoundsException if <CODE>inData</CODE> is not
  640. * large enough to hold a pixel value for this
  641. * <CODE>ColorModel</CODE>.
  642. * @throws UnsupportedOperationException If the transfer type of
  643. * this <CODE>ComponentColorModel</CODE>
  644. * is not one of the supported transfer types:
  645. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  646. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  647. * @see ColorModel#getRGBdefault
  648. */
  649. public int getRGB(Object inData) {
  650. if (colorSpaceType == ColorSpace.TYPE_GRAY) {
  651. int gray = getGray(inData);
  652. return (getAlpha(inData) << 24)
  653. | (gray << 16)
  654. | (gray << 8)
  655. | gray;
  656. }
  657. return (getAlpha(inData) << 24)
  658. | (getRed(inData) << 16)
  659. | (getGreen(inData) << 8)
  660. | (getBlue(inData));
  661. }
  662. /**
  663. * Returns a data element array representation of a pixel in this
  664. * <CODE>ColorModel</CODE>, given an integer pixel representation
  665. * in the default RGB color model.
  666. * This array can then be passed to the <CODE>setDataElements</CODE>
  667. * method of a <CODE>WritableRaster</CODE> object. If the <CODE>pixel</CODE>
  668. * parameter is null, a new array is allocated.
  669. *
  670. * @param rgb
  671. * @param pixel The integer representation of the pixel.
  672. *
  673. * @throws ClassCastException If <CODE>pixel</CODE> is not null and
  674. * is not a primitive array of type <CODE>transferType</CODE>.
  675. * @throws ArrayIndexOutOfBoundsException If <CODE>pixel</CODE> is
  676. * not large enough to hold a pixel value for this
  677. * <CODE>ColorModel</CODE>.
  678. * @throws UnsupportedOperationException If the transfer type of
  679. * this <CODE>ComponentColorModel</CODE>
  680. * is not one of the supported transfer types:
  681. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  682. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  683. *
  684. * @see WritableRaster#setDataElements
  685. * @see SampleModel#setDataElements
  686. */
  687. public Object getDataElements(int rgb, Object pixel) {
  688. //REMIND: maybe more efficient not to use int array for
  689. //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT
  690. int intpixel[] = null;
  691. if (transferType == DataBuffer.TYPE_INT &&
  692. pixel != null) {
  693. intpixel = (int[])pixel;
  694. } else {
  695. intpixel = new int[numComponents];
  696. }
  697. // REMIND: Use rendering hints?
  698. if (! is_sRGB) {
  699. if (colorSpaceType == ColorSpace.TYPE_GRAY) {
  700. double gray = ((((rgb>>16)&0xff)*.299/255) +
  701. (((rgb>>8) &0xff)*.587/255) +
  702. (((rgb) &0xff)*.114/255));
  703. intpixel[0] = (int) (gray * (1 << nBits[0]));
  704. if (supportsAlpha) {
  705. if (nBits[1] == 8) {
  706. intpixel[1] = (rgb>>24)&0xff;
  707. }
  708. else {
  709. intpixel[1] =
  710. (int)(((rgb>>24)&0xff)/255.f * ((1<<nBits[1])-1));
  711. }
  712. }
  713. }
  714. else {
  715. // Need to convert the color
  716. float[] norm = new float[3];
  717. norm[0] = ((rgb>>16)&0xff)/255.f;
  718. norm[1] = ((rgb>>8)&0xff)/255.f;
  719. norm[2] = ((rgb>>0)&0xff)/255.f;
  720. norm = colorSpace.fromRGB(norm);
  721. for (int i = 0; i < numColorComponents; i++) {
  722. intpixel[i] = (int)(norm[i]*((1<<nBits[i]) - 1));
  723. }
  724. if (supportsAlpha) {
  725. if (nBits[numColorComponents] == 8) {
  726. intpixel[numColorComponents] = (rgb>>24)&0xff;
  727. }
  728. else {
  729. intpixel[numColorComponents] =
  730. (int)(((rgb>>24)&0xff)/255.f * ((1<<nBits[1])-1));
  731. }
  732. }
  733. }
  734. }
  735. else {
  736. int alp = (rgb>>24)&0xff;
  737. int red = (rgb>>16)&0xff;
  738. int grn = (rgb>>8) &0xff;
  739. int blu = (rgb) &0xff;
  740. if (isAlphaPremultiplied) {
  741. float norm = alp255.f;
  742. if (nBits[0] == 8) {
  743. intpixel[0] = (int)(red*norm);
  744. }
  745. else {
  746. intpixel[0] = (int)((red*norm)/255.f * ((1<<nBits[0])-1));
  747. }
  748. if (nBits[1] == 8) {
  749. intpixel[1] = (int)(grn*norm);
  750. }
  751. else {
  752. intpixel[1] = (int)((grn*norm)/255.f * ((1<<nBits[1])-1));
  753. }
  754. if (nBits[2] == 8) {
  755. intpixel[2] = (int)(blu*norm);
  756. }
  757. else {
  758. intpixel[2] = (int)((blu*norm)/255.f * ((1<<nBits[2])-1));
  759. }
  760. if (supportsAlpha) {
  761. if (nBits[3] == 8) {
  762. intpixel[3] = alp;
  763. }
  764. else {
  765. intpixel[3] = (int)(norm * ((1<<nBits[3])-1));
  766. }
  767. }
  768. }
  769. else {
  770. if (nBits[0] == 8) {
  771. intpixel[0] = red;
  772. }
  773. else {
  774. intpixel[0] = (int)(red255.f * ((1<<nBits[0])-1));
  775. }
  776. if (nBits[1] == 8) {
  777. intpixel[1] = (int)(grn);
  778. }
  779. else {
  780. intpixel[1] = (int)(grn255.f * ((1<<nBits[1])-1));
  781. }
  782. if (nBits[2] == 8) {
  783. intpixel[2] = (int)(blu);
  784. }
  785. else {
  786. intpixel[2] = (int)(blu255.f * ((1<<nBits[2])-1));
  787. }
  788. if (supportsAlpha) {
  789. if (nBits[3] == 8) {
  790. intpixel[3] = alp;
  791. }
  792. else {
  793. intpixel[3] = (int)(alp255.f * ((1<<nBits[3])-1));
  794. }
  795. }
  796. }
  797. }
  798. switch (transferType) {
  799. case DataBuffer.TYPE_BYTE: {
  800. byte bdata[];
  801. if (pixel == null) {
  802. bdata = new byte[numComponents];
  803. } else {
  804. bdata = (byte[])pixel;
  805. }
  806. for (int i = 0; i < numComponents; i++) {
  807. bdata[i] = (byte)(0xff&intpixel[i]);
  808. }
  809. return bdata;
  810. }
  811. case DataBuffer.TYPE_USHORT:{
  812. short sdata[];
  813. if (pixel == null) {
  814. sdata = new short[numComponents];
  815. } else {
  816. sdata = (short[])pixel;
  817. }
  818. for (int i = 0; i < numComponents; i++) {
  819. sdata[i] = (short)(intpixel[i]&0xffff);
  820. }
  821. return sdata;
  822. }
  823. case DataBuffer.TYPE_INT:
  824. return intpixel;
  825. }
  826. throw new IllegalArgumentException("This method has not been "+
  827. "implemented for transferType " + transferType);
  828. }
  829. /** Returns an array of unnormalized color/alpha components given a pixel
  830. * in this <CODE>ColorModel</CODE>. Color/alpha components are
  831. * stored in the <CODE>components</CODE> array starting at <CODE>offset</CODE>
  832. * (even if the array is allocated by this method).
  833. *
  834. * @param pixel The pixel value specified as an integer.
  835. * @param components An integer array in which to store the unnormalized
  836. * color/alpha components. If the <CODE>components</CODE> array is null,
  837. * a new array is allocated.
  838. * @param offset An offset into the <CODE>components</CODE> array.
  839. *
  840. * @return The components array.
  841. *
  842. * @throws IllegalArgumentException If there is more than one
  843. * component in this <CODE>ColorModel</CODE>.
  844. * @throws ArrayIndexOutOfBoundsException If the <CODE>components</CODE>
  845. * array is not null and is not large enough to hold all the color and
  846. * alpha components (starting at offset).
  847. */
  848. public int[] getComponents(int pixel, int[] components, int offset) {
  849. if (numComponents > 1) {
  850. throw new
  851. IllegalArgumentException("More than one component per pixel");
  852. }
  853. if (components == null) {
  854. components = new int[offset+1];
  855. }
  856. components[offset+0] = (pixel & ((1<<nBits[0]) - 1));
  857. return components;
  858. }
  859. /**
  860. * Returns an array of unnormalized color/alpha components given a pixel
  861. * in this <CODE>ColorModel</CODE>. The pixel value is specified by an
  862. * array of data elements of type <CODE>transferType</CODE> passed in as
  863. * an object reference.
  864. * Color/alpha components are stored in the <CODE>components</CODE> array
  865. * starting at <CODE>offset</CODE> (even if the array is allocated by
  866. * this method).
  867. *
  868. * @param pixel A pixel value specified by an array of data elements of
  869. * type <CODE>transferType</CODE>.
  870. * @param components An integer array in which to store the unnormalized
  871. * color/alpha components. If the <CODE>components</CODE> array is null,
  872. * a new array is allocated.
  873. * @param offset An offset into the <CODE>components</CODE> array.
  874. *
  875. * @return The <CODE>components</CODE> array.
  876. *
  877. * @throws UnsupportedOperationException If the transfer type of
  878. * this <CODE>ComponentColorModel</CODE>
  879. * is not one of the supported transfer types:
  880. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  881. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  882. * @throws ClassCastException If <CODE>pixel</CODE> is not a primitive
  883. * array of type <CODE>transferType</CODE>.
  884. * @throws IllegalArgumentException If the <CODE>components</CODE> array is
  885. * not null and is not large enough to hold all the color and alpha
  886. * components (starting at offset), or if <CODE>pixel</CODE> is not large
  887. * enough to hold a pixel value for this ColorModel.
  888. */
  889. public int[] getComponents(Object pixel, int[] components, int offset) {
  890. int intpixel[];
  891. if (pixel instanceof int[]) {
  892. intpixel = (int[])pixel;
  893. } else {
  894. intpixel = DataBuffer.toIntArray(pixel);
  895. if (intpixel == null) {
  896. throw new UnsupportedOperationException("This method has not been "+
  897. "implemented for transferType " + transferType);
  898. }
  899. }
  900. if (intpixel.length < numComponents) {
  901. throw new IllegalArgumentException
  902. ("Length of pixel array < number of components in model");
  903. }
  904. if (components == null) {
  905. components = new int[offset+numComponents];
  906. }
  907. else if ((components.length-offset) < numComponents) {
  908. throw new IllegalArgumentException
  909. ("Length of components array < number of components in model");
  910. }
  911. System.arraycopy(intpixel, 0, components, offset, numComponents);
  912. return components;
  913. }
  914. /**
  915. * Returns a pixel value represented as an int in this <CODE>ColorModel</CODE>,
  916. * given an array of unnormalized color/alpha components.
  917. *
  918. * @param components An array of unnormalized color/alpha components.
  919. * @param offset An offset into the <CODE>components</CODE> array.
  920. *
  921. * @return A pixel value represented as an int.
  922. *
  923. * @throws IllegalArgumentException If there is more than one component
  924. * in this <CODE>ColorModel</CODE>.
  925. */
  926. public int getDataElement(int[] components, int offset) {
  927. if (numComponents == 1) {
  928. return components[offset+0];
  929. }
  930. throw new IllegalArgumentException("This model returns "+
  931. numComponents+
  932. " elements in the pixel array.");
  933. }
  934. /**
  935. * Returns a data element array representation of a pixel in this
  936. * <CODE>ColorModel</CODE>, given an array of unnormalized color/alpha
  937. * components. This array can then be passed to the <CODE>setDataElements</CODE>
  938. * method of a <CODE>WritableRaster</CODE> object.
  939. *
  940. * @param components An array of unnormalized color/alpha components.
  941. * @param offset The integer offset into the <CODE>components</CODE> array.
  942. * @param obj The object in which to store the data element array
  943. * representation of the pixel. If <CODE>obj</CODE> variable is null,
  944. * a new array is allocated. If <CODE>obj</CODE> is not null, it must
  945. * be a primitive array of type <CODE>transferType</CODE>. An
  946. * <CODE>ArrayIndexOutOfBoundsException</CODE> is thrown if
  947. * <CODE>obj</CODE> is not large enough to hold a pixel value
  948. * for this <CODE>ColorModel</CODE>.
  949. *
  950. * @return The data element array representation of a pixel
  951. * in this <CODE>ColorModel</CODE>.
  952. *
  953. * @throws IllegalArgumentException If the components array
  954. * is not large enough to hold all the color and alpha components
  955. * (starting at offset).
  956. * @throws ClassCastException If <CODE>obj</CODE> is not null and is not a
  957. * primitive array of type <CODE>transferType</CODE>.
  958. * @throws ArrayIndexOutOfBoundsException If <CODE>obj</CODE> is not large
  959. * enough to hold a pixel value for this <CODE>ColorModel</CODE>.
  960. * @throws UnsupportedOperationException If the transfer type of
  961. * this <CODE>ComponentColorModel</CODE>
  962. * is not one of the supported transfer types:
  963. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  964. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  965. *
  966. * @see WritableRaster#setDataElements
  967. * @see SampleModel#setDataElements
  968. */
  969. public Object getDataElements(int[] components, int offset, Object obj) {
  970. if ((components.length-offset) < numComponents) {
  971. throw new IllegalArgumentException("Component array too small"+
  972. " (should be "+numComponents);
  973. }
  974. switch(transferType) {
  975. case DataBuffer.TYPE_INT:
  976. {
  977. int[] pixel;
  978. if (obj == null) {
  979. pixel = new int[components.length];
  980. }
  981. else {
  982. pixel = (int[]) obj;
  983. }
  984. System.arraycopy(components, offset, pixel, 0,
  985. numComponents);
  986. return pixel;
  987. }
  988. case DataBuffer.TYPE_BYTE:
  989. {
  990. byte[] pixel;
  991. if (obj == null) {
  992. pixel = new byte[components.length];
  993. }
  994. else {
  995. pixel = (byte[]) obj;
  996. }
  997. for (int i=0; i < numComponents; i++) {
  998. pixel[i] = (byte) (components[offset+i]&0xff);
  999. }
  1000. return pixel;
  1001. }
  1002. case DataBuffer.TYPE_USHORT:
  1003. {
  1004. short[] pixel;
  1005. if (obj == null) {
  1006. pixel = new short[components.length];
  1007. }
  1008. else {
  1009. pixel = (short[]) obj;
  1010. }
  1011. for (int i=0; i < numComponents; i++) {
  1012. pixel[i] = (short) (components[offset+i]&0xffff);
  1013. }
  1014. return pixel;
  1015. }
  1016. default:
  1017. throw new UnsupportedOperationException("This method has not been "+
  1018. "implemented for transferType " +
  1019. transferType);
  1020. }
  1021. }
  1022. /**
  1023. * Forces the raster data to match the state specified in the
  1024. * <CODE>isAlphaPremultiplied</CODE> variable, assuming the data
  1025. * is currently correctly described by this <CODE>ColorModel</CODE>.
  1026. * It may multiply or divide the color raster data by alpha, or
  1027. * do nothing if the data is in the correct state. If the data needs
  1028. * to be coerced, this method also returns an instance of
  1029. * this <CODE>ColorModel</CODE> with
  1030. * the <CODE>isAlphaPremultiplied</CODE> flag set appropriately.
  1031. *
  1032. * @throws UnsupportedOperationException If the transfer type of
  1033. * this <CODE>ComponentColorModel</CODE>
  1034. * is not one of the supported transfer types:
  1035. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  1036. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  1037. *
  1038. * @throws UnsupportedOperationException If the transfer type of
  1039. * this <CODE>ComponentColorModel</CODE>
  1040. * is not one of the supported transfer types:
  1041. * <CODE>DataBuffer.TYPE_BYTE</CODE>, <CODE>DataBuffer.TYPE_USHORT</CODE>,
  1042. * or <CODE>DataBuffer.TYPE_INT</CODE>.
  1043. */
  1044. public ColorModel coerceData (WritableRaster raster,
  1045. boolean isAlphaPremultiplied) {
  1046. if ((supportsAlpha == false) ||
  1047. (this.isAlphaPremultiplied == isAlphaPremultiplied))
  1048. {
  1049. // Nothing to do
  1050. return this;
  1051. }
  1052. int w = raster.getWidth();
  1053. int h = raster.getHeight();
  1054. int aIdx = raster.getNumBands() - 1;
  1055. int alpha;
  1056. int rminX = raster.getMinX();
  1057. int rY = raster.getMinY();
  1058. int rX;
  1059. if (isAlphaPremultiplied) {
  1060. switch (transferType) {
  1061. case DataBuffer.TYPE_BYTE: {
  1062. byte pixel[] = null;
  1063. for (int y = 0; y < h; y++, rY++) {
  1064. rX = rminX;
  1065. for (int x = 0; x < w; x++, rX++) {
  1066. pixel = (byte[])raster.getDataElements(rX, rY,
  1067. pixel);
  1068. alpha = pixel[aIdx] & 0xff;
  1069. if (alpha != 0) {
  1070. for (int c=0; c < aIdx; c++) {
  1071. pixel[c] = (byte)((pixel[c]&0xff) * alpha);
  1072. }
  1073. raster.setDataElements(rX, rY, pixel);
  1074. }
  1075. }
  1076. }
  1077. }
  1078. break;
  1079. case DataBuffer.TYPE_USHORT: {
  1080. short pixel[] = null;
  1081. for (int y = 0; y < h; y++, rY++) {
  1082. rX = rminX;
  1083. for (int x = 0; x < w; x++, rX++) {
  1084. pixel = (short[])raster.getDataElements(rX, rY,
  1085. pixel);
  1086. alpha = pixel[aIdx] &0xffff;
  1087. if (alpha != 0) {
  1088. for (int c=0; c < aIdx; c++) {
  1089. pixel[c] = (short)
  1090. ((pixel[c]&0xffff) * alpha);
  1091. }
  1092. raster.setDataElements(rX, rY, pixel);
  1093. }
  1094. }
  1095. }
  1096. }
  1097. break;
  1098. case DataBuffer.TYPE_INT: {
  1099. int pixel[] = null;
  1100. for (int y = 0; y < h; y++, rY++) {
  1101. rX = rminX;
  1102. for (int x = 0; x < w; x++, rX++) {
  1103. pixel = (int[])raster.getDataElements(rX, rY,
  1104. pixel);
  1105. alpha = pixel[aIdx];
  1106. if (alpha != 0) {
  1107. for (int c=0; c < aIdx; c++) {
  1108. pixel[c] *= alpha;
  1109. }
  1110. raster.setDataElements(rX, rY, pixel);
  1111. }
  1112. }
  1113. }
  1114. }
  1115. break;
  1116. default:
  1117. throw new UnsupportedOperationException("This method has not been "+
  1118. "implemented for transferType " + transferType);
  1119. }
  1120. }
  1121. else {
  1122. // We are premultiplied and want to divide it out
  1123. switch (transferType) {
  1124. case DataBuffer.TYPE_BYTE: {
  1125. for (int y = 0; y < h; y++, rY++) {
  1126. rX = rminX;
  1127. for (int x = 0; x < w; x++, rX++) {
  1128. byte pixel[] = null;
  1129. pixel = (byte[])raster.getDataElements(rX, rY, pixel);
  1130. alpha = pixel[aIdx] & 0xff;
  1131. for (int c=0; c < aIdx; c++) {
  1132. if (alpha != 0) {
  1133. pixel[c] = (byte)
  1134. ((pixel[c]&0xff) / alpha);
  1135. }
  1136. }
  1137. raster.setDataElements(rX, rY, pixel);
  1138. }
  1139. }
  1140. }
  1141. break;
  1142. case DataBuffer.TYPE_USHORT: {
  1143. for (int y = 0; y < h; y++, rY++) {
  1144. rX = rminX;
  1145. for (int x = 0; x < w; x++, rX++) {
  1146. short pixel[] = null;
  1147. pixel = (short[])raster.getDataElements(rX, rY,
  1148. pixel);
  1149. alpha = pixel[aIdx] & 0xffff;
  1150. for (int c=0; c < aIdx; c++) {
  1151. if (alpha != 0) {
  1152. pixel[c] = (short)
  1153. ((pixel[c]&0xffff) / alpha);
  1154. }
  1155. }
  1156. raster.setDataElements(rX, rY, pixel);
  1157. }
  1158. }
  1159. }
  1160. break;
  1161. case DataBuffer.TYPE_INT: {
  1162. for (int y = 0; y < h; y++, rY++) {
  1163. rX = rminX;
  1164. for (int x = 0; x < w; x++, rX++) {
  1165. int pixel[] = null;
  1166. pixel = (int[])raster.getDataElements(rX, rY,
  1167. pixel);
  1168. alpha = pixel[aIdx];
  1169. for (int c=0; c < aIdx; c++) {
  1170. if (alpha != 0) {
  1171. pixel[c] /= alpha;
  1172. }
  1173. }
  1174. raster.setDataElements(rX, rY, pixel);
  1175. }
  1176. }
  1177. }
  1178. break;
  1179. default:
  1180. throw new UnsupportedOperationException("This method has not been "+
  1181. "implemented for transferType " + transferType);
  1182. }
  1183. }
  1184. // Return a new color model
  1185. return new ComponentColorModel(colorSpace, nBits, supportsAlpha,
  1186. isAlphaPremultiplied, transparency,
  1187. transferType);
  1188. }
  1189. /**
  1190. * Returns true if <CODE>raster</CODE> is compatible with this
  1191. * <CODE>ColorModel</CODE> false if it is not.
  1192. *
  1193. * @param raster The <CODE>Raster</CODE> object to test for compatibility.
  1194. *
  1195. * @return <CODE>true</CODE> if <CODE>raster</CODE> is compatible with this
  1196. * <CODE>ColorModel</CODE>, <CODE>false</CODE> if it is not.
  1197. */
  1198. public boolean isCompatibleRaster(Raster raster) {
  1199. boolean flag = true;
  1200. SampleModel sm = raster.getSampleModel();
  1201. if (sm instanceof ComponentSampleModel) {
  1202. if (sm.getNumBands() != getNumComponents()) {
  1203. return false;
  1204. }
  1205. for (int i=0; i<nBits.length; i++) {
  1206. if (sm.getSampleSize(i) < nBits[i])
  1207. flag = false;
  1208. }
  1209. }
  1210. else {
  1211. return false;
  1212. }
  1213. return ( (raster.getTransferType() == transferType) && flag);
  1214. }
  1215. /**
  1216. * Creates a <CODE>WritableRaster</CODE> with the specified width and height,
  1217. * that has a data layout (<CODE>SampleModel</CODE>) compatible with
  1218. * this <CODE>ColorModel</CODE>.
  1219. *
  1220. * @param w The width of the <CODE>WritableRaster</CODE> you want to create.
  1221. * @param h The height of the <CODE>WritableRaster</CODE> you want to create.
  1222. *
  1223. * @return A <CODE>WritableRaster</CODE> that is compatible with
  1224. * this <CODE>ColorModel</CODE>.
  1225. * @see WritableRaster
  1226. * @see SampleModel
  1227. */
  1228. public WritableRaster createCompatibleWritableRaster (int w, int h) {
  1229. int dataSize = w*h*numComponents;
  1230. WritableRaster raster = null;
  1231. // Create the raster
  1232. raster = Raster.createInterleavedRaster(transferType,
  1233. w, h,
  1234. numComponents, null);
  1235. return raster;
  1236. }
  1237. /**
  1238. * Creates a <CODE>SampleModel</CODE> with the specified width and height,
  1239. * that has a data layout compatible with this <CODE>ColorModel</CODE>.
  1240. *
  1241. * @param w The width of the <CODE>SampleModel</CODE> you want to create.
  1242. * @param h The height of the <CODE>SampleModel</CODE> you want to create.
  1243. *
  1244. * @return A <CODE>SampleModel</CODE> that is compatible with this
  1245. * <CODE>ColorModel</CODE>.
  1246. *
  1247. * @see SampleModel
  1248. */
  1249. public SampleModel createCompatibleSampleModel(int w, int h) {
  1250. int[] bandOffsets = new int[numComponents];
  1251. for (int i=0; i < numComponents; i++) {
  1252. bandOffsets[i] = 0;
  1253. }
  1254. return new PixelInterleavedSampleModel(transferType, w, h,
  1255. numComponents, w*numComponents,
  1256. bandOffsets);
  1257. }
  1258. /**
  1259. * Checks whether or not the specified <CODE>SampleModel</CODE>
  1260. * is compatible with this <CODE>ColorModel</CODE>.
  1261. *
  1262. * @param sm The <CODE>SampleModel</CODE> to test for compatibility.
  1263. *
  1264. * @return <CODE>true</CODE> if the <CODE>SampleModel</CODE> is
  1265. * compatible with this <CODE>ColorModel</CODE>, <CODE>false</CODE>
  1266. * if it is not.
  1267. *
  1268. * @see SampleModel
  1269. */
  1270. public boolean isCompatibleSampleModel(SampleModel sm) {
  1271. if (sm instanceof ComponentSampleModel) {
  1272. return false;
  1273. }
  1274. if (sm.getTransferType() != transferType) {
  1275. return false;
  1276. }
  1277. return true;
  1278. }
  1279. /**
  1280. * Returns a <CODE>Raster</CODE> representing the alpha channel of an image,
  1281. * extracted from the input <CODE>Raster</CODE>.
  1282. * This method assumes that <CODE>Raster</CODE> objects associated with
  1283. * this <CODE>ColorModel</CODE> store the alpha band, if present, as
  1284. * the last band of image data. Returns null if there is no separate spatial
  1285. * alpha channel associated with this <CODE>ColorModel</CODE>.
  1286. * This method creates a new <CODE>Raster</CODE>, but will share the data
  1287. * array.
  1288. *
  1289. * @param raster The <CODE>WritableRaster</CODE> from which to extract the
  1290. * alpha channel.
  1291. *
  1292. * @return A <CODE>WritableRaster</CODE> containing the image's alpha channel.
  1293. *
  1294. */
  1295. public WritableRaster getAlphaRaster(WritableRaster raster) {
  1296. if (hasAlpha() == false) {
  1297. return null;
  1298. }
  1299. int x = raster.getMinX();
  1300. int y = raster.getMinY();
  1301. int[] band = new int[1];
  1302. band[0] = raster.getNumBands() - 1;
  1303. return raster.createWritableChild(x, y, raster.getWidth(),
  1304. raster.getHeight(), x, y,
  1305. band);
  1306. }
  1307. /**
  1308. * Compares this color model with another for equality.
  1309. *
  1310. * @param obj The object to compare with this color model.
  1311. * @return <CODE>true</CODE> if the color model objects are equal,
  1312. * <CODE>false</CODE> if they are not.
  1313. */
  1314. public boolean equals(Object obj) {
  1315. if (!super.equals(obj)) {
  1316. return false;
  1317. }
  1318. if (obj.getClass() != getClass()) {
  1319. return false;
  1320. }
  1321. return true;
  1322. }
  1323. }