1. /*
  2. * @(#)ICC_Profile.java 1.28 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /**********************************************************************
  8. **********************************************************************
  9. **********************************************************************
  10. *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
  11. *** As an unpublished work pursuant to Title 17 of the United ***
  12. *** States Code. All rights reserved. ***
  13. **********************************************************************
  14. **********************************************************************
  15. **********************************************************************/
  16. package java.awt.color;
  17. import sun.awt.color.CMM;
  18. import sun.awt.color.ProfileDeferralMgr;
  19. import sun.awt.color.ProfileDeferralInfo;
  20. import sun.awt.color.ProfileActivator;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileNotFoundException;
  24. import java.io.FileOutputStream;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.ObjectInputStream;
  28. import java.io.ObjectOutputStream;
  29. import java.io.ObjectStreamException;
  30. import java.io.OutputStream;
  31. import java.io.Serializable;
  32. import java.util.StringTokenizer;
  33. /**
  34. * A representation of color profile data for device independent and
  35. * device dependent color spaces based on the International Color
  36. * Consortium Specification ICC.1:1998-09, File Format for Color Profiles,
  37. * September 1998, and the addendum ICC.1A:1999-04, April 1999, to that
  38. * specification (see <A href="http://www.color.org"> http://www.color.org</A>).
  39. * <p>
  40. * An ICC_ColorSpace object can be constructed from an appropriate
  41. * ICC_Profile.
  42. * Typically, an ICC_ColorSpace would be associated with an ICC
  43. * Profile which is either an input, display, or output profile (see
  44. * the ICC specification). There are also device link, abstract,
  45. * color space conversion, and named color profiles. These are less
  46. * useful for tagging a color or image, but are useful for other
  47. * purposes (in particular device link profiles can provide improved
  48. * performance for converting from one device's color space to
  49. * another's).
  50. * <p>
  51. * ICC Profiles represent transformations from the color space of
  52. * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
  53. * Profiles of interest for tagging images or colors have a PCS
  54. * which is one of the two specific device independent
  55. * spaces (one CIEXYZ space and one CIELab space) defined in the
  56. * ICC Profile Format Specification. Most profiles of interest
  57. * either have invertible transformations or explicitly specify
  58. * transformations going both directions.
  59. * <p>
  60. * @version 10 Feb 1997
  61. * @see ICC_ColorSpace
  62. */
  63. public class ICC_Profile implements Serializable {
  64. transient long ID;
  65. private transient ProfileDeferralInfo deferralInfo;
  66. private transient ProfileActivator profileActivator;
  67. // Registry of singleton profile objects for specific color spaces
  68. // defined in the ColorSpace class (e.g. CS_sRGB), see
  69. // getInstance(int cspace) factory method.
  70. private static ICC_Profile sRGBprofile;
  71. private static ICC_Profile XYZprofile;
  72. private static ICC_Profile PYCCprofile;
  73. private static ICC_Profile GRAYprofile;
  74. private static ICC_Profile LINEAR_RGBprofile;
  75. /**
  76. * Profile class is input.
  77. */
  78. public static final int CLASS_INPUT = 0;
  79. /**
  80. * Profile class is display.
  81. */
  82. public static final int CLASS_DISPLAY = 1;
  83. /**
  84. * Profile class is output.
  85. */
  86. public static final int CLASS_OUTPUT = 2;
  87. /**
  88. * Profile class is device link.
  89. */
  90. public static final int CLASS_DEVICELINK = 3;
  91. /**
  92. * Profile class is color space conversion.
  93. */
  94. public static final int CLASS_COLORSPACECONVERSION = 4;
  95. /**
  96. * Profile class is abstract.
  97. */
  98. public static final int CLASS_ABSTRACT = 5;
  99. /**
  100. * Profile class is named color.
  101. */
  102. public static final int CLASS_NAMEDCOLOR = 6;
  103. /**
  104. * ICC Profile Color Space Type Signature: 'XYZ '.
  105. */
  106. public static final int icSigXYZData = 0x58595A20; /* 'XYZ ' */
  107. /**
  108. * ICC Profile Color Space Type Signature: 'Lab '.
  109. */
  110. public static final int icSigLabData = 0x4C616220; /* 'Lab ' */
  111. /**
  112. * ICC Profile Color Space Type Signature: 'Luv '.
  113. */
  114. public static final int icSigLuvData = 0x4C757620; /* 'Luv ' */
  115. /**
  116. * ICC Profile Color Space Type Signature: 'YCbr'.
  117. */
  118. public static final int icSigYCbCrData = 0x59436272; /* 'YCbr' */
  119. /**
  120. * ICC Profile Color Space Type Signature: 'Yxy '.
  121. */
  122. public static final int icSigYxyData = 0x59787920; /* 'Yxy ' */
  123. /**
  124. * ICC Profile Color Space Type Signature: 'RGB '.
  125. */
  126. public static final int icSigRgbData = 0x52474220; /* 'RGB ' */
  127. /**
  128. * ICC Profile Color Space Type Signature: 'GRAY'.
  129. */
  130. public static final int icSigGrayData = 0x47524159; /* 'GRAY' */
  131. /**
  132. * ICC Profile Color Space Type Signature: 'HSV'.
  133. */
  134. public static final int icSigHsvData = 0x48535620; /* 'HSV ' */
  135. /**
  136. * ICC Profile Color Space Type Signature: 'HLS'.
  137. */
  138. public static final int icSigHlsData = 0x484C5320; /* 'HLS ' */
  139. /**
  140. * ICC Profile Color Space Type Signature: 'CMYK'.
  141. */
  142. public static final int icSigCmykData = 0x434D594B; /* 'CMYK' */
  143. /**
  144. * ICC Profile Color Space Type Signature: 'CMY '.
  145. */
  146. public static final int icSigCmyData = 0x434D5920; /* 'CMY ' */
  147. /**
  148. * ICC Profile Color Space Type Signature: '2CLR'.
  149. */
  150. public static final int icSigSpace2CLR = 0x32434C52; /* '2CLR' */
  151. /**
  152. * ICC Profile Color Space Type Signature: '3CLR'.
  153. */
  154. public static final int icSigSpace3CLR = 0x33434C52; /* '3CLR' */
  155. /**
  156. * ICC Profile Color Space Type Signature: '4CLR'.
  157. */
  158. public static final int icSigSpace4CLR = 0x34434C52; /* '4CLR' */
  159. /**
  160. * ICC Profile Color Space Type Signature: '5CLR'.
  161. */
  162. public static final int icSigSpace5CLR = 0x35434C52; /* '5CLR' */
  163. /**
  164. * ICC Profile Color Space Type Signature: '6CLR'.
  165. */
  166. public static final int icSigSpace6CLR = 0x36434C52; /* '6CLR' */
  167. /**
  168. * ICC Profile Color Space Type Signature: '7CLR'.
  169. */
  170. public static final int icSigSpace7CLR = 0x37434C52; /* '7CLR' */
  171. /**
  172. * ICC Profile Color Space Type Signature: '8CLR'.
  173. */
  174. public static final int icSigSpace8CLR = 0x38434C52; /* '8CLR' */
  175. /**
  176. * ICC Profile Color Space Type Signature: '9CLR'.
  177. */
  178. public static final int icSigSpace9CLR = 0x39434C52; /* '9CLR' */
  179. /**
  180. * ICC Profile Color Space Type Signature: 'ACLR'.
  181. */
  182. public static final int icSigSpaceACLR = 0x41434C52; /* 'ACLR' */
  183. /**
  184. * ICC Profile Color Space Type Signature: 'BCLR'.
  185. */
  186. public static final int icSigSpaceBCLR = 0x42434C52; /* 'BCLR' */
  187. /**
  188. * ICC Profile Color Space Type Signature: 'CCLR'.
  189. */
  190. public static final int icSigSpaceCCLR = 0x43434C52; /* 'CCLR' */
  191. /**
  192. * ICC Profile Color Space Type Signature: 'DCLR'.
  193. */
  194. public static final int icSigSpaceDCLR = 0x44434C52; /* 'DCLR' */
  195. /**
  196. * ICC Profile Color Space Type Signature: 'ECLR'.
  197. */
  198. public static final int icSigSpaceECLR = 0x45434C52; /* 'ECLR' */
  199. /**
  200. * ICC Profile Color Space Type Signature: 'FCLR'.
  201. */
  202. public static final int icSigSpaceFCLR = 0x46434C52; /* 'FCLR' */
  203. /**
  204. * ICC Profile Class Signature: 'scnr'.
  205. */
  206. public static final int icSigInputClass = 0x73636E72; /* 'scnr' */
  207. /**
  208. * ICC Profile Class Signature: 'mntr'.
  209. */
  210. public static final int icSigDisplayClass = 0x6D6E7472; /* 'mntr' */
  211. /**
  212. * ICC Profile Class Signature: 'prtr'.
  213. */
  214. public static final int icSigOutputClass = 0x70727472; /* 'prtr' */
  215. /**
  216. * ICC Profile Class Signature: 'link'.
  217. */
  218. public static final int icSigLinkClass = 0x6C696E6B; /* 'link' */
  219. /**
  220. * ICC Profile Class Signature: 'abst'.
  221. */
  222. public static final int icSigAbstractClass = 0x61627374; /* 'abst' */
  223. /**
  224. * ICC Profile Class Signature: 'spac'.
  225. */
  226. public static final int icSigColorSpaceClass = 0x73706163; /* 'spac' */
  227. /**
  228. * ICC Profile Class Signature: 'nmcl'.
  229. */
  230. public static final int icSigNamedColorClass = 0x6e6d636c; /* 'nmcl' */
  231. /**
  232. * ICC Profile Rendering Intent: Perceptual.
  233. */
  234. public static final int icPerceptual = 0;
  235. /**
  236. * ICC Profile Rendering Intent: RelativeColorimetric.
  237. */
  238. public static final int icRelativeColorimetric = 1;
  239. /**
  240. * ICC Profile Rendering Intent: Saturation.
  241. */
  242. public static final int icSaturation = 2;
  243. /**
  244. * ICC Profile Rendering Intent: AbsoluteColorimetric.
  245. */
  246. public static final int icAbsoluteColorimetric = 3;
  247. /**
  248. * ICC Profile Tag Signature: 'head' - special.
  249. */
  250. public static final int icSigHead = 0x68656164; /* 'head' - special */
  251. /**
  252. * ICC Profile Tag Signature: 'A2B0'.
  253. */
  254. public static final int icSigAToB0Tag = 0x41324230; /* 'A2B0' */
  255. /**
  256. * ICC Profile Tag Signature: 'A2B1'.
  257. */
  258. public static final int icSigAToB1Tag = 0x41324231; /* 'A2B1' */
  259. /**
  260. * ICC Profile Tag Signature: 'A2B2'.
  261. */
  262. public static final int icSigAToB2Tag = 0x41324232; /* 'A2B2' */
  263. /**
  264. * ICC Profile Tag Signature: 'bXYZ'.
  265. */
  266. public static final int icSigBlueColorantTag = 0x6258595A; /* 'bXYZ' */
  267. /**
  268. * ICC Profile Tag Signature: 'bTRC'.
  269. */
  270. public static final int icSigBlueTRCTag = 0x62545243; /* 'bTRC' */
  271. /**
  272. * ICC Profile Tag Signature: 'B2A0'.
  273. */
  274. public static final int icSigBToA0Tag = 0x42324130; /* 'B2A0' */
  275. /**
  276. * ICC Profile Tag Signature: 'B2A1'.
  277. */
  278. public static final int icSigBToA1Tag = 0x42324131; /* 'B2A1' */
  279. /**
  280. * ICC Profile Tag Signature: 'B2A2'.
  281. */
  282. public static final int icSigBToA2Tag = 0x42324132; /* 'B2A2' */
  283. /**
  284. * ICC Profile Tag Signature: 'calt'.
  285. */
  286. public static final int icSigCalibrationDateTimeTag = 0x63616C74;
  287. /* 'calt' */
  288. /**
  289. * ICC Profile Tag Signature: 'targ'.
  290. */
  291. public static final int icSigCharTargetTag = 0x74617267; /* 'targ' */
  292. /**
  293. * ICC Profile Tag Signature: 'cprt'.
  294. */
  295. public static final int icSigCopyrightTag = 0x63707274; /* 'cprt' */
  296. /**
  297. * ICC Profile Tag Signature: 'crdi'.
  298. */
  299. public static final int icSigCrdInfoTag = 0x63726469; /* 'crdi' */
  300. /**
  301. * ICC Profile Tag Signature: 'dmnd'.
  302. */
  303. public static final int icSigDeviceMfgDescTag = 0x646D6E64; /* 'dmnd' */
  304. /**
  305. * ICC Profile Tag Signature: 'dmdd'.
  306. */
  307. public static final int icSigDeviceModelDescTag = 0x646D6464; /* 'dmdd' */
  308. /**
  309. * ICC Profile Tag Signature: 'devs'.
  310. */
  311. public static final int icSigDeviceSettingsTag = 0x64657673; /* 'devs' */
  312. /**
  313. * ICC Profile Tag Signature: 'gamt'.
  314. */
  315. public static final int icSigGamutTag = 0x67616D74; /* 'gamt' */
  316. /**
  317. * ICC Profile Tag Signature: 'kTRC'.
  318. */
  319. public static final int icSigGrayTRCTag = 0x6b545243; /* 'kTRC' */
  320. /**
  321. * ICC Profile Tag Signature: 'gXYZ'.
  322. */
  323. public static final int icSigGreenColorantTag = 0x6758595A; /* 'gXYZ' */
  324. /**
  325. * ICC Profile Tag Signature: 'gTRC'.
  326. */
  327. public static final int icSigGreenTRCTag = 0x67545243; /* 'gTRC' */
  328. /**
  329. * ICC Profile Tag Signature: 'lumi'.
  330. */
  331. public static final int icSigLuminanceTag = 0x6C756d69; /* 'lumi' */
  332. /**
  333. * ICC Profile Tag Signature: 'meas'.
  334. */
  335. public static final int icSigMeasurementTag = 0x6D656173; /* 'meas' */
  336. /**
  337. * ICC Profile Tag Signature: 'bkpt'.
  338. */
  339. public static final int icSigMediaBlackPointTag = 0x626B7074; /* 'bkpt' */
  340. /**
  341. * ICC Profile Tag Signature: 'wtpt'.
  342. */
  343. public static final int icSigMediaWhitePointTag = 0x77747074; /* 'wtpt' */
  344. /**
  345. * ICC Profile Tag Signature: 'ncl2'.
  346. */
  347. public static final int icSigNamedColor2Tag = 0x6E636C32; /* 'ncl2' */
  348. /**
  349. * ICC Profile Tag Signature: 'resp'.
  350. */
  351. public static final int icSigOutputResponseTag = 0x72657370; /* 'resp' */
  352. /**
  353. * ICC Profile Tag Signature: 'pre0'.
  354. */
  355. public static final int icSigPreview0Tag = 0x70726530; /* 'pre0' */
  356. /**
  357. * ICC Profile Tag Signature: 'pre1'.
  358. */
  359. public static final int icSigPreview1Tag = 0x70726531; /* 'pre1' */
  360. /**
  361. * ICC Profile Tag Signature: 'pre2'.
  362. */
  363. public static final int icSigPreview2Tag = 0x70726532; /* 'pre2' */
  364. /**
  365. * ICC Profile Tag Signature: 'desc'.
  366. */
  367. public static final int icSigProfileDescriptionTag = 0x64657363;
  368. /* 'desc' */
  369. /**
  370. * ICC Profile Tag Signature: 'pseq'.
  371. */
  372. public static final int icSigProfileSequenceDescTag = 0x70736571;
  373. /* 'pseq' */
  374. /**
  375. * ICC Profile Tag Signature: 'psd0'.
  376. */
  377. public static final int icSigPs2CRD0Tag = 0x70736430; /* 'psd0' */
  378. /**
  379. * ICC Profile Tag Signature: 'psd1'.
  380. */
  381. public static final int icSigPs2CRD1Tag = 0x70736431; /* 'psd1' */
  382. /**
  383. * ICC Profile Tag Signature: 'psd2'.
  384. */
  385. public static final int icSigPs2CRD2Tag = 0x70736432; /* 'psd2' */
  386. /**
  387. * ICC Profile Tag Signature: 'psd3'.
  388. */
  389. public static final int icSigPs2CRD3Tag = 0x70736433; /* 'psd3' */
  390. /**
  391. * ICC Profile Tag Signature: 'ps2s'.
  392. */
  393. public static final int icSigPs2CSATag = 0x70733273; /* 'ps2s' */
  394. /**
  395. * ICC Profile Tag Signature: 'ps2i'.
  396. */
  397. public static final int icSigPs2RenderingIntentTag = 0x70733269;
  398. /* 'ps2i' */
  399. /**
  400. * ICC Profile Tag Signature: 'rXYZ'.
  401. */
  402. public static final int icSigRedColorantTag = 0x7258595A; /* 'rXYZ' */
  403. /**
  404. * ICC Profile Tag Signature: 'rTRC'.
  405. */
  406. public static final int icSigRedTRCTag = 0x72545243; /* 'rTRC' */
  407. /**
  408. * ICC Profile Tag Signature: 'scrd'.
  409. */
  410. public static final int icSigScreeningDescTag = 0x73637264; /* 'scrd' */
  411. /**
  412. * ICC Profile Tag Signature: 'scrn'.
  413. */
  414. public static final int icSigScreeningTag = 0x7363726E; /* 'scrn' */
  415. /**
  416. * ICC Profile Tag Signature: 'tech'.
  417. */
  418. public static final int icSigTechnologyTag = 0x74656368; /* 'tech' */
  419. /**
  420. * ICC Profile Tag Signature: 'bfd '.
  421. */
  422. public static final int icSigUcrBgTag = 0x62666420; /* 'bfd ' */
  423. /**
  424. * ICC Profile Tag Signature: 'vued'.
  425. */
  426. public static final int icSigViewingCondDescTag = 0x76756564; /* 'vued' */
  427. /**
  428. * ICC Profile Tag Signature: 'view'.
  429. */
  430. public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
  431. /**
  432. * ICC Profile Tag Signature: 'chrm'.
  433. */
  434. public static final int icSigChromaticityTag = 0x6368726d; /* 'chrm' */
  435. /**
  436. * ICC Profile Header Location: profile size in bytes.
  437. */
  438. public static final int icHdrSize = 0; /* Profile size in bytes */
  439. /**
  440. * ICC Profile Header Location: CMM for this profile.
  441. */
  442. public static final int icHdrCmmId = 4; /* CMM for this profile */
  443. /**
  444. * ICC Profile Header Location: format version number.
  445. */
  446. public static final int icHdrVersion = 8; /* Format version number */
  447. /**
  448. * ICC Profile Header Location: type of profile.
  449. */
  450. public static final int icHdrDeviceClass = 12; /* Type of profile */
  451. /**
  452. * ICC Profile Header Location: color space of data.
  453. */
  454. public static final int icHdrColorSpace = 16; /* Color space of data */
  455. /**
  456. * ICC Profile Header Location: PCS - XYZ or Lab only.
  457. */
  458. public static final int icHdrPcs = 20; /* PCS - XYZ or Lab only */
  459. /**
  460. * ICC Profile Header Location: date profile was created.
  461. */
  462. public static final int icHdrDate = 24; /* Date profile was created */
  463. /**
  464. * ICC Profile Header Location: icMagicNumber.
  465. */
  466. public static final int icHdrMagic = 36; /* icMagicNumber */
  467. /**
  468. * ICC Profile Header Location: primary platform.
  469. */
  470. public static final int icHdrPlatform = 40; /* Primary Platform */
  471. /**
  472. * ICC Profile Header Location: various bit settings.
  473. */
  474. public static final int icHdrFlags = 44; /* Various bit settings */
  475. /**
  476. * ICC Profile Header Location: device manufacturer.
  477. */
  478. public static final int icHdrManufacturer = 48; /* Device manufacturer */
  479. /**
  480. * ICC Profile Header Location: device model number.
  481. */
  482. public static final int icHdrModel = 52; /* Device model number */
  483. /**
  484. * ICC Profile Header Location: device attributes.
  485. */
  486. public static final int icHdrAttributes = 56; /* Device attributes */
  487. /**
  488. * ICC Profile Header Location: rendering intent.
  489. */
  490. public static final int icHdrRenderingIntent = 64; /* Rendering intent */
  491. /**
  492. * ICC Profile Header Location: profile illuminant.
  493. */
  494. public static final int icHdrIlluminant = 68; /* Profile illuminant */
  495. /**
  496. * ICC Profile Header Location: profile creator.
  497. */
  498. public static final int icHdrCreator = 80; /* Profile creator */
  499. /**
  500. * ICC Profile Constant: tag type signaturE.
  501. */
  502. public static final int icTagType = 0; /* tag type signature */
  503. /**
  504. * ICC Profile Constant: reserved.
  505. */
  506. public static final int icTagReserved = 4; /* reserved */
  507. /**
  508. * ICC Profile Constant: curveType count.
  509. */
  510. public static final int icCurveCount = 8; /* curveType count */
  511. /**
  512. * ICC Profile Constant: curveType data.
  513. */
  514. public static final int icCurveData = 12; /* curveType data */
  515. /**
  516. * ICC Profile Constant: XYZNumber X.
  517. */
  518. public static final int icXYZNumberX = 8; /* XYZNumber X */
  519. /**
  520. * Constructs an ICC_Profile object with a given ID.
  521. */
  522. ICC_Profile(long ID) {
  523. this.ID = ID;
  524. }
  525. /**
  526. * Constructs an ICC_Profile object whose loading will be deferred.
  527. * The ID will be 0 until the profile is loaded.
  528. */
  529. ICC_Profile(ProfileDeferralInfo pdi) {
  530. this.deferralInfo = pdi;
  531. this.profileActivator = new ProfileActivator() {
  532. public void activate() {
  533. activateDeferredProfile();
  534. }
  535. };
  536. ProfileDeferralMgr.registerDeferral(this.profileActivator);
  537. }
  538. /**
  539. * Frees the resources associated with an ICC_Profile object.
  540. */
  541. protected void finalize () {
  542. if (ID != 0) {
  543. CMM.checkStatus(CMM.cmmFreeProfile(ID));
  544. } else if (profileActivator != null) {
  545. ProfileDeferralMgr.unregisterDeferral(profileActivator);
  546. }
  547. }
  548. /**
  549. * Constructs an ICC_Profile object corresponding to the data in
  550. * a byte array. Throws an IllegalArgumentException if the data
  551. * does not correspond to a valid ICC Profile.
  552. * @param data the specified ICC Profile data
  553. * @return an <code>ICC_Profile</code> object corresponding to
  554. * the data in the specified <code>data</code> array.
  555. */
  556. public static ICC_Profile getInstance(byte[] data) {
  557. ICC_Profile thisProfile;
  558. long[] theID = new long [1];
  559. if (ProfileDeferralMgr.deferring) {
  560. ProfileDeferralMgr.activateProfiles();
  561. }
  562. try {
  563. CMM.checkStatus(CMM.cmmLoadProfile(data, theID));
  564. } catch (CMMException c) {
  565. throw new IllegalArgumentException("Invalid ICC Profile Data");
  566. }
  567. try {
  568. if ((getColorSpaceType (theID[0]) == ColorSpace.TYPE_GRAY) &&
  569. (getData (theID[0], icSigMediaWhitePointTag) != null) &&
  570. (getData (theID[0], icSigGrayTRCTag) != null)) {
  571. thisProfile = new ICC_ProfileGray (theID[0]);
  572. }
  573. else if ((getColorSpaceType (theID[0]) == ColorSpace.TYPE_RGB) &&
  574. (getData (theID[0], icSigMediaWhitePointTag) != null) &&
  575. (getData (theID[0], icSigRedColorantTag) != null) &&
  576. (getData (theID[0], icSigGreenColorantTag) != null) &&
  577. (getData (theID[0], icSigBlueColorantTag) != null) &&
  578. (getData (theID[0], icSigRedTRCTag) != null) &&
  579. (getData (theID[0], icSigGreenTRCTag) != null) &&
  580. (getData (theID[0], icSigBlueTRCTag) != null)) {
  581. thisProfile = new ICC_ProfileRGB (theID[0]);
  582. }
  583. else {
  584. thisProfile = new ICC_Profile (theID[0]);
  585. }
  586. } catch (CMMException c) {
  587. thisProfile = new ICC_Profile (theID[0]);
  588. }
  589. return thisProfile;
  590. }
  591. /**
  592. * Constructs an ICC_Profile corresponding to one of the specific color
  593. * spaces defined by the ColorSpace class (for example CS_sRGB).
  594. * Throws an IllegalArgumentException if cspace is not one of the
  595. * defined color spaces.
  596. *
  597. * @param cspace the type of color space to create a profile for.
  598. * The specified type is one of the color
  599. * space constants defined in the <CODE>ColorSpace</CODE> class.
  600. *
  601. * @return an <code>ICC_Profile</code> object corresponding to
  602. * the specified <code>ColorSpace</code> type.
  603. * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
  604. * one of the predefined color space types.
  605. */
  606. public static ICC_Profile getInstance (int cspace)
  607. {
  608. ICC_Profile thisProfile = null;
  609. String fileName;
  610. try {
  611. switch (cspace) {
  612. case ColorSpace.CS_sRGB:
  613. if (sRGBprofile == null) {
  614. sRGBprofile = getDeferredInstance(
  615. new ProfileDeferralInfo("sRGB.pf", ColorSpace.TYPE_RGB,
  616. 3, CLASS_DISPLAY));
  617. }
  618. thisProfile = sRGBprofile;
  619. break;
  620. case ColorSpace.CS_CIEXYZ:
  621. if (XYZprofile == null) {
  622. XYZprofile = getInstance ("CIEXYZ.pf");
  623. }
  624. thisProfile = XYZprofile;
  625. break;
  626. case ColorSpace.CS_PYCC:
  627. if (PYCCprofile == null) {
  628. PYCCprofile = getInstance ("PYCC.pf");
  629. }
  630. thisProfile = PYCCprofile;
  631. break;
  632. case ColorSpace.CS_GRAY:
  633. if (GRAYprofile == null) {
  634. GRAYprofile = getInstance ("GRAY.pf");
  635. }
  636. thisProfile = GRAYprofile;
  637. break;
  638. case ColorSpace.CS_LINEAR_RGB:
  639. if (LINEAR_RGBprofile == null) {
  640. LINEAR_RGBprofile = getInstance ("LINEAR_RGB.pf");
  641. }
  642. thisProfile = LINEAR_RGBprofile;
  643. break;
  644. default:
  645. throw new IllegalArgumentException("Unknown color space");
  646. }
  647. } catch (IOException e) {
  648. throw new IllegalArgumentException("Can't load standard profile");
  649. }
  650. return thisProfile;
  651. }
  652. /**
  653. * Constructs an ICC_Profile corresponding to the data in a file.
  654. * fileName may be an absolute or a relative file specification.
  655. * Relative file names are looked for in several places: first, relative
  656. * to any directories specified by the java.iccprofile.path property;
  657. * second, relative to any directories specified by the java.class.path
  658. * property; finally, in a directory used to store profiles always
  659. * available, such as the profile for sRGB. Built-in profiles use .pf as
  660. * the file name extension for profiles, e.g. sRGB.pf.
  661. * This method throws an IOException if the specified file cannot be
  662. * opened or if an I/O error occurs while reading the file. It throws
  663. * an IllegalArgumentException if the file does not contain valid ICC
  664. * Profile data.
  665. * @param fileName The file that contains the data for the profile.
  666. *
  667. * @return an <code>ICC_Profile</code> object corresponding to
  668. * the data in the specified file.
  669. * @exception IOException If the specified file cannot be opened or
  670. * an I/O error occurs while reading the file.
  671. *
  672. * @exception IllegalArgumentException If the file does not
  673. * contain valid ICC Profile data.
  674. */
  675. public static ICC_Profile getInstance(String fileName) throws IOException {
  676. ICC_Profile thisProfile;
  677. FileInputStream fis;
  678. if ((fis = openProfile(fileName)) == null) {
  679. throw new IOException("Cannot open file " + fileName);
  680. }
  681. thisProfile = getInstance(fis);
  682. fis.close(); /* close the file */
  683. return thisProfile;
  684. }
  685. /**
  686. * Constructs an ICC_Profile corresponding to the data in an InputStream.
  687. * This method throws an IllegalArgumentException if the stream does not
  688. * contain valid ICC Profile data. It throws an IOException if an I/O
  689. * error occurs while reading the stream.
  690. * @param s The input stream from which to read the profile data.
  691. *
  692. * @return an <CODE>ICC_Profile</CODE> object corresponding to the
  693. * data in the specified <code>InputStream</code>.
  694. *
  695. * @exception IOException If an I/O error occurs while reading the stream.
  696. *
  697. * @exception IllegalArgumentException If the stream does not
  698. * contain valid ICC Profile data.
  699. */
  700. public static ICC_Profile getInstance(InputStream s) throws IOException {
  701. byte profileData[];
  702. if (s instanceof ProfileDeferralInfo) {
  703. /* hack to detect profiles whose loading can be deferred */
  704. return getDeferredInstance((ProfileDeferralInfo) s);
  705. }
  706. if ((profileData = getProfileDataFromStream(s)) == null) {
  707. throw new IllegalArgumentException("Invalid ICC Profile Data");
  708. }
  709. return getInstance(profileData);
  710. }
  711. static byte[] getProfileDataFromStream(InputStream s) throws IOException {
  712. byte profileData[];
  713. int profileSize;
  714. byte header[] = new byte[128];
  715. int bytestoread = 128;
  716. int bytesread = 0;
  717. int n;
  718. while (bytestoread != 0) {
  719. if ((n = s.read(header, bytesread, bytestoread)) < 0) {
  720. return null;
  721. }
  722. bytesread += n;
  723. bytestoread -= n;
  724. }
  725. if (header[36] != 0x61 || header[37] != 0x63 ||
  726. header[38] != 0x73 || header[39] != 0x70) {
  727. return null; /* not a valid profile */
  728. }
  729. profileSize = ((header[0] & 0xff) << 24) |
  730. ((header[1] & 0xff) << 16) |
  731. ((header[2] & 0xff) << 8) |
  732. (header[3] & 0xff);
  733. profileData = new byte[profileSize];
  734. System.arraycopy(header, 0, profileData, 0, 128);
  735. bytestoread = profileSize - 128;
  736. bytesread = 128;
  737. while (bytestoread != 0) {
  738. if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
  739. return null;
  740. }
  741. bytesread += n;
  742. bytestoread -= n;
  743. }
  744. return profileData;
  745. }
  746. /**
  747. * Constructs an ICC_Profile for which the actual loading of the
  748. * profile data from a file and the initialization of the CMM should
  749. * be deferred as long as possible.
  750. */
  751. static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi)
  752. throws IOException {
  753. if (!ProfileDeferralMgr.deferring) {
  754. return getInstance(pdi.filename);
  755. }
  756. if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
  757. return new ICC_ProfileRGB(pdi);
  758. } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
  759. return new ICC_ProfileGray(pdi);
  760. } else {
  761. return new ICC_Profile(pdi);
  762. }
  763. }
  764. void activateDeferredProfile() {
  765. long[] theID = new long [1];
  766. byte profileData[];
  767. FileInputStream fis;
  768. String fileName = deferralInfo.filename;
  769. profileActivator = null;
  770. deferralInfo = null;
  771. if ((fis = openProfile(fileName)) == null) {
  772. throw new IllegalArgumentException("Cannot open file " + fileName);
  773. }
  774. try {
  775. profileData = getProfileDataFromStream(fis);
  776. fis.close(); /* close the file */
  777. }
  778. catch (IOException e) {
  779. throw new IllegalArgumentException("Invalid ICC Profile Data" +
  780. fileName);
  781. }
  782. if (profileData == null) {
  783. throw new IllegalArgumentException("Invalid ICC Profile Data" +
  784. fileName);
  785. }
  786. try {
  787. CMM.checkStatus(CMM.cmmLoadProfile(profileData, theID));
  788. } catch (CMMException c) {
  789. throw new IllegalArgumentException("Invalid ICC Profile Data" +
  790. fileName);
  791. }
  792. ID = theID[0];
  793. }
  794. /**
  795. * Returns profile major version.
  796. * @return The major version of the profile.
  797. */
  798. public int getMajorVersion() {
  799. byte[] theHeader;
  800. theHeader = getData(icSigHead); /* getData will activate deferred
  801. profiles if necessary */
  802. return (int) theHeader[8];
  803. }
  804. /**
  805. * Returns profile minor version.
  806. * @return The minor version of the profile.
  807. */
  808. public int getMinorVersion() {
  809. byte[] theHeader;
  810. theHeader = getData(icSigHead); /* getData will activate deferred
  811. profiles if necessary */
  812. return (int) theHeader[9];
  813. }
  814. /**
  815. * Returns the profile class.
  816. * @return One of the predefined profile class constants.
  817. */
  818. public int getProfileClass() {
  819. byte[] theHeader;
  820. int theClassSig, theClass;
  821. if (deferralInfo != null) {
  822. return deferralInfo.profileClass; /* Need to have this info for
  823. ICC_ColorSpace without
  824. causing a deferred profile
  825. to be loaded */
  826. }
  827. theHeader = getData(icSigHead);
  828. theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
  829. switch (theClassSig) {
  830. case icSigInputClass:
  831. theClass = CLASS_INPUT;
  832. break;
  833. case icSigDisplayClass:
  834. theClass = CLASS_DISPLAY;
  835. break;
  836. case icSigOutputClass:
  837. theClass = CLASS_OUTPUT;
  838. break;
  839. case icSigLinkClass:
  840. theClass = CLASS_DEVICELINK;
  841. break;
  842. case icSigColorSpaceClass:
  843. theClass = CLASS_COLORSPACECONVERSION;
  844. break;
  845. case icSigAbstractClass:
  846. theClass = CLASS_ABSTRACT;
  847. break;
  848. case icSigNamedColorClass:
  849. theClass = CLASS_NAMEDCOLOR;
  850. break;
  851. default:
  852. throw new IllegalArgumentException("Unknown profile class");
  853. }
  854. return theClass;
  855. }
  856. /**
  857. * Returns the color space type. Returns one of the color space type
  858. * constants defined by the ColorSpace class. This is the
  859. * "input" color space of the profile. The type defines the
  860. * number of components of the color space and the interpretation,
  861. * e.g. TYPE_RGB identifies a color space with three components - red,
  862. * green, and blue. It does not define the particular color
  863. * characteristics of the space, e.g. the chromaticities of the
  864. * primaries.
  865. * @return One of the color space type constants defined in the
  866. * <CODE>ColorSpace</CODE> class.
  867. */
  868. public int getColorSpaceType() {
  869. if (deferralInfo != null) {
  870. return deferralInfo.colorSpaceType; /* Need to have this info for
  871. ICC_ColorSpace without
  872. causing a deferred profile
  873. to be loaded */
  874. }
  875. return getColorSpaceType(ID);
  876. }
  877. static int getColorSpaceType(long profileID) {
  878. byte[] theHeader;
  879. int theColorSpaceSig, theColorSpace;
  880. theHeader = getData(profileID, icSigHead);
  881. theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
  882. theColorSpace = iccCStoJCS (theColorSpaceSig);
  883. return theColorSpace;
  884. }
  885. /**
  886. * Returns the color space type of the Profile Connection Space (PCS).
  887. * Returns one of the color space type constants defined by the
  888. * ColorSpace class. This is the "output" color space of the
  889. * profile. For an input, display, or output profile useful
  890. * for tagging colors or images, this will be either TYPE_XYZ or
  891. * TYPE_Lab and should be interpreted as the corresponding specific
  892. * color space defined in the ICC specification. For a device
  893. * link profile, this could be any of the color space type constants.
  894. * @return One of the color space type constants defined in the
  895. * <CODE>ColorSpace</CODE> class.
  896. */
  897. public int getPCSType() {
  898. if (ProfileDeferralMgr.deferring) {
  899. ProfileDeferralMgr.activateProfiles();
  900. }
  901. return getPCSType(ID);
  902. }
  903. static int getPCSType(long profileID) {
  904. byte[] theHeader;
  905. int thePCSSig, thePCS;
  906. theHeader = getData(profileID, icSigHead);
  907. thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
  908. thePCS = iccCStoJCS(thePCSSig);
  909. return thePCS;
  910. }
  911. /**
  912. * Write this ICC_Profile to a file.
  913. *
  914. * @param fileName The file to write the profile data to.
  915. *
  916. * @exception IOException If the file cannot be opened for writing
  917. * or an I/O error occurs while writing to the file.
  918. */
  919. public void write(String fileName) throws IOException {
  920. FileOutputStream outputFile;
  921. byte profileData[];
  922. profileData = getData(); /* this will activate deferred
  923. profiles if necessary */
  924. outputFile = new FileOutputStream(fileName);
  925. outputFile.write(profileData);
  926. outputFile.close ();
  927. }
  928. /**
  929. * Write this ICC_Profile to an OutputStream.
  930. *
  931. * @param s The stream to write the profile data to.
  932. *
  933. * @exception IOException If an I/O error occurs while writing to the
  934. * stream.
  935. */
  936. public void write(OutputStream s) throws IOException {
  937. byte profileData[];
  938. profileData = getData(); /* this will activate deferred
  939. profiles if necessary */
  940. s.write(profileData);
  941. }
  942. /**
  943. * Returns a byte array corresponding to the data of this ICC_Profile.
  944. * @return A byte array that contains the profile data.
  945. * @see #setData(int, byte[])
  946. */
  947. public byte[] getData() {
  948. int[] profileSize = new int [1];
  949. byte[] profileData;
  950. if (ProfileDeferralMgr.deferring) {
  951. ProfileDeferralMgr.activateProfiles();
  952. }
  953. /* get the number of bytes needed for this profile */
  954. CMM.checkStatus(CMM.cmmGetProfileSize(ID, profileSize));
  955. profileData = new byte [profileSize[0]];
  956. /* get the data for the profile */
  957. CMM.checkStatus(CMM.cmmGetProfileData(ID, profileData));
  958. return profileData;
  959. }
  960. /**
  961. * Returns a particular tagged data element from the profile as
  962. * a byte array. Elements are identified by signatures
  963. * as defined in the ICC specification. The signature
  964. * icSigHead can be used to get the header. This method is useful
  965. * for advanced applets or applications which need to access
  966. * profile data directly.
  967. *
  968. * @param tagSignature The ICC tag signature for the data element you
  969. * want to get.
  970. *
  971. * @return A byte array that contains the tagged data element. Returns
  972. * <code>null</code> if the specified tag doesn't exist.
  973. * @see #setData(int, byte[])
  974. */
  975. public byte[] getData(int tagSignature) {
  976. if (ProfileDeferralMgr.deferring) {
  977. ProfileDeferralMgr.activateProfiles();
  978. }
  979. return getData(ID, tagSignature);
  980. }
  981. static byte[] getData(long profileID, int tagSignature) {
  982. int[] tagSize = new int [1];
  983. byte[] tagData;
  984. try {
  985. /* get the number of bytes needed for this tag */
  986. CMM.checkStatus(CMM.cmmGetTagSize(profileID, tagSignature,
  987. tagSize));
  988. tagData = new byte[tagSize[0]]; /* get an array for the tag */
  989. /* get the tag's data */
  990. CMM.checkStatus(CMM.cmmGetTagData(profileID, tagSignature,
  991. tagData));
  992. } catch(CMMException c) {
  993. tagData = null;
  994. }
  995. return tagData;
  996. }
  997. /**
  998. * Sets a particular tagged data element in the profile from
  999. * a byte array. This method is useful
  1000. * for advanced applets or applications which need to access
  1001. * profile data directly.
  1002. *
  1003. * @param tagSignature The ICC tag signature for the data element
  1004. * you want to set.
  1005. * @param tagData the data to set for the specified tag signature
  1006. * @see #getData
  1007. */
  1008. public void setData(int tagSignature, byte[] tagData) {
  1009. if (ProfileDeferralMgr.deferring) {
  1010. ProfileDeferralMgr.activateProfiles();
  1011. }
  1012. CMM.checkStatus(CMM.cmmSetTagData(ID, tagSignature, tagData));
  1013. }
  1014. /**
  1015. * Sets the rendering intent of the profile.
  1016. * This is used to select the proper transform from a profile that
  1017. * has multiple transforms.
  1018. */
  1019. void setRenderingIntent(int renderingIntent) {
  1020. byte[] theHeader = getData(icSigHead);/* getData will activate deferred
  1021. profiles if necessary */
  1022. intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
  1023. /* set the rendering intent */
  1024. setData (icSigHead, theHeader);
  1025. }
  1026. /**
  1027. * Returns the rendering intent of the profile.
  1028. * This is used to select the proper transform from a profile that
  1029. * has multiple transforms. It is typically set in a source profile
  1030. * to select a transform from an output profile.
  1031. */
  1032. int getRenderingIntent() {
  1033. byte[] theHeader = getData(icSigHead);/* getData will activate deferred
  1034. profiles if necessary */
  1035. int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
  1036. /* set the rendering intent */
  1037. return renderingIntent;
  1038. }
  1039. /**
  1040. * Returns the number of color components in the "input" color
  1041. * space of this profile. For example if the color space type
  1042. * of this profile is TYPE_RGB, then this method will return 3.
  1043. *
  1044. * @return The number of color components in the profile's input
  1045. * color space.
  1046. *
  1047. * @throws ProfileDataException if color space is in the profile
  1048. * is invalid
  1049. */
  1050. public int getNumComponents() {
  1051. byte[] theHeader;
  1052. int theColorSpaceSig, theNumComponents;
  1053. if (deferralInfo != null) {
  1054. return deferralInfo.numComponents; /* Need to have this info for
  1055. ICC_ColorSpace without
  1056. causing a deferred profile
  1057. to be loaded */
  1058. }
  1059. theHeader = getData(icSigHead);
  1060. theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
  1061. switch (theColorSpaceSig) {
  1062. case icSigGrayData:
  1063. theNumComponents = 1;
  1064. break;
  1065. case icSigSpace2CLR:
  1066. theNumComponents = 2;
  1067. break;
  1068. case icSigXYZData:
  1069. case icSigLabData:
  1070. case icSigLuvData:
  1071. case icSigYCbCrData:
  1072. case icSigYxyData:
  1073. case icSigRgbData:
  1074. case icSigHsvData:
  1075. case icSigHlsData:
  1076. case icSigCmyData:
  1077. case icSigSpace3CLR:
  1078. theNumComponents = 3;
  1079. break;
  1080. case icSigCmykData:
  1081. case icSigSpace4CLR:
  1082. theNumComponents = 4;
  1083. break;
  1084. case icSigSpace5CLR:
  1085. theNumComponents = 5;
  1086. break;
  1087. case icSigSpace6CLR:
  1088. theNumComponents = 6;
  1089. break;
  1090. case icSigSpace7CLR:
  1091. theNumComponents = 7;
  1092. break;
  1093. case icSigSpace8CLR:
  1094. theNumComponents = 8;
  1095. break;
  1096. case icSigSpace9CLR:
  1097. theNumComponents = 9;
  1098. break;
  1099. case icSigSpaceACLR:
  1100. theNumComponents = 10;
  1101. break;
  1102. case icSigSpaceBCLR:
  1103. theNumComponents = 11;
  1104. break;
  1105. case icSigSpaceCCLR:
  1106. theNumComponents = 12;
  1107. break;
  1108. case icSigSpaceDCLR:
  1109. theNumComponents = 13;
  1110. break;
  1111. case icSigSpaceECLR:
  1112. theNumComponents = 14;
  1113. break;
  1114. case icSigSpaceFCLR:
  1115. theNumComponents = 15;
  1116. break;
  1117. default:
  1118. throw new ProfileDataException ("invalid ICC color space");
  1119. }
  1120. return theNumComponents;
  1121. }
  1122. /**
  1123. * Returns a float array of length 3 containing the X, Y, and Z
  1124. * components of the mediaWhitePointTag in the ICC profile.
  1125. */
  1126. float[] getMediaWhitePoint() {
  1127. return getXYZTag(icSigMediaWhitePointTag);
  1128. /* get the media white point tag */
  1129. }
  1130. /**
  1131. * Returns a float array of length 3 containing the X, Y, and Z
  1132. * components encoded in an XYZType tag.
  1133. */
  1134. float[] getXYZTag(int theTagSignature) {
  1135. byte[] theData;
  1136. float[] theXYZNumber;
  1137. int i1, i2, theS15Fixed16;
  1138. theData = getData(theTagSignature); /* get the tag data */
  1139. /* getData will activate deferred
  1140. profiles if necessary */
  1141. theXYZNumber = new float [3]; /* array to return */
  1142. /* convert s15Fixed16Number to float */
  1143. for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
  1144. theS15Fixed16 = intFromBigEndian(theData, i2);
  1145. theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
  1146. }
  1147. return theXYZNumber;
  1148. }
  1149. /**
  1150. * Returns a gamma value representing a tone reproduction
  1151. * curve (TRC). If the profile represents the TRC as a table rather
  1152. * than a single gamma value, then an exception is thrown. In this
  1153. * case the actual table can be obtained via getTRC().
  1154. * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
  1155. * icSigGreenTRCTag, or icSigBlueTRCTag.
  1156. * @return the gamma value as a float.
  1157. * @exception ProfileDataException if the profile does not specify
  1158. * the TRC as a single gamma value.
  1159. */
  1160. float getGamma(int theTagSignature) {
  1161. byte[] theTRCData;
  1162. float theGamma;
  1163. int theU8Fixed8;
  1164. theTRCData = getData(theTagSignature); /* get the TRC */
  1165. /* getData will activate deferred
  1166. profiles if necessary */
  1167. if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
  1168. throw new ProfileDataException ("TRC is not a gamma");
  1169. }
  1170. /* convert u8Fixed8 to float */
  1171. theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
  1172. theGamma = ((float) theU8Fixed8) / 256.0f;
  1173. return theGamma;
  1174. }
  1175. /**
  1176. * Returns the TRC as an array of shorts. If the profile has
  1177. * specified the TRC as linear (gamma = 1.0) or as a simple gamma
  1178. * value, this method throws an exception, and the getGamma() method
  1179. * should be used to get the gamma value. Otherwise the short array
  1180. * returned here represents a lookup table where the input Gray value
  1181. * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
  1182. * to array index 0 and value 1.0 maps to array index length-1.
  1183. * Interpolation may be used to generate output values for
  1184. * input values which do not map exactly to an index in the
  1185. * array. Output values also map linearly to the range [0.0, 1.0].
  1186. * Value 0.0 is represented by an array value of 0x0000 and
  1187. * value 1.0 by 0xFFFF, i.e. the values are really unsigned
  1188. * short values, although they are returned in a short array.
  1189. * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
  1190. * icSigGreenTRCTag, or icSigBlueTRCTag.
  1191. * @return a short array representing the TRC.
  1192. * @exception ProfileDataException if the profile does not specify
  1193. * the TRC as a table.
  1194. */
  1195. short[] getTRC(int theTagSignature) {
  1196. byte[] theTRCData;
  1197. short[] theTRC;
  1198. int i1, i2, nElements, theU8Fixed8;
  1199. theTRCData = getData(theTagSignature); /* get the TRC */
  1200. /* getData will activate deferred
  1201. profiles if necessary */
  1202. nElements = intFromBigEndian(theTRCData, icCurveCount);
  1203. if (nElements == 1) {
  1204. throw new ProfileDataException("TRC is not a table");
  1205. }
  1206. /* make the short array */
  1207. theTRC = new short [nElements];
  1208. for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
  1209. theTRC[i1] = shortFromBigEndian(theTRCData, i2);
  1210. }
  1211. return theTRC;
  1212. }
  1213. /* convert an ICC color space signature into a Java color space type */
  1214. static int iccCStoJCS(int theColorSpaceSig) {
  1215. int theColorSpace;
  1216. switch (theColorSpaceSig) {
  1217. case icSigXYZData:
  1218. theColorSpace = ColorSpace.TYPE_XYZ;
  1219. break;
  1220. case icSigLabData:
  1221. theColorSpace = ColorSpace.TYPE_Lab;
  1222. break;
  1223. case icSigLuvData:
  1224. theColorSpace = ColorSpace.TYPE_Luv;
  1225. break;
  1226. case icSigYCbCrData:
  1227. theColorSpace = ColorSpace.TYPE_YCbCr;
  1228. break;
  1229. case icSigYxyData:
  1230. theColorSpace = ColorSpace.TYPE_Yxy;
  1231. break;
  1232. case icSigRgbData:
  1233. theColorSpace = ColorSpace.TYPE_RGB;
  1234. break;
  1235. case icSigGrayData:
  1236. theColorSpace = ColorSpace.TYPE_GRAY;
  1237. break;
  1238. case icSigHsvData:
  1239. theColorSpace = ColorSpace.TYPE_HSV;
  1240. break;
  1241. case icSigHlsData:
  1242. theColorSpace = ColorSpace.TYPE_HLS;
  1243. break;
  1244. case icSigCmykData:
  1245. theColorSpace = ColorSpace.TYPE_CMYK;
  1246. break;
  1247. case icSigCmyData:
  1248. theColorSpace = ColorSpace.TYPE_CMY;
  1249. break;
  1250. case icSigSpace2CLR:
  1251. theColorSpace = ColorSpace.TYPE_2CLR;
  1252. break;
  1253. case icSigSpace3CLR:
  1254. theColorSpace = ColorSpace.TYPE_3CLR;
  1255. break;
  1256. case icSigSpace4CLR:
  1257. theColorSpace = ColorSpace.TYPE_4CLR;
  1258. break;
  1259. case icSigSpace5CLR:
  1260. theColorSpace = ColorSpace.TYPE_5CLR;
  1261. break;
  1262. case icSigSpace6CLR:
  1263. theColorSpace = ColorSpace.TYPE_6CLR;
  1264. break;
  1265. case icSigSpace7CLR:
  1266. theColorSpace = ColorSpace.TYPE_7CLR;
  1267. break;
  1268. case icSigSpace8CLR:
  1269. theColorSpace = ColorSpace.TYPE_8CLR;
  1270. break;
  1271. case icSigSpace9CLR:
  1272. theColorSpace = ColorSpace.TYPE_9CLR;
  1273. break;
  1274. case icSigSpaceACLR:
  1275. theColorSpace = ColorSpace.TYPE_ACLR;
  1276. break;
  1277. case icSigSpaceBCLR:
  1278. theColorSpace = ColorSpace.TYPE_BCLR;
  1279. break;
  1280. case icSigSpaceCCLR:
  1281. theColorSpace = ColorSpace.TYPE_CCLR;
  1282. break;
  1283. case icSigSpaceDCLR:
  1284. theColorSpace = ColorSpace.TYPE_DCLR;
  1285. break;
  1286. case icSigSpaceECLR:
  1287. theColorSpace = ColorSpace.TYPE_ECLR;
  1288. break;
  1289. case icSigSpaceFCLR:
  1290. theColorSpace = ColorSpace.TYPE_FCLR;
  1291. break;
  1292. default:
  1293. throw new IllegalArgumentException ("Unknown color space");
  1294. }
  1295. return theColorSpace;
  1296. }
  1297. static int intFromBigEndian(byte[] array, int index) {
  1298. return (((array[index] & 0xff) << 24) |
  1299. ((array[index+1] & 0xff) << 16) |
  1300. ((array[index+2] & 0xff) << 8) |
  1301. (array[index+3] & 0xff));
  1302. }
  1303. static void intToBigEndian(int value, byte[] array, int index) {
  1304. array[index] = (byte) (value >> 24);
  1305. array[index+1] = (byte) (value >> 16);
  1306. array[index+2] = (byte) (value >> 8);
  1307. array[index+3] = (byte) (value);
  1308. }
  1309. static short shortFromBigEndian(byte[] array, int index) {
  1310. return (short) (((array[index] & 0xff) << 8) |
  1311. (array[index+1] & 0xff));
  1312. }
  1313. static void shortToBigEndian(short value, byte[] array, int index) {
  1314. array[index] = (byte) (value >> 8);
  1315. array[index+1] = (byte) (value);
  1316. }
  1317. /*
  1318. * fileName may be an absolute or a relative file specification.
  1319. * Relative file names are looked for in several places: first, relative
  1320. * to any directories specified by the java.iccprofile.path property;
  1321. * second, relative to any directories specified by the java.class.path
  1322. * property; finally, in a directory used to store profiles always
  1323. * available, such as a profile for sRGB. Built-in profiles use .pf as
  1324. * the file name extension for profiles, e.g. sRGB.pf.
  1325. */
  1326. private static FileInputStream openProfile(final String fileName) {
  1327. return (FileInputStream)java.security.AccessController.doPrivileged(
  1328. new java.security.PrivilegedAction() {
  1329. public Object run() {
  1330. return privilegedOpenProfile(fileName);
  1331. }
  1332. });
  1333. }
  1334. /*
  1335. * this version is called from doPrivileged in privilegedOpenProfile.
  1336. * the whole method is privileged!
  1337. */
  1338. private static FileInputStream privilegedOpenProfile(String fileName) {
  1339. FileInputStream fis = null;
  1340. String path, dir, fullPath;
  1341. try {
  1342. fis = new FileInputStream(fileName); /* absolute file name */
  1343. }
  1344. catch (FileNotFoundException e) {
  1345. }
  1346. if ((fis == null) &&
  1347. ((path = System.getProperty("java.iccprofile.path")) != null)){
  1348. /* try relative to java.iccprofile.path */
  1349. StringTokenizer st =
  1350. new StringTokenizer(path, File.pathSeparator);
  1351. while (st.hasMoreTokens() && (fis == null)) {
  1352. dir = st.nextToken();
  1353. try {
  1354. fullPath = dir + File.separatorChar + fileName;
  1355. fis = new FileInputStream(fullPath);
  1356. }
  1357. catch (FileNotFoundException e) {
  1358. }
  1359. }
  1360. }
  1361. if ((fis == null) &&
  1362. ((path = System.getProperty("java.class.path")) != null)) {
  1363. /* try relative to java.class.path */
  1364. StringTokenizer st =
  1365. new StringTokenizer(path, File.pathSeparator);
  1366. while (st.hasMoreTokens() && (fis == null)) {
  1367. dir = st.nextToken();
  1368. try {
  1369. fullPath = dir + File.separatorChar + fileName;
  1370. fis = new FileInputStream(fullPath);
  1371. }
  1372. catch (FileNotFoundException e) {
  1373. }
  1374. }
  1375. }
  1376. if (fis == null) { /* try the directory of built-in profiles */
  1377. dir = System.getProperty("java.home") +
  1378. File.separatorChar + "lib" + File.separatorChar + "cmm";
  1379. fullPath = dir + File.separatorChar + fileName;
  1380. try {
  1381. fis = new FileInputStream(fullPath);
  1382. }
  1383. catch (FileNotFoundException e) {
  1384. }
  1385. }
  1386. return fis;
  1387. }
  1388. /*
  1389. * Serialization support.
  1390. *
  1391. * Directly deserialized profiles are useless since they are not
  1392. * registered with CMM. We don't allow constructor to be called
  1393. * directly and instead have clients to call one of getInstance
  1394. * factory methods that will register the profile with CMM. For
  1395. * deserialization we implement readResolve method that will
  1396. * resolve the bogus deserialized profile object with one obtained
  1397. * with getInstance as well.
  1398. *
  1399. * There're two primary factory methods for construction of ICC
  1400. * profiles: getInstance(int cspace) and getInstance(byte[] data).
  1401. * This implementation of ICC_Profile uses the former to return a
  1402. * cached singleton profile object, other implementations will
  1403. * likely use this technique too. To preserve the singleton
  1404. * pattern across serialization we serialize cached singleton
  1405. * profiles in such a way that deserializing VM could call
  1406. * getInstance(int cspace) method that will resolve deserialized
  1407. * object into the corresponding singleton as well.
  1408. *
  1409. * Since the singletons are private to ICC_Profile the readResolve
  1410. * method have to be `protected' instead of `private' so that
  1411. * singletons that are instances of subclasses of ICC_Profile
  1412. * could be correctly deserialized.
  1413. */
  1414. /**
  1415. * Version of the format of additional serialized data in the
  1416. * stream. Version <code>1</code> corresponds to Java 2
  1417. * Platform, v1.3.
  1418. * @since 1.3
  1419. * @serial
  1420. */
  1421. private int iccProfileSerializedDataVersion = 1;
  1422. /**
  1423. * Writes default serializable fields to the stream. Writes a
  1424. * string and an array of bytes to the stream as additional data.
  1425. *
  1426. * @param s stream used for serialization.
  1427. * @throws IOException
  1428. * thrown by <code>ObjectInputStream</code>.
  1429. * @serialData
  1430. * The <code>String</code> is the name of one of
  1431. * <code>CS_<var>*</var></code> constants defined in the
  1432. * {@link ColorSpace} class if the profile object is a profile
  1433. * for a predefined color space (for example
  1434. * <code>"CS_sRGB"</code>). The string is <code>null</code>
  1435. * otherwise.
  1436. * <p>
  1437. * The <code>byte[]</code> array is the profile data for the
  1438. * profile. For predefined color spaces <code>null</code> is
  1439. * written instead of the profile data. If in the future
  1440. * versions of Java API new predefined color spaces will be
  1441. * added, future versions of this class may choose to write
  1442. * for new predefined color spaces not only the color space
  1443. * name, but the profile data as well so that older versions
  1444. * could still deserialize the object.
  1445. */
  1446. private void writeObject(ObjectOutputStream s)
  1447. throws IOException
  1448. {
  1449. s.defaultWriteObject();
  1450. String csName = null;
  1451. if (this == sRGBprofile) {
  1452. csName = "CS_sRGB";
  1453. } else if (this == XYZprofile) {
  1454. csName = "CS_CIEXYZ";
  1455. } else if (this == PYCCprofile) {
  1456. csName = "CS_PYCC";
  1457. } else if (this == GRAYprofile) {
  1458. csName = "CS_GRAY";
  1459. } else if (this == LINEAR_RGBprofile) {
  1460. csName = "CS_LINEAR_RGB";
  1461. }
  1462. // Future versions may choose to write profile data for new
  1463. // predefined color spaces as well, if any will be introduced,
  1464. // so that old versions that don't recognize the new CS name
  1465. // may fall back to constructing profile from the data.
  1466. byte[] data = null;
  1467. if (csName == null) {
  1468. // getData will activate deferred profile if necessary
  1469. data = getData();
  1470. }
  1471. s.writeObject(csName);
  1472. s.writeObject(data);
  1473. }
  1474. // Temporary storage used by readObject to store resolved profile
  1475. // (obtained with getInstance) for readResolve to return.
  1476. private transient ICC_Profile resolvedDeserializedProfile;
  1477. /**
  1478. * Reads default serializable fields from the stream. Reads from
  1479. * the stream a string and an array of bytes as additional data.
  1480. *
  1481. * @param s stream used for deserialization.
  1482. * @throws IOException
  1483. * thrown by <code>ObjectInputStream</code>.
  1484. * @throws ClassNotFoundException
  1485. * thrown by <code>ObjectInputStream</code>.
  1486. * @serialData
  1487. * The <code>String</code> is the name of one of
  1488. * <code>CS_<var>*</var></code> constants defined in the
  1489. * {@link ColorSpace} class if the profile object is a profile
  1490. * for a predefined color space (for example
  1491. * <code>"CS_sRGB"</code>). The string is <code>null</code>
  1492. * otherwise.
  1493. * <p>
  1494. * The <code>byte[]</code> array is the profile data for the
  1495. * profile. It will usually be <code>null</code> for the
  1496. * predefined profiles.
  1497. * <p>
  1498. * If the string is recognized as a constant name for
  1499. * predefined color space the object will be resolved into
  1500. * profile obtained with
  1501. * <code>getInstance(int cspace)</code> and the profile
  1502. * data are ignored. Otherwise the object will be resolved
  1503. * into profile obtained with
  1504. * <code>getInstance(byte[] data)</code>.
  1505. * @see #readResolve()
  1506. * @see #getInstance(int)
  1507. * @see #getInstance(byte[])
  1508. */
  1509. private void readObject(ObjectInputStream s)
  1510. throws IOException, ClassNotFoundException
  1511. {
  1512. s.defaultReadObject();
  1513. String csName = (String)s.readObject();
  1514. byte[] data = (byte[])s.readObject();
  1515. int cspace = 0; // ColorSpace.CS_* constant if known
  1516. boolean isKnownPredefinedCS = false;
  1517. if (csName != null) {
  1518. isKnownPredefinedCS = true;
  1519. if (csName.equals("CS_sRGB")) {
  1520. cspace = ColorSpace.CS_sRGB;
  1521. } else if (csName.equals("CS_CIEXYZ")) {
  1522. cspace = ColorSpace.CS_CIEXYZ;
  1523. } else if (csName.equals("CS_PYCC")) {
  1524. cspace = ColorSpace.CS_PYCC;
  1525. } else if (csName.equals("CS_GRAY")) {
  1526. cspace = ColorSpace.CS_GRAY;
  1527. } else if (csName.equals("CS_LINEAR_RGB")) {
  1528. cspace = ColorSpace.CS_LINEAR_RGB;
  1529. } else {
  1530. isKnownPredefinedCS = false;
  1531. }
  1532. }
  1533. if (isKnownPredefinedCS) {
  1534. resolvedDeserializedProfile = getInstance(cspace);
  1535. } else {
  1536. resolvedDeserializedProfile = getInstance(data);
  1537. }
  1538. }
  1539. /**
  1540. * Resolves instances being deserialized into instances registered
  1541. * with CMM.
  1542. * @return ICC_Profile object for profile registered with CMM.
  1543. * @throws ObjectStreamException
  1544. * never thrown, but mandated by the serialization spec.
  1545. */
  1546. protected Object readResolve() throws ObjectStreamException {
  1547. return resolvedDeserializedProfile;
  1548. }
  1549. }