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