1. /*
  2. * @(#)ICC_ColorSpace.java 1.20 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. /**********************************************************************
  11. **********************************************************************
  12. **********************************************************************
  13. *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
  14. *** As an unpublished work pursuant to Title 17 of the United ***
  15. *** States Code. All rights reserved. ***
  16. **********************************************************************
  17. **********************************************************************
  18. **********************************************************************/
  19. package java.awt.color;
  20. import sun.awt.color.ICC_Transform;
  21. /**
  22. *
  23. * An implementation of the abstract ColorSpace class. This representation of
  24. * device independent and device dependent color spaces is based on the
  25. * International Color Consortium Specification ICC.1:1998-09, File Format for
  26. * Color Profiles, September 1998, and the addendum ICC.1A:1999-04, April 1999,
  27. * to that specification (see <A href="http://www.color.org">
  28. * http://www.color.org</A>).
  29. * <p>
  30. * Typically, a Color or ColorModel would be associated with an ICC
  31. * Profile which is either an input, display, or output profile (see
  32. * the ICC specification). There are other types of ICC Profiles, e.g.
  33. * abstract profiles, device link profiles, and named color profiles,
  34. * which do not contain information appropriate for representing the color
  35. * space of a color, image, or device (see ICC_Profile).
  36. * Attempting to create an ICC_ColorSpace object from an inappropriate ICC
  37. * Profile is an error.
  38. * <p>
  39. * ICC Profiles represent transformations from the color space of
  40. * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
  41. * Profiles of interest for tagging images or colors have a
  42. * PCS which is one of the device independent
  43. * spaces (one CIEXYZ space and two CIELab spaces) defined in the
  44. * ICC Profile Format Specification. Most profiles of interest
  45. * either have invertible transformations or explicitly specify
  46. * transformations going both directions. Should an ICC_ColorSpace
  47. * object be used in a way requiring a conversion from PCS to
  48. * the profile's native space and there is inadequate data to
  49. * correctly perform the conversion, the ICC_ColorSpace object will
  50. * produce output in the specified type of color space (e.g. TYPE_RGB,
  51. * TYPE_CMYK, etc.), but the specific color values of the output data
  52. * will be undefined.
  53. * <p>
  54. * The details of this class are not important for simple applets,
  55. * which draw in a default color space or manipulate and display
  56. * imported images with a known color space. At most, such applets
  57. * would need to get one of the default color spaces via
  58. * ColorSpace.getInstance().
  59. * <p>
  60. * @see ColorSpace
  61. * @see ICC_Profile
  62. */
  63. public class ICC_ColorSpace extends ColorSpace {
  64. private ICC_Profile thisProfile;
  65. // {to,from}{RGB,CIEXYZ} methods create and cache these when needed
  66. private transient ICC_Transform this2srgb;
  67. private transient ICC_Transform srgb2this;
  68. private transient ICC_Transform this2xyz;
  69. private transient ICC_Transform xyz2this;
  70. /**
  71. * Constructs a new ICC_ColorSpace from an ICC_Profile object.
  72. * @exception IllegalArgumentException if profile is inappropriate for
  73. * representing a ColorSpace.
  74. */
  75. public ICC_ColorSpace (ICC_Profile profile) {
  76. super (profile.getColorSpaceType(), profile.getNumComponents());
  77. int profileClass = profile.getProfileClass();
  78. /* REMIND - is NAMEDCOLOR OK? */
  79. if ((profileClass != ICC_Profile.CLASS_INPUT) &&
  80. (profileClass != ICC_Profile.CLASS_DISPLAY) &&
  81. (profileClass != ICC_Profile.CLASS_OUTPUT) &&
  82. (profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) &&
  83. (profileClass != ICC_Profile.CLASS_NAMEDCOLOR) ) {
  84. throw new IllegalArgumentException("Invalid profile type");
  85. }
  86. thisProfile = profile;
  87. }
  88. /**
  89. * Returns the ICC_Profile for this ICC_ColorSpace.
  90. */
  91. public ICC_Profile getProfile() {
  92. return thisProfile;
  93. }
  94. /**
  95. * Transforms a color value assumed to be in this ColorSpace
  96. * into a value in the default CS_sRGB color space.
  97. * <p>
  98. * This method transforms color values using algorithms designed
  99. * to produce the best perceptual match between input and output
  100. * colors. In order to do colorimetric conversion of color values,
  101. * you should use the <code>toCIEXYZ</code>
  102. * method of this color space to first convert from the input
  103. * color space to the CS_CIEXYZ color space, and then use the
  104. * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
  105. * convert from CS_CIEXYZ to the output color space.
  106. * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
  107. * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
  108. * <p>
  109. * @param colorvalue a float array with length of at least the number
  110. of components in this ColorSpace.
  111. * @return a float array of length 3.
  112. */
  113. public float[] toRGB (float[] colorvalue) {
  114. ICC_Transform[] transformList;
  115. float[] result;
  116. ICC_ColorSpace srgbCS;
  117. if (this2srgb == null) {
  118. transformList = new ICC_Transform [2];
  119. srgbCS = (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
  120. transformList[0] = new ICC_Transform (
  121. thisProfile, ICC_Transform.Any, ICC_Transform.In);
  122. transformList[1] = new ICC_Transform (
  123. srgbCS.getProfile(), ICC_Transform.Any, ICC_Transform.Out);
  124. this2srgb = new ICC_Transform (transformList);
  125. }
  126. float[] tmp;
  127. if (ColorSpace.isCS_CIEXYZ(this)) {
  128. // Fix for 4267139. We do a specific fix here for the fact that the
  129. // ICC encoding for CIEXYZ maps to a range of 0.0 to 2.0, rather than
  130. // 0.0 to 1.0 to allow for X and Z values greater than 1.0 (Y values
  131. // should never be greater than 1.0). What this means is that the
  132. // Y values passed to xyz2this.colorConvert (1, tmp, result)
  133. // should range from 0.0 to 0.5, so they need to be halved here.
  134. // REMIND: The only encoding we can know about right now that
  135. // requires this fix (given our interfaces to the underlying CMM)
  136. // is CIEXYZ, but this probably needs a more general long-term fix.
  137. tmp = new float[3];
  138. float ALMOST_ONE_HALF = 1.0f / (1.0f + (32767.0f / 32768.0f));
  139. tmp[0] = colorvalue[0] * ALMOST_ONE_HALF;
  140. tmp[1] = colorvalue[1] * ALMOST_ONE_HALF;
  141. tmp[2] = colorvalue[2] * ALMOST_ONE_HALF;
  142. } else {
  143. tmp = colorvalue;
  144. }
  145. result = new float [3];
  146. this2srgb.colorConvert (1, tmp, result);
  147. return result;
  148. }
  149. /**
  150. * Transforms a color value assumed to be in the default CS_sRGB
  151. * color space into this ColorSpace.
  152. * <p>
  153. * This method transforms color values using algorithms designed
  154. * to produce the best perceptual match between input and output
  155. * colors. In order to do colorimetric conversion of color values,
  156. * you should use the <code>toCIEXYZ</code>
  157. * method of the CS_sRGB color space to first convert from the input
  158. * color space to the CS_CIEXYZ color space, and then use the
  159. * <code>fromCIEXYZ</code> method of this color space to
  160. * convert from CS_CIEXYZ to the output color space.
  161. * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
  162. * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
  163. * <p>
  164. * @param rgbvalue a float array with length of at least 3.
  165. * @return a float array with length equal to the number of
  166. components in this ColorSpace.
  167. */
  168. public float[] fromRGB(float[] rgbvalue) {
  169. ICC_Transform[] transformList;
  170. float[] result;
  171. ICC_ColorSpace srgbCS;
  172. if (srgb2this == null) {
  173. transformList = new ICC_Transform [2];
  174. srgbCS = (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
  175. transformList[0] = new ICC_Transform (
  176. srgbCS.getProfile(), ICC_Transform.Any, ICC_Transform.In);
  177. transformList[1] = new ICC_Transform (
  178. thisProfile, ICC_Transform.Any, ICC_Transform.Out);
  179. srgb2this = new ICC_Transform (transformList);
  180. }
  181. result = new float [this.getNumComponents()];
  182. srgb2this.colorConvert (1, rgbvalue, result);
  183. if (ColorSpace.isCS_CIEXYZ(this)) {
  184. // Fix for 4267139. We do a specific fix here for the fact that the
  185. // ICC encoding for CIEXYZ maps to a range of 0.0 to 2.0, rather than
  186. // 0.0 to 1.0 to allow for X and Z values greater than 1.0 (Y values
  187. // should never be greater than 1.0). What this means is that the
  188. // result Y values returned from this2xyz.colorConvert(1,colorvalue,
  189. // result) will range from 0.0 to 0.5, so they need to be doubled
  190. // here.
  191. // REMIND: The only encoding we can know about right now that
  192. // requires this fix (given our interfaces to the underlying CMM)
  193. // is CIEXYZ, but this probably needs a more general long-term fix.
  194. float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
  195. result[0] *= ALMOST_TWO;
  196. result[1] *= ALMOST_TWO;
  197. result[2] *= ALMOST_TWO;
  198. }
  199. return result;
  200. }
  201. /**
  202. * Transforms a color value assumed to be in this ColorSpace
  203. * into the CS_CIEXYZ conversion color space.
  204. * <p>
  205. * This method transforms color values using relative colorimetry,
  206. * as defined by the ICC Specification. This
  207. * means that the XYZ values returned by this method are represented
  208. * relative to the D50 white point of the CS_CIEXYZ color space.
  209. * This representation is useful in a two-step color conversion
  210. * process in which colors are transformed from an input color
  211. * space to CS_CIEXYZ and then to an output color space. This
  212. * representation is not the same as the XYZ values that would
  213. * be measured from the given color value by a colorimeter.
  214. * A further transformation is necessary to compute the XYZ values
  215. * that would be measured using current CIE recommended practices.
  216. * The paragraphs below explain this in more detail.
  217. * <p>
  218. * The ICC standard uses a device independent color space (DICS) as the
  219. * mechanism for converting color from one device to another device. In
  220. * this architecture, colors are converted from the source device's color
  221. * space to the ICC DICS and then from the ICC DICS to the destination
  222. * device's color space. The ICC standard defines device profiles which
  223. * contain transforms which will convert between a device's color space
  224. * and the ICC DICS. The overall conversion of colors from a source
  225. * device to colors of a destination device is done by connecting the
  226. * device-to-DICS transform of the profile for the source device to the
  227. * DICS-to-device transform of the profile for the destination device.
  228. * For this reason, the ICC DICS is commonly referred to as the profile
  229. * connection space (PCS). The color space used in the methods
  230. * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
  231. * Specification. This is also the color space represented by
  232. * ColorSpace.CS_CIEXYZ.
  233. * <p>
  234. * The XYZ values of a color are often represented as relative to some
  235. * white point, so the actual meaning of the XYZ values cannot be known
  236. * without knowing the white point of those values. This is known as
  237. * relative colorimetry. The PCS uses a white point of D50, so the XYZ
  238. * values of the PCS are relative to D50. For example, white in the PCS
  239. * will have the XYZ values of D50, which is defined to be X=.9642,
  240. * Y=1.000, and Z=0.8249. This white point is commonly used for graphic
  241. * arts applications, but others are often used in other applications.
  242. * <p>
  243. * To quantify the color characteristics of a device such as a printer
  244. * or monitor, measurements of XYZ values for particular device colors
  245. * are typically made. For purposes of this discussion, the term
  246. * device XYZ values is used to mean the XYZ values that would be
  247. * measured from device colors using current CIE recommended practices.
  248. * <p>
  249. * Converting between device XYZ values and the PCS XYZ values returned
  250. * by this method corresponds to converting between the device's color
  251. * space, as represented by CIE colorimetric values, and the PCS. There
  252. * are many factors involved in this process, some of which are quite
  253. * subtle. The most important, however, is the adjustment made to account
  254. * for differences between the device's white point and the white point of
  255. * the PCS. There are many techniques for doing this and it is the
  256. * subject of much current research and controversy. Some commonly used
  257. * methods are XYZ scaling, the von Kries transform, and the Bradford
  258. * transform. The proper method to use depends upon each particular
  259. * application.
  260. * <p>
  261. * The simplest method is XYZ scaling. In this method each device XYZ
  262. * value is converted to a PCS XYZ value by multiplying it by the ratio
  263. * of the PCS white point (D50) to the device white point.
  264. * <pre>
  265. *
  266. * Xd, Yd, Zd are the device XYZ values
  267. * Xdw, Ydw, Zdw are the device XYZ white point values
  268. * Xp, Yp, Zp are the PCS XYZ values
  269. * Xd50, Yd50, Zd50 are the PCS XYZ white point values
  270. *
  271. * Xp = Xd * (Xd50 / Xdw)
  272. * Yp = Yd * (Yd50 / Ydw)
  273. * Zp = Zd * (Zd50 / Zdw)
  274. *
  275. * </pre>
  276. * <p>
  277. * Conversion from the PCS to the device would be done by inverting these
  278. * equations:
  279. * <pre>
  280. *
  281. * Xd = Xp * (Xdw / Xd50)
  282. * Yd = Yp * (Ydw / Yd50)
  283. * Zd = Zp * (Zdw / Zd50)
  284. *
  285. * </pre>
  286. * <p>
  287. * Note that the media white point tag in an ICC profile is not the same
  288. * as the device white point. The media white point tag is expressed in
  289. * PCS values and is used to represent the difference between the XYZ of
  290. * device illuminant and the XYZ of the device media when measured under
  291. * that illuminant. The device white point is expressed as the device
  292. * XYZ values corresponding to white displayed on the device. For
  293. * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
  294. * will result in a measured device XYZ value of D65. This will not
  295. * be the same as the media white point tag XYZ value in the ICC
  296. * profile for an sRGB device.
  297. * <p>
  298. * @param colorvalue a float array with length of at least the number
  299. * of components in this ColorSpace.
  300. * @return a float array of length 3.
  301. */
  302. public float[] toCIEXYZ(float[] colorvalue) {
  303. ICC_Transform[] transformList;
  304. float[] result;
  305. ICC_ColorSpace xyzCS;
  306. if (this2xyz == null) {
  307. transformList = new ICC_Transform [2];
  308. xyzCS = (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
  309. try {
  310. transformList[0] = new ICC_Transform (thisProfile,
  311. ICC_Profile.icRelativeColorimetric, ICC_Transform.In);
  312. } catch (CMMException e) {
  313. transformList[0] = new ICC_Transform (thisProfile,
  314. ICC_Transform.Any, ICC_Transform.In);
  315. }
  316. transformList[1] = new ICC_Transform (xyzCS.getProfile(),
  317. ICC_Transform.Any, ICC_Transform.Out);
  318. this2xyz = new ICC_Transform (transformList);
  319. }
  320. result = new float [3];
  321. this2xyz.colorConvert (1, colorvalue, result);
  322. // Fix for 4267139. We do a specific fix here for the fact that the
  323. // ICC encoding for CIEXYZ maps to a range of 0.0 to 2.0, rather than
  324. // 0.0 to 1.0 to allow for X and Z values greater than 1.0 (Y values
  325. // should never be greater than 1.0). What this means is that the
  326. // result Y values returned from this2xyz.colorConvert (1, colorvalue,
  327. // result) will range from 0.0 to 0.5, so they need to be doubled here.
  328. // REMIND: The only encoding we can know about right now that requires
  329. // this fix (given our interfaces to the underlying CMM) is CIEXYZ,
  330. // but this probably needs a more general long-term fix.
  331. float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
  332. result[0] *= ALMOST_TWO;
  333. result[1] *= ALMOST_TWO;
  334. result[2] *= ALMOST_TWO;
  335. return result;
  336. }
  337. /**
  338. * Transforms a color value assumed to be in the CS_CIEXYZ conversion
  339. * color space into this ColorSpace.
  340. * <p>
  341. * This method transforms color values using relative colorimetry,
  342. * as defined by the ICC Specification. This
  343. * means that the XYZ argument values taken by this method are represented
  344. * relative to the D50 white point of the CS_CIEXYZ color space.
  345. * This representation is useful in a two-step color conversion
  346. * process in which colors are transformed from an input color
  347. * space to CS_CIEXYZ and then to an output color space. The color
  348. * values returned by this method are not those that would produce
  349. * the XYZ value passed to the method when measured by a colorimeter.
  350. * If you have XYZ values corresponding to measurements made using
  351. * current CIE recommended practices, they must be converted to D50
  352. * relative values before being passed to this method.
  353. * The paragraphs below explain this in more detail.
  354. * <p>
  355. * The ICC standard uses a device independent color space (DICS) as the
  356. * mechanism for converting color from one device to another device. In
  357. * this architecture, colors are converted from the source device's color
  358. * space to the ICC DICS and then from the ICC DICS to the destination
  359. * device's color space. The ICC standard defines device profiles which
  360. * contain transforms which will convert between a device's color space
  361. * and the ICC DICS. The overall conversion of colors from a source
  362. * device to colors of a destination device is done by connecting the
  363. * device-to-DICS transform of the profile for the source device to the
  364. * DICS-to-device transform of the profile for the destination device.
  365. * For this reason, the ICC DICS is commonly referred to as the profile
  366. * connection space (PCS). The color space used in the methods
  367. * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
  368. * Specification. This is also the color space represented by
  369. * ColorSpace.CS_CIEXYZ.
  370. * <p>
  371. * The XYZ values of a color are often represented as relative to some
  372. * white point, so the actual meaning of the XYZ values cannot be known
  373. * without knowing the white point of those values. This is known as
  374. * relative colorimetry. The PCS uses a white point of D50, so the XYZ
  375. * values of the PCS are relative to D50. For example, white in the PCS
  376. * will have the XYZ values of D50, which is defined to be X=.9642,
  377. * Y=1.000, and Z=0.8249. This white point is commonly used for graphic
  378. * arts applications, but others are often used in other applications.
  379. * <p>
  380. * To quantify the color characteristics of a device such as a printer
  381. * or monitor, measurements of XYZ values for particular device colors
  382. * are typically made. For purposes of this discussion, the term
  383. * device XYZ values is used to mean the XYZ values that would be
  384. * measured from device colors using current CIE recommended practices.
  385. * <p>
  386. * Converting between device XYZ values and the PCS XYZ values taken as
  387. * arguments by this method corresponds to converting between the device's
  388. * color space, as represented by CIE colorimetric values, and the PCS.
  389. * There are many factors involved in this process, some of which are quite
  390. * subtle. The most important, however, is the adjustment made to account
  391. * for differences between the device's white point and the white point of
  392. * the PCS. There are many techniques for doing this and it is the
  393. * subject of much current research and controversy. Some commonly used
  394. * methods are XYZ scaling, the von Kries transform, and the Bradford
  395. * transform. The proper method to use depends upon each particular
  396. * application.
  397. * <p>
  398. * The simplest method is XYZ scaling. In this method each device XYZ
  399. * value is converted to a PCS XYZ value by multiplying it by the ratio
  400. * of the PCS white point (D50) to the device white point.
  401. * <pre>
  402. *
  403. * Xd, Yd, Zd are the device XYZ values
  404. * Xdw, Ydw, Zdw are the device XYZ white point values
  405. * Xp, Yp, Zp are the PCS XYZ values
  406. * Xd50, Yd50, Zd50 are the PCS XYZ white point values
  407. *
  408. * Xp = Xd * (Xd50 / Xdw)
  409. * Yp = Yd * (Yd50 / Ydw)
  410. * Zp = Zd * (Zd50 / Zdw)
  411. *
  412. * </pre>
  413. * <p>
  414. * Conversion from the PCS to the device would be done by inverting these
  415. * equations:
  416. * <pre>
  417. *
  418. * Xd = Xp * (Xdw / Xd50)
  419. * Yd = Yp * (Ydw / Yd50)
  420. * Zd = Zp * (Zdw / Zd50)
  421. *
  422. * </pre>
  423. * <p>
  424. * Note that the media white point tag in an ICC profile is not the same
  425. * as the device white point. The media white point tag is expressed in
  426. * PCS values and is used to represent the difference between the XYZ of
  427. * device illuminant and the XYZ of the device media when measured under
  428. * that illuminant. The device white point is expressed as the device
  429. * XYZ values corresponding to white displayed on the device. For
  430. * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
  431. * will result in a measured device XYZ value of D65. This will not
  432. * be the same as the media white point tag XYZ value in the ICC
  433. * profile for an sRGB device.
  434. * <p>
  435. * <p>
  436. * @param colorvalue a float array with length of at least 3.
  437. * @return a float array with length equal to the number of
  438. * components in this ColorSpace.
  439. */
  440. public float[] fromCIEXYZ(float[] colorvalue) {
  441. ICC_Transform[] transformList;
  442. float[] result;
  443. ICC_ColorSpace xyzCS;
  444. if (xyz2this == null) {
  445. transformList = new ICC_Transform [2];
  446. xyzCS = (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
  447. transformList[0] = new ICC_Transform (xyzCS.getProfile(),
  448. ICC_Transform.Any, ICC_Transform.In);
  449. try {
  450. transformList[1] = new ICC_Transform (thisProfile,
  451. ICC_Profile.icRelativeColorimetric, ICC_Transform.Out);
  452. } catch (CMMException e) {
  453. transformList[1] = new ICC_Transform (thisProfile,
  454. ICC_Transform.Any, ICC_Transform.Out);
  455. }
  456. xyz2this = new ICC_Transform (transformList);
  457. }
  458. // Fix for 4267139. We do a specific fix here for the fact that the
  459. // ICC encoding for CIEXYZ maps to a range of 0.0 to 2.0, rather than
  460. // 0.0 to 1.0 to allow for X and Z values greater than 1.0 (Y values
  461. // should never be greater than 1.0). What this means is that the
  462. // Y values passed to xyz2this.colorConvert (1, tmp, result)
  463. // should range from 0.0 to 0.5, so they need to be halved here.
  464. // REMIND: The only encoding we can know about right now that requires
  465. // this fix (given our interfaces to the underlying CMM) is CIEXYZ,
  466. // but this probably needs a more general long-term fix.
  467. float tmp[] = new float[3];
  468. float ALMOST_ONE_HALF = 1.0f / (1.0f + (32767.0f / 32768.0f));
  469. tmp[0] = colorvalue[0] * ALMOST_ONE_HALF;
  470. tmp[1] = colorvalue[1] * ALMOST_ONE_HALF;
  471. tmp[2] = colorvalue[2] * ALMOST_ONE_HALF;
  472. result = new float [this.getNumComponents()];
  473. xyz2this.colorConvert (1, tmp, result);
  474. return result;
  475. }
  476. }