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