6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 **********************************************************************
28 **********************************************************************
29 **********************************************************************
30 *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
31 *** As an unpublished work pursuant to Title 17 of the United ***
32 *** States Code. All rights reserved. ***
33 **********************************************************************
34 **********************************************************************
35 **********************************************************************/
36
37 package java.awt.color;
38
39 import sun.java2d.cmm.PCMM;
40 import sun.java2d.cmm.CMSManager;
41 import sun.java2d.cmm.Profile;
42 import sun.java2d.cmm.ProfileDataVerifier;
43 import sun.java2d.cmm.ProfileDeferralMgr;
44 import sun.java2d.cmm.ProfileDeferralInfo;
45 import sun.java2d.cmm.ProfileActivator;
46
47 import java.io.File;
48 import java.io.FileInputStream;
49 import java.io.FileNotFoundException;
50 import java.io.FileOutputStream;
51 import java.io.FilePermission;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.io.ObjectInputStream;
55 import java.io.ObjectOutputStream;
56 import java.io.ObjectStreamException;
57 import java.io.OutputStream;
58 import java.io.Serializable;
59
60 import java.util.StringTokenizer;
61
62 import java.security.AccessController;
63 import java.security.PrivilegedAction;
64
65
66 /**
67 * A representation of color profile data for device independent and
68 * device dependent color spaces based on the International Color
69 * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
70 * (see <A href="http://www.color.org"> http://www.color.org</A>).
71 * <p>
72 * An ICC_ColorSpace object can be constructed from an appropriate
73 * ICC_Profile.
74 * Typically, an ICC_ColorSpace would be associated with an ICC
75 * Profile which is either an input, display, or output profile (see
76 * the ICC specification). There are also device link, abstract,
77 * color space conversion, and named color profiles. These are less
78 * useful for tagging a color or image, but are useful for other
79 * purposes (in particular device link profiles can provide improved
80 * performance for converting from one device's color space to
81 * another's).
82 * <p>
83 * ICC Profiles represent transformations from the color space of
84 * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
85 * Profiles of interest for tagging images or colors have a PCS
86 * which is one of the two specific device independent
87 * spaces (one CIEXYZ space and one CIELab space) defined in the
88 * ICC Profile Format Specification. Most profiles of interest
89 * either have invertible transformations or explicitly specify
90 * transformations going both directions.
91 * @see ICC_ColorSpace
92 */
93
94
95 public class ICC_Profile implements Serializable {
96
97 private static final long serialVersionUID = -3938515861990936766L;
98
99 private transient Profile cmmProfile;
100
101 private transient ProfileDeferralInfo deferralInfo;
102 private transient ProfileActivator profileActivator;
103
104 // Registry of singleton profile objects for specific color spaces
105 // defined in the ColorSpace class (e.g. CS_sRGB), see
106 // getInstance(int cspace) factory method.
107 private static ICC_Profile sRGBprofile;
108 private static ICC_Profile XYZprofile;
109 private static ICC_Profile PYCCprofile;
110 private static ICC_Profile GRAYprofile;
111 private static ICC_Profile LINEAR_RGBprofile;
112
113
114 /**
115 * Profile class is input.
116 */
117 public static final int CLASS_INPUT = 0;
118
119 /**
120 * Profile class is display.
121 */
122 public static final int CLASS_DISPLAY = 1;
123
124 /**
125 * Profile class is output.
126 */
127 public static final int CLASS_OUTPUT = 2;
128
129 /**
130 * Profile class is device link.
131 */
132 public static final int CLASS_DEVICELINK = 3;
133
134 /**
135 * Profile class is color space conversion.
136 */
137 public static final int CLASS_COLORSPACECONVERSION = 4;
138
139 /**
140 * Profile class is abstract.
141 */
142 public static final int CLASS_ABSTRACT = 5;
143
144 /**
145 * Profile class is named color.
146 */
147 public static final int CLASS_NAMEDCOLOR = 6;
148
149
150 /**
151 * ICC Profile Color Space Type Signature: 'XYZ '.
152 */
153 public static final int icSigXYZData = 0x58595A20; /* 'XYZ ' */
154
155 /**
156 * ICC Profile Color Space Type Signature: 'Lab '.
157 */
158 public static final int icSigLabData = 0x4C616220; /* 'Lab ' */
159
160 /**
161 * ICC Profile Color Space Type Signature: 'Luv '.
162 */
163 public static final int icSigLuvData = 0x4C757620; /* 'Luv ' */
164
165 /**
166 * ICC Profile Color Space Type Signature: 'YCbr'.
167 */
168 public static final int icSigYCbCrData = 0x59436272; /* 'YCbr' */
169
304 public static final int icSigColorSpaceClass = 0x73706163; /* 'spac' */
305
306 /**
307 * ICC Profile Class Signature: 'nmcl'.
308 */
309 public static final int icSigNamedColorClass = 0x6e6d636c; /* 'nmcl' */
310
311
312 /**
313 * ICC Profile Rendering Intent: Perceptual.
314 */
315 public static final int icPerceptual = 0;
316
317 /**
318 * ICC Profile Rendering Intent: RelativeColorimetric.
319 */
320 public static final int icRelativeColorimetric = 1;
321
322 /**
323 * ICC Profile Rendering Intent: Media-RelativeColorimetric.
324 * @since 1.5
325 */
326 public static final int icMediaRelativeColorimetric = 1;
327
328 /**
329 * ICC Profile Rendering Intent: Saturation.
330 */
331 public static final int icSaturation = 2;
332
333 /**
334 * ICC Profile Rendering Intent: AbsoluteColorimetric.
335 */
336 public static final int icAbsoluteColorimetric = 3;
337
338 /**
339 * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
340 * @since 1.5
341 */
342 public static final int icICCAbsoluteColorimetric = 3;
343
344
345 /**
346 * ICC Profile Tag Signature: 'head' - special.
347 */
348 public static final int icSigHead = 0x68656164; /* 'head' - special */
349
350 /**
351 * ICC Profile Tag Signature: 'A2B0'.
352 */
353 public static final int icSigAToB0Tag = 0x41324230; /* 'A2B0' */
354
355 /**
356 * ICC Profile Tag Signature: 'A2B1'.
357 */
358 public static final int icSigAToB1Tag = 0x41324231; /* 'A2B1' */
359
360 /**
361 * ICC Profile Tag Signature: 'A2B2'.
362 */
363 public static final int icSigAToB2Tag = 0x41324232; /* 'A2B2' */
364
365 /**
366 * ICC Profile Tag Signature: 'bXYZ'.
367 */
368 public static final int icSigBlueColorantTag = 0x6258595A; /* 'bXYZ' */
369
370 /**
371 * ICC Profile Tag Signature: 'bXYZ'.
372 * @since 1.5
373 */
374 public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
375
376 /**
377 * ICC Profile Tag Signature: 'bTRC'.
378 */
379 public static final int icSigBlueTRCTag = 0x62545243; /* 'bTRC' */
380
381 /**
382 * ICC Profile Tag Signature: 'B2A0'.
383 */
384 public static final int icSigBToA0Tag = 0x42324130; /* 'B2A0' */
385
386 /**
387 * ICC Profile Tag Signature: 'B2A1'.
388 */
389 public static final int icSigBToA1Tag = 0x42324131; /* 'B2A1' */
390
391 /**
429 */
430 public static final int icSigDeviceSettingsTag = 0x64657673; /* 'devs' */
431
432 /**
433 * ICC Profile Tag Signature: 'gamt'.
434 */
435 public static final int icSigGamutTag = 0x67616D74; /* 'gamt' */
436
437 /**
438 * ICC Profile Tag Signature: 'kTRC'.
439 */
440 public static final int icSigGrayTRCTag = 0x6b545243; /* 'kTRC' */
441
442 /**
443 * ICC Profile Tag Signature: 'gXYZ'.
444 */
445 public static final int icSigGreenColorantTag = 0x6758595A; /* 'gXYZ' */
446
447 /**
448 * ICC Profile Tag Signature: 'gXYZ'.
449 * @since 1.5
450 */
451 public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
452
453 /**
454 * ICC Profile Tag Signature: 'gTRC'.
455 */
456 public static final int icSigGreenTRCTag = 0x67545243; /* 'gTRC' */
457
458 /**
459 * ICC Profile Tag Signature: 'lumi'.
460 */
461 public static final int icSigLuminanceTag = 0x6C756d69; /* 'lumi' */
462
463 /**
464 * ICC Profile Tag Signature: 'meas'.
465 */
466 public static final int icSigMeasurementTag = 0x6D656173; /* 'meas' */
467
468 /**
533 public static final int icSigPs2CRD3Tag = 0x70736433; /* 'psd3' */
534
535 /**
536 * ICC Profile Tag Signature: 'ps2s'.
537 */
538 public static final int icSigPs2CSATag = 0x70733273; /* 'ps2s' */
539
540 /**
541 * ICC Profile Tag Signature: 'ps2i'.
542 */
543 public static final int icSigPs2RenderingIntentTag = 0x70733269;
544 /* 'ps2i' */
545
546 /**
547 * ICC Profile Tag Signature: 'rXYZ'.
548 */
549 public static final int icSigRedColorantTag = 0x7258595A; /* 'rXYZ' */
550
551 /**
552 * ICC Profile Tag Signature: 'rXYZ'.
553 * @since 1.5
554 */
555 public static final int icSigRedMatrixColumnTag = 0x7258595A; /* 'rXYZ' */
556
557 /**
558 * ICC Profile Tag Signature: 'rTRC'.
559 */
560 public static final int icSigRedTRCTag = 0x72545243; /* 'rTRC' */
561
562 /**
563 * ICC Profile Tag Signature: 'scrd'.
564 */
565 public static final int icSigScreeningDescTag = 0x73637264; /* 'scrd' */
566
567 /**
568 * ICC Profile Tag Signature: 'scrn'.
569 */
570 public static final int icSigScreeningTag = 0x7363726E; /* 'scrn' */
571
572 /**
579 */
580 public static final int icSigUcrBgTag = 0x62666420; /* 'bfd ' */
581
582 /**
583 * ICC Profile Tag Signature: 'vued'.
584 */
585 public static final int icSigViewingCondDescTag = 0x76756564; /* 'vued' */
586
587 /**
588 * ICC Profile Tag Signature: 'view'.
589 */
590 public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
591
592 /**
593 * ICC Profile Tag Signature: 'chrm'.
594 */
595 public static final int icSigChromaticityTag = 0x6368726d; /* 'chrm' */
596
597 /**
598 * ICC Profile Tag Signature: 'chad'.
599 * @since 1.5
600 */
601 public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
602
603 /**
604 * ICC Profile Tag Signature: 'clro'.
605 * @since 1.5
606 */
607 public static final int icSigColorantOrderTag = 0x636C726F; /* 'clro' */
608
609 /**
610 * ICC Profile Tag Signature: 'clrt'.
611 * @since 1.5
612 */
613 public static final int icSigColorantTableTag = 0x636C7274; /* 'clrt' */
614
615
616 /**
617 * ICC Profile Header Location: profile size in bytes.
618 */
619 public static final int icHdrSize = 0; /* Profile size in bytes */
620
621 /**
622 * ICC Profile Header Location: CMM for this profile.
623 */
624 public static final int icHdrCmmId = 4; /* CMM for this profile */
625
626 /**
627 * ICC Profile Header Location: format version number.
628 */
629 public static final int icHdrVersion = 8; /* Format version number */
630
678 */
679 public static final int icHdrAttributes = 56; /* Device attributes */
680
681 /**
682 * ICC Profile Header Location: rendering intent.
683 */
684 public static final int icHdrRenderingIntent = 64; /* Rendering intent */
685
686 /**
687 * ICC Profile Header Location: profile illuminant.
688 */
689 public static final int icHdrIlluminant = 68; /* Profile illuminant */
690
691 /**
692 * ICC Profile Header Location: profile creator.
693 */
694 public static final int icHdrCreator = 80; /* Profile creator */
695
696 /**
697 * ICC Profile Header Location: profile's ID.
698 * @since 1.5
699 */
700 public static final int icHdrProfileID = 84; /* Profile's ID */
701
702
703 /**
704 * ICC Profile Constant: tag type signature.
705 */
706 public static final int icTagType = 0; /* tag type signature */
707
708 /**
709 * ICC Profile Constant: reserved.
710 */
711 public static final int icTagReserved = 4; /* reserved */
712
713 /**
714 * ICC Profile Constant: curveType count.
715 */
716 public static final int icCurveCount = 8; /* curveType count */
717
718 /**
719 * ICC Profile Constant: curveType data.
720 */
721 public static final int icCurveData = 12; /* curveType data */
722
723 /**
724 * ICC Profile Constant: XYZNumber X.
725 */
726 public static final int icXYZNumberX = 8; /* XYZNumber X */
727
728
729 /**
730 * Constructs an ICC_Profile object with a given ID.
731 */
732 ICC_Profile(Profile p) {
733 this.cmmProfile = p;
734 }
735
736
737 /**
738 * Constructs an ICC_Profile object whose loading will be deferred.
739 * The ID will be 0 until the profile is loaded.
740 */
741 ICC_Profile(ProfileDeferralInfo pdi) {
742 this.deferralInfo = pdi;
743 this.profileActivator = new ProfileActivator() {
744 public void activate() throws ProfileDataException {
745 activateDeferredProfile();
746 }
747 };
748 ProfileDeferralMgr.registerDeferral(this.profileActivator);
749 }
750
751
752 /**
753 * Frees the resources associated with an ICC_Profile object.
754 *
755 * @deprecated The {@code finalize} method has been deprecated.
756 * Subclasses that override {@code finalize} in order to perform cleanup
757 * should be modified to use alternative cleanup mechanisms and
758 * to remove the overriding {@code finalize} method.
759 * When overriding the {@code finalize} method, its implementation must explicitly
760 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
761 * See the specification for {@link Object#finalize()} for further
762 * information about migration options.
763 */
764 @Deprecated(since="9")
765 protected void finalize () {
766 if (cmmProfile != null) {
767 CMSManager.getModule().freeProfile(cmmProfile);
768 } else if (profileActivator != null) {
769 ProfileDeferralMgr.unregisterDeferral(profileActivator);
770 }
771 }
772
773
774 /**
775 * Constructs an ICC_Profile object corresponding to the data in
776 * a byte array. Throws an IllegalArgumentException if the data
777 * does not correspond to a valid ICC Profile.
778 * @param data the specified ICC Profile data
779 * @return an {@code ICC_Profile} object corresponding to
780 * the data in the specified {@code data} array.
781 */
782 public static ICC_Profile getInstance(byte[] data) {
783 ICC_Profile thisProfile;
784
785 Profile p = null;
786
787 if (ProfileDeferralMgr.deferring) {
788 ProfileDeferralMgr.activateProfiles();
789 }
790
791 ProfileDataVerifier.verify(data);
792
793 try {
794 p = CMSManager.getModule().loadProfile(data);
795 } catch (CMMException c) {
796 throw new IllegalArgumentException("Invalid ICC Profile Data");
797 }
798
799 try {
800 if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
804 }
805 else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
806 (getData (p, icSigMediaWhitePointTag) != null) &&
807 (getData (p, icSigRedColorantTag) != null) &&
808 (getData (p, icSigGreenColorantTag) != null) &&
809 (getData (p, icSigBlueColorantTag) != null) &&
810 (getData (p, icSigRedTRCTag) != null) &&
811 (getData (p, icSigGreenTRCTag) != null) &&
812 (getData (p, icSigBlueTRCTag) != null)) {
813 thisProfile = new ICC_ProfileRGB (p);
814 }
815 else {
816 thisProfile = new ICC_Profile (p);
817 }
818 } catch (CMMException c) {
819 thisProfile = new ICC_Profile (p);
820 }
821 return thisProfile;
822 }
823
824
825
826 /**
827 * Constructs an ICC_Profile corresponding to one of the specific color
828 * spaces defined by the ColorSpace class (for example CS_sRGB).
829 * Throws an IllegalArgumentException if cspace is not one of the
830 * defined color spaces.
831 *
832 * @param cspace the type of color space to create a profile for.
833 * The specified type is one of the color
834 * space constants defined in the {@code ColorSpace} class.
835 *
836 * @return an {@code ICC_Profile} object corresponding to
837 * the specified {@code ColorSpace} type.
838 * @exception IllegalArgumentException If {@code cspace} is not
839 * one of the predefined color space types.
840 */
841 public static ICC_Profile getInstance (int cspace) {
842 ICC_Profile thisProfile = null;
843 String fileName;
844
845 switch (cspace) {
846 case ColorSpace.CS_sRGB:
847 synchronized(ICC_Profile.class) {
848 if (sRGBprofile == null) {
849 /*
850 * Deferral is only used for standard profiles.
851 * Enabling the appropriate access privileges is handled
852 * at a lower level.
853 */
854 ProfileDeferralInfo pInfo =
855 new ProfileDeferralInfo("sRGB.pf",
856 ColorSpace.TYPE_RGB, 3,
857 CLASS_DISPLAY);
858 sRGBprofile = getDeferredInstance(pInfo);
859 }
914 synchronized(ICC_Profile.class) {
915 if (LINEAR_RGBprofile == null) {
916 ProfileDeferralInfo pInfo =
917 new ProfileDeferralInfo("LINEAR_RGB.pf",
918 ColorSpace.TYPE_RGB, 3,
919 CLASS_DISPLAY);
920 LINEAR_RGBprofile = getDeferredInstance(pInfo);
921 }
922 thisProfile = LINEAR_RGBprofile;
923 }
924
925 break;
926
927 default:
928 throw new IllegalArgumentException("Unknown color space");
929 }
930
931 return thisProfile;
932 }
933
934 /* This asserts system privileges, so is used only for the
935 * standard profiles.
936 */
937 private static ICC_Profile getStandardProfile(final String name) {
938
939 return AccessController.doPrivileged(
940 new PrivilegedAction<ICC_Profile>() {
941 public ICC_Profile run() {
942 ICC_Profile p = null;
943 try {
944 p = getInstance (name);
945 } catch (IOException ex) {
946 throw new IllegalArgumentException(
947 "Can't load standard profile: " + name);
948 }
949 return p;
950 }
951 });
952 }
953
954 /**
955 * Constructs an ICC_Profile corresponding to the data in a file.
956 * fileName may be an absolute or a relative file specification.
957 * Relative file names are looked for in several places: first, relative
958 * to any directories specified by the java.iccprofile.path property;
959 * second, relative to any directories specified by the java.class.path
960 * property; finally, in a directory used to store profiles always
961 * available, such as the profile for sRGB. Built-in profiles use .pf as
962 * the file name extension for profiles, e.g. sRGB.pf.
963 * This method throws an IOException if the specified file cannot be
964 * opened or if an I/O error occurs while reading the file. It throws
965 * an IllegalArgumentException if the file does not contain valid ICC
966 * Profile data.
967 * @param fileName The file that contains the data for the profile.
968 *
969 * @return an {@code ICC_Profile} object corresponding to
970 * the data in the specified file.
971 * @exception IOException If the specified file cannot be opened or
972 * an I/O error occurs while reading the file.
973 *
974 * @exception IllegalArgumentException If the file does not
975 * contain valid ICC Profile data.
976 *
977 * @exception SecurityException If a security manager is installed
978 * and it does not permit read access to the given file.
979 */
980 public static ICC_Profile getInstance(String fileName) throws IOException {
981 ICC_Profile thisProfile;
982 InputStream is = null;
983
984
985 File f = getProfileFile(fileName);
986 if (f != null) {
987 is = new FileInputStream(f);
988 } else {
989 is = getStandardProfileInputStream(fileName);
990 }
991 if (is == null) {
992 throw new IOException("Cannot open file " + fileName);
993 }
994
995 thisProfile = getInstance(is);
996
997 is.close(); /* close the file */
998
999 return thisProfile;
1000 }
1001
1002
1003 /**
1004 * Constructs an ICC_Profile corresponding to the data in an InputStream.
1005 * This method throws an IllegalArgumentException if the stream does not
1006 * contain valid ICC Profile data. It throws an IOException if an I/O
1007 * error occurs while reading the stream.
1008 * @param s The input stream from which to read the profile data.
1009 *
1010 * @return an {@code ICC_Profile} object corresponding to the
1011 * data in the specified {@code InputStream}.
1012 *
1013 * @exception IOException If an I/O error occurs while reading the stream.
1014 *
1015 * @exception IllegalArgumentException If the stream does not
1016 * contain valid ICC Profile data.
1017 */
1018 public static ICC_Profile getInstance(InputStream s) throws IOException {
1019 byte[] profileData;
1020
1021 if (s instanceof ProfileDeferralInfo) {
1022 /* hack to detect profiles whose loading can be deferred */
1023 return getDeferredInstance((ProfileDeferralInfo) s);
1024 }
1025
1026 if ((profileData = getProfileDataFromStream(s)) == null) {
1027 throw new IllegalArgumentException("Invalid ICC Profile Data");
1028 }
1029
1030 return getInstance(profileData);
1031 }
1032
1033
1034 static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1035 byte[] profileData;
1036 int profileSize;
1053 }
1054 profileSize = ((header[0] & 0xff) << 24) |
1055 ((header[1] & 0xff) << 16) |
1056 ((header[2] & 0xff) << 8) |
1057 (header[3] & 0xff);
1058 profileData = new byte[profileSize];
1059 System.arraycopy(header, 0, profileData, 0, 128);
1060 bytestoread = profileSize - 128;
1061 bytesread = 128;
1062 while (bytestoread != 0) {
1063 if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1064 return null;
1065 }
1066 bytesread += n;
1067 bytestoread -= n;
1068 }
1069
1070 return profileData;
1071 }
1072
1073
1074 /**
1075 * Constructs an ICC_Profile for which the actual loading of the
1076 * profile data from a file and the initialization of the CMM should
1077 * be deferred as long as possible.
1078 * Deferral is only used for standard profiles.
1079 * If deferring is disabled, then getStandardProfile() ensures
1080 * that all of the appropriate access privileges are granted
1081 * when loading this profile.
1082 * If deferring is enabled, then the deferred activation
1083 * code will take care of access privileges.
1084 * @see #activateDeferredProfile()
1085 */
1086 static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1087 if (!ProfileDeferralMgr.deferring) {
1088 return getStandardProfile(pdi.filename);
1089 }
1090 if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1091 return new ICC_ProfileRGB(pdi);
1092 } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1093 return new ICC_ProfileGray(pdi);
1094 } else {
1095 return new ICC_Profile(pdi);
1096 }
1097 }
1098
1099
1100 void activateDeferredProfile() throws ProfileDataException {
1101 byte[] profileData;
1102 final String fileName = deferralInfo.filename;
1103
1114 catch (IOException e) {
1115 ProfileDataException pde = new
1116 ProfileDataException("Invalid ICC Profile Data" + fileName);
1117 pde.initCause(e);
1118 throw pde;
1119 }
1120 if (profileData == null) {
1121 throw new ProfileDataException("Invalid ICC Profile Data" +
1122 fileName);
1123 }
1124 try {
1125 cmmProfile = CMSManager.getModule().loadProfile(profileData);
1126 } catch (CMMException c) {
1127 ProfileDataException pde = new
1128 ProfileDataException("Invalid ICC Profile Data" + fileName);
1129 pde.initCause(c);
1130 throw pde;
1131 }
1132 }
1133
1134
1135 /**
1136 * Returns profile major version.
1137 * @return The major version of the profile.
1138 */
1139 public int getMajorVersion() {
1140 byte[] theHeader;
1141
1142 theHeader = getData(icSigHead); /* getData will activate deferred
1143 profiles if necessary */
1144
1145 return (int) theHeader[8];
1146 }
1147
1148 /**
1149 * Returns profile minor version.
1150 * @return The minor version of the profile.
1151 */
1152 public int getMinorVersion() {
1153 byte[] theHeader;
1154
1155 theHeader = getData(icSigHead); /* getData will activate deferred
1156 profiles if necessary */
1157
1158 return (int) theHeader[9];
1159 }
1160
1161 /**
1162 * Returns the profile class.
1163 * @return One of the predefined profile class constants.
1164 */
1165 public int getProfileClass() {
1166 byte[] theHeader;
1167 int theClassSig, theClass;
1168
1169 if (deferralInfo != null) {
1170 return deferralInfo.profileClass; /* Need to have this info for
1171 ICC_ColorSpace without
1172 causing a deferred profile
1173 to be loaded */
1174 }
1175
1176 theHeader = getData(icSigHead);
1177
1178 theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1179
1180 switch (theClassSig) {
1181 case icSigInputClass:
1182 theClass = CLASS_INPUT;
1183 break;
1198 theClass = CLASS_COLORSPACECONVERSION;
1199 break;
1200
1201 case icSigAbstractClass:
1202 theClass = CLASS_ABSTRACT;
1203 break;
1204
1205 case icSigNamedColorClass:
1206 theClass = CLASS_NAMEDCOLOR;
1207 break;
1208
1209 default:
1210 throw new IllegalArgumentException("Unknown profile class");
1211 }
1212
1213 return theClass;
1214 }
1215
1216 /**
1217 * Returns the color space type. Returns one of the color space type
1218 * constants defined by the ColorSpace class. This is the
1219 * "input" color space of the profile. The type defines the
1220 * number of components of the color space and the interpretation,
1221 * e.g. TYPE_RGB identifies a color space with three components - red,
1222 * green, and blue. It does not define the particular color
1223 * characteristics of the space, e.g. the chromaticities of the
1224 * primaries.
1225 * @return One of the color space type constants defined in the
1226 * {@code ColorSpace} class.
1227 */
1228 public int getColorSpaceType() {
1229 if (deferralInfo != null) {
1230 return deferralInfo.colorSpaceType; /* Need to have this info for
1231 ICC_ColorSpace without
1232 causing a deferred profile
1233 to be loaded */
1234 }
1235 return getColorSpaceType(cmmProfile);
1236 }
1237
1238 static int getColorSpaceType(Profile p) {
1239 byte[] theHeader;
1240 int theColorSpaceSig, theColorSpace;
1241
1242 theHeader = getData(p, icSigHead);
1243 theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1244 theColorSpace = iccCStoJCS (theColorSpaceSig);
1245 return theColorSpace;
1246 }
1247
1248 /**
1249 * Returns the color space type of the Profile Connection Space (PCS).
1250 * Returns one of the color space type constants defined by the
1251 * ColorSpace class. This is the "output" color space of the
1252 * profile. For an input, display, or output profile useful
1253 * for tagging colors or images, this will be either TYPE_XYZ or
1254 * TYPE_Lab and should be interpreted as the corresponding specific
1255 * color space defined in the ICC specification. For a device
1256 * link profile, this could be any of the color space type constants.
1257 * @return One of the color space type constants defined in the
1258 * {@code ColorSpace} class.
1259 */
1260 public int getPCSType() {
1261 if (ProfileDeferralMgr.deferring) {
1262 ProfileDeferralMgr.activateProfiles();
1263 }
1264 return getPCSType(cmmProfile);
1265 }
1266
1267
1268 static int getPCSType(Profile p) {
1269 byte[] theHeader;
1270 int thePCSSig, thePCS;
1271
1272 theHeader = getData(p, icSigHead);
1273 thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1274 thePCS = iccCStoJCS(thePCSSig);
1275 return thePCS;
1276 }
1277
1278
1279 /**
1280 * Write this ICC_Profile to a file.
1281 *
1282 * @param fileName The file to write the profile data to.
1283 *
1284 * @exception IOException If the file cannot be opened for writing
1285 * or an I/O error occurs while writing to the file.
1286 */
1287 public void write(String fileName) throws IOException {
1288 FileOutputStream outputFile;
1289 byte[] profileData;
1290
1291 profileData = getData(); /* this will activate deferred
1292 profiles if necessary */
1293 outputFile = new FileOutputStream(fileName);
1294 outputFile.write(profileData);
1295 outputFile.close ();
1296 }
1297
1298
1299 /**
1300 * Write this ICC_Profile to an OutputStream.
1301 *
1302 * @param s The stream to write the profile data to.
1303 *
1304 * @exception IOException If an I/O error occurs while writing to the
1305 * stream.
1306 */
1307 public void write(OutputStream s) throws IOException {
1308 byte[] profileData;
1309
1310 profileData = getData(); /* this will activate deferred
1311 profiles if necessary */
1312 s.write(profileData);
1313 }
1314
1315
1316 /**
1317 * Returns a byte array corresponding to the data of this ICC_Profile.
1318 * @return A byte array that contains the profile data.
1319 * @see #setData(int, byte[])
1320 */
1321 public byte[] getData() {
1322 int profileSize;
1323 byte[] profileData;
1324
1325 if (ProfileDeferralMgr.deferring) {
1326 ProfileDeferralMgr.activateProfiles();
1327 }
1328
1329 PCMM mdl = CMSManager.getModule();
1330
1331 /* get the number of bytes needed for this profile */
1332 profileSize = mdl.getProfileSize(cmmProfile);
1333
1334 profileData = new byte [profileSize];
1335
1336 /* get the data for the profile */
1337 mdl.getProfileData(cmmProfile, profileData);
1338
1339 return profileData;
1340 }
1341
1342
1343 /**
1344 * Returns a particular tagged data element from the profile as
1345 * a byte array. Elements are identified by signatures
1346 * as defined in the ICC specification. The signature
1347 * icSigHead can be used to get the header. This method is useful
1348 * for advanced applets or applications which need to access
1349 * profile data directly.
1350 *
1351 * @param tagSignature The ICC tag signature for the data element you
1352 * want to get.
1353 *
1354 * @return A byte array that contains the tagged data element. Returns
1355 * {@code null} if the specified tag doesn't exist.
1356 * @see #setData(int, byte[])
1357 */
1358 public byte[] getData(int tagSignature) {
1359
1360 if (ProfileDeferralMgr.deferring) {
1361 ProfileDeferralMgr.activateProfiles();
1362 }
1363
1364 return getData(cmmProfile, tagSignature);
1365 }
1366
1367
1368 static byte[] getData(Profile p, int tagSignature) {
1369 int tagSize;
1370 byte[] tagData;
1371
1372 try {
1373 PCMM mdl = CMSManager.getModule();
1374
1375 /* get the number of bytes needed for this tag */
1376 tagSize = mdl.getTagSize(p, tagSignature);
1377
1378 tagData = new byte[tagSize]; /* get an array for the tag */
1379
1380 /* get the tag's data */
1381 mdl.getTagData(p, tagSignature, tagData);
1382 } catch(CMMException c) {
1383 tagData = null;
1384 }
1385
1386 return tagData;
1387 }
1388
1389 /**
1390 * Sets a particular tagged data element in the profile from
1391 * a byte array. The array should contain data in a format, corresponded
1392 * to the {@code tagSignature} as defined in the ICC specification, section 10.
1393 * This method is useful for advanced applets or applications which need to
1394 * access profile data directly.
1395 *
1396 * @param tagSignature The ICC tag signature for the data element
1397 * you want to set.
1398 * @param tagData the data to set for the specified tag signature
1399 * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1400 * as defined in the ICC specification.
1401 * @throws IllegalArgumentException if a content of the {@code tagData}
1402 * array can not be interpreted as valid tag data, corresponding
1403 * to the {@code tagSignature}.
1404 * @see #getData
1405 */
1406 public void setData(int tagSignature, byte[] tagData) {
1407
1408 if (ProfileDeferralMgr.deferring) {
1409 ProfileDeferralMgr.activateProfiles();
1410 }
1411
1412 CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1413 }
1414
1415 /**
1416 * Sets the rendering intent of the profile.
1417 * This is used to select the proper transform from a profile that
1418 * has multiple transforms.
1419 */
1420 void setRenderingIntent(int renderingIntent) {
1421 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1422 profiles if necessary */
1423 intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1424 /* set the rendering intent */
1425 setData (icSigHead, theHeader);
1426 }
1427
1428
1429 /**
1430 * Returns the rendering intent of the profile.
1431 * This is used to select the proper transform from a profile that
1432 * has multiple transforms. It is typically set in a source profile
1433 * to select a transform from an output profile.
1434 */
1435 int getRenderingIntent() {
1436 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1437 profiles if necessary */
1438
1439 int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1440 /* set the rendering intent */
1441
1442 /* According to ICC spec, only the least-significant 16 bits shall be
1443 * used to encode the rendering intent. The most significant 16 bits
1444 * shall be set to zero. Thus, we are ignoring two most significant
1445 * bytes here.
1446 *
1447 * See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1448 */
1449 return (0xffff & renderingIntent);
1450 }
1451
1452
1453 /**
1454 * Returns the number of color components in the "input" color
1455 * space of this profile. For example if the color space type
1456 * of this profile is TYPE_RGB, then this method will return 3.
1457 *
1458 * @return The number of color components in the profile's input
1459 * color space.
1460 *
1461 * @throws ProfileDataException if color space is in the profile
1462 * is invalid
1463 */
1464 public int getNumComponents() {
1465 byte[] theHeader;
1466 int theColorSpaceSig, theNumComponents;
1467
1468 if (deferralInfo != null) {
1469 return deferralInfo.numComponents; /* Need to have this info for
1470 ICC_ColorSpace without
1471 causing a deferred profile
1472 to be loaded */
1473 }
1474 theHeader = getData(icSigHead);
1475
1476 theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1477
1478 switch (theColorSpaceSig) {
1479 case icSigGrayData:
1480 theNumComponents = 1;
1481 break;
1482
1536
1537 case icSigSpaceDCLR:
1538 theNumComponents = 13;
1539 break;
1540
1541 case icSigSpaceECLR:
1542 theNumComponents = 14;
1543 break;
1544
1545 case icSigSpaceFCLR:
1546 theNumComponents = 15;
1547 break;
1548
1549 default:
1550 throw new ProfileDataException ("invalid ICC color space");
1551 }
1552
1553 return theNumComponents;
1554 }
1555
1556
1557 /**
1558 * Returns a float array of length 3 containing the X, Y, and Z
1559 * components of the mediaWhitePointTag in the ICC profile.
1560 */
1561 float[] getMediaWhitePoint() {
1562 return getXYZTag(icSigMediaWhitePointTag);
1563 /* get the media white point tag */
1564 }
1565
1566
1567 /**
1568 * Returns a float array of length 3 containing the X, Y, and Z
1569 * components encoded in an XYZType tag.
1570 */
1571 float[] getXYZTag(int theTagSignature) {
1572 byte[] theData;
1573 float[] theXYZNumber;
1574 int i1, i2, theS15Fixed16;
1575
1576 theData = getData(theTagSignature); /* get the tag data */
1577 /* getData will activate deferred
1578 profiles if necessary */
1579
1580 theXYZNumber = new float [3]; /* array to return */
1581
1582 /* convert s15Fixed16Number to float */
1583 for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1584 theS15Fixed16 = intFromBigEndian(theData, i2);
1585 theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1586 }
1587 return theXYZNumber;
1588 }
1589
1590
1591 /**
1592 * Returns a gamma value representing a tone reproduction
1593 * curve (TRC). If the profile represents the TRC as a table rather
1594 * than a single gamma value, then an exception is thrown. In this
1595 * case the actual table can be obtained via getTRC().
1596 * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1597 * icSigGreenTRCTag, or icSigBlueTRCTag.
1598 * @return the gamma value as a float.
1599 * @exception ProfileDataException if the profile does not specify
1600 * the TRC as a single gamma value.
1601 */
1602 float getGamma(int theTagSignature) {
1603 byte[] theTRCData;
1604 float theGamma;
1605 int theU8Fixed8;
1606
1607 theTRCData = getData(theTagSignature); /* get the TRC */
1608 /* getData will activate deferred
1609 profiles if necessary */
1610
1611 if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1612 throw new ProfileDataException ("TRC is not a gamma");
1613 }
1614
1615 /* convert u8Fixed8 to float */
1616 theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1617
1618 theGamma = ((float) theU8Fixed8) / 256.0f;
1619
1620 return theGamma;
1621 }
1622
1623
1624 /**
1625 * Returns the TRC as an array of shorts. If the profile has
1626 * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1627 * value, this method throws an exception, and the getGamma() method
1628 * should be used to get the gamma value. Otherwise the short array
1629 * returned here represents a lookup table where the input Gray value
1630 * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
1631 * to array index 0 and value 1.0 maps to array index length-1.
1632 * Interpolation may be used to generate output values for
1633 * input values which do not map exactly to an index in the
1634 * array. Output values also map linearly to the range [0.0, 1.0].
1635 * Value 0.0 is represented by an array value of 0x0000 and
1636 * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1637 * short values, although they are returned in a short array.
1638 * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1639 * icSigGreenTRCTag, or icSigBlueTRCTag.
1640 * @return a short array representing the TRC.
1641 * @exception ProfileDataException if the profile does not specify
1642 * the TRC as a table.
1643 */
1644 short[] getTRC(int theTagSignature) {
1645 byte[] theTRCData;
1646 short[] theTRC;
1647 int i1, i2, nElements, theU8Fixed8;
1648
1649 theTRCData = getData(theTagSignature); /* get the TRC */
1650 /* getData will activate deferred
1651 profiles if necessary */
1652
1653 nElements = intFromBigEndian(theTRCData, icCurveCount);
1654
1655 if (nElements == 1) {
1656 throw new ProfileDataException("TRC is not a table");
1657 }
1658
1659 /* make the short array */
1660 theTRC = new short [nElements];
1661
1662 for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1663 theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1664 }
1665
1666 return theTRC;
1667 }
1668
1669
1670 /* convert an ICC color space signature into a Java color space type */
1671 static int iccCStoJCS(int theColorSpaceSig) {
1672 int theColorSpace;
1673
1674 switch (theColorSpaceSig) {
1675 case icSigXYZData:
1676 theColorSpace = ColorSpace.TYPE_XYZ;
1677 break;
1678
1679 case icSigLabData:
1680 theColorSpace = ColorSpace.TYPE_Lab;
1681 break;
1682
1683 case icSigLuvData:
1684 theColorSpace = ColorSpace.TYPE_Luv;
1685 break;
1686
1687 case icSigYCbCrData:
1688 theColorSpace = ColorSpace.TYPE_YCbCr;
1689 break;
1690
1758
1759 case icSigSpaceCCLR:
1760 theColorSpace = ColorSpace.TYPE_CCLR;
1761 break;
1762
1763 case icSigSpaceDCLR:
1764 theColorSpace = ColorSpace.TYPE_DCLR;
1765 break;
1766
1767 case icSigSpaceECLR:
1768 theColorSpace = ColorSpace.TYPE_ECLR;
1769 break;
1770
1771 case icSigSpaceFCLR:
1772 theColorSpace = ColorSpace.TYPE_FCLR;
1773 break;
1774
1775 default:
1776 throw new IllegalArgumentException ("Unknown color space");
1777 }
1778
1779 return theColorSpace;
1780 }
1781
1782
1783 static int intFromBigEndian(byte[] array, int index) {
1784 return (((array[index] & 0xff) << 24) |
1785 ((array[index+1] & 0xff) << 16) |
1786 ((array[index+2] & 0xff) << 8) |
1787 (array[index+3] & 0xff));
1788 }
1789
1790
1791 static void intToBigEndian(int value, byte[] array, int index) {
1792 array[index] = (byte) (value >> 24);
1793 array[index+1] = (byte) (value >> 16);
1794 array[index+2] = (byte) (value >> 8);
1795 array[index+3] = (byte) (value);
1796 }
1797
1798
1799 static short shortFromBigEndian(byte[] array, int index) {
1800 return (short) (((array[index] & 0xff) << 8) |
1801 (array[index+1] & 0xff));
1802 }
1803
1804
1805 static void shortToBigEndian(short value, byte[] array, int index) {
1806 array[index] = (byte) (value >> 8);
1807 array[index+1] = (byte) (value);
1808 }
1809
1810
1811 /*
1812 * fileName may be an absolute or a relative file specification.
1813 * Relative file names are looked for in several places: first, relative
1814 * to any directories specified by the java.iccprofile.path property;
1815 * second, relative to any directories specified by the java.class.path.
1816 * The built-in profile files are now loaded as resources, since they
1817 * may not be individual disk files, and so this method will not find
1818 * these and on a null return, the caller needs to try as resources.
1819 * Built-in profiles use .pf as the file name extension for profiles,
1820 * e.g. sRGB.pf.
1821 */
1822 private static File getProfileFile(String fileName) {
1823 String path, dir, fullPath;
1824
1825 File f = new File(fileName); /* try absolute file name */
1826 if (f.isAbsolute()) {
1827 /* Rest of code has little sense for an absolute pathname,
1828 so return here. */
1829 return f.isFile() ? f : null;
1830 }
1831 if ((!f.isFile()) &&
1832 ((path = System.getProperty("java.iccprofile.path")) != null)){
1833 /* try relative to java.iccprofile.path */
1834 StringTokenizer st =
1835 new StringTokenizer(path, File.pathSeparator);
1836 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1837 dir = st.nextToken();
1838 fullPath = dir + File.separatorChar + fileName;
1839 f = new File(fullPath);
1840 if (!isChildOf(f, dir)) {
1845
1846 if (((f == null) || (!f.isFile())) &&
1847 ((path = System.getProperty("java.class.path")) != null)) {
1848 /* try relative to java.class.path */
1849 StringTokenizer st =
1850 new StringTokenizer(path, File.pathSeparator);
1851 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1852 dir = st.nextToken();
1853 fullPath = dir + File.separatorChar + fileName;
1854 f = new File(fullPath);
1855 }
1856 }
1857
1858 if (f != null && !f.isFile()) {
1859 f = null;
1860 }
1861 return f;
1862 }
1863
1864 /**
1865 * Returns a stream corresponding to a built-in profile
1866 * specified by fileName.
1867 * If there is no built-in profile with such name, then the method
1868 * returns null.
1869 */
1870 private static InputStream getStandardProfileInputStream(String fileName) {
1871 return AccessController.doPrivileged(
1872 new PrivilegedAction<InputStream>() {
1873 public InputStream run () {
1874 return
1875 PCMM.class.getResourceAsStream("profiles/" + fileName);
1876 }
1877 }, null, new FilePermission("<<ALL FILES>>", "read"),
1878 new RuntimePermission("accessSystemModules"));
1879 }
1880
1881 /**
1882 * Checks whether given file resides inside give directory.
1883 */
1884 private static boolean isChildOf(File f, String dirName) {
1885 try {
1886 File dir = new File(dirName);
1887 String canonicalDirName = dir.getCanonicalPath();
1888 if (!canonicalDirName.endsWith(File.separator)) {
1892 return canonicalFileName.startsWith(canonicalDirName);
1893 } catch (IOException e) {
1894 /* we do not expect the IOException here, because invocation
1895 * of this function is always preceded by isFile() call.
1896 */
1897 return false;
1898 }
1899 }
1900
1901 /**
1902 * Checks whether built-in profile specified by fileName exists.
1903 */
1904 private static boolean standardProfileExists(final String fileName) {
1905 return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1906 public Boolean run() {
1907 return PCMM.class.getResource("profiles/"+fileName) != null;
1908 }
1909 });
1910 }
1911
1912
1913 /*
1914 * Serialization support.
1915 *
1916 * Directly deserialized profiles are useless since they are not
1917 * registered with CMM. We don't allow constructor to be called
1918 * directly and instead have clients to call one of getInstance
1919 * factory methods that will register the profile with CMM. For
1920 * deserialization we implement readResolve method that will
1921 * resolve the bogus deserialized profile object with one obtained
1922 * with getInstance as well.
1923 *
1924 * There are two primary factory methods for construction of ICC
1925 * profiles: getInstance(int cspace) and getInstance(byte[] data).
1926 * This implementation of ICC_Profile uses the former to return a
1927 * cached singleton profile object, other implementations will
1928 * likely use this technique too. To preserve the singleton
1929 * pattern across serialization we serialize cached singleton
1930 * profiles in such a way that deserializing VM could call
1931 * getInstance(int cspace) method that will resolve deserialized
1932 * object into the corresponding singleton as well.
1933 *
1934 * Since the singletons are private to ICC_Profile the readResolve
1935 * method have to be `protected' instead of `private' so that
1936 * singletons that are instances of subclasses of ICC_Profile
1937 * could be correctly deserialized.
1938 */
1939
1940
1941 /**
1942 * Version of the format of additional serialized data in the
1943 * stream. Version {@code 1} corresponds to Java 2
1944 * Platform, v1.3.
1945 * @since 1.3
1946 * @serial
1947 */
1948 private int iccProfileSerializedDataVersion = 1;
1949
1950
1951 /**
1952 * Writes default serializable fields to the stream. Writes a
1953 * string and an array of bytes to the stream as additional data.
1954 *
1955 * @param s stream used for serialization.
1956 * @throws IOException
1957 * thrown by {@code ObjectInputStream}.
1958 * @serialData
1959 * The {@code String} is the name of one of
1960 * <code>CS_<var>*</var></code> constants defined in the
1961 * {@link ColorSpace} class if the profile object is a profile
1962 * for a predefined color space (for example
1963 * {@code "CS_sRGB"}). The string is {@code null}
1964 * otherwise.
1965 * <p>
1966 * The {@code byte[]} array is the profile data for the
1967 * profile. For predefined color spaces {@code null} is
1968 * written instead of the profile data. If in the future
1969 * versions of Java API new predefined color spaces will be
1970 * added, future versions of this class may choose to write
1971 * for new predefined color spaces not only the color space
1972 * name, but the profile data as well so that older versions
1973 * could still deserialize the object.
1974 */
1975 private void writeObject(ObjectOutputStream s)
1976 throws IOException
1977 {
1978 s.defaultWriteObject();
1979
1980 String csName = null;
1981 if (this == sRGBprofile) {
1982 csName = "CS_sRGB";
1983 } else if (this == XYZprofile) {
1984 csName = "CS_CIEXYZ";
1985 } else if (this == PYCCprofile) {
1986 csName = "CS_PYCC";
1987 } else if (this == GRAYprofile) {
1988 csName = "CS_GRAY";
1989 } else if (this == LINEAR_RGBprofile) {
1990 csName = "CS_LINEAR_RGB";
1991 }
1992
1993 // Future versions may choose to write profile data for new
1994 // predefined color spaces as well, if any will be introduced,
1995 // so that old versions that don't recognize the new CS name
1996 // may fall back to constructing profile from the data.
1997 byte[] data = null;
1998 if (csName == null) {
1999 // getData will activate deferred profile if necessary
2000 data = getData();
2001 }
2002
2003 s.writeObject(csName);
2004 s.writeObject(data);
2005 }
2006
2007 // Temporary storage used by readObject to store resolved profile
2008 // (obtained with getInstance) for readResolve to return.
2009 private transient ICC_Profile resolvedDeserializedProfile;
2010
2011 /**
2012 * Reads default serializable fields from the stream. Reads from
2013 * the stream a string and an array of bytes as additional data.
2014 *
2015 * @param s stream used for deserialization.
2016 * @throws IOException
2017 * thrown by {@code ObjectInputStream}.
2018 * @throws ClassNotFoundException
2019 * thrown by {@code ObjectInputStream}.
2020 * @serialData
2021 * The {@code String} is the name of one of
2022 * <code>CS_<var>*</var></code> constants defined in the
2023 * {@link ColorSpace} class if the profile object is a profile
2024 * for a predefined color space (for example
2025 * {@code "CS_sRGB"}). The string is {@code null}
2026 * otherwise.
2027 * <p>
2028 * The {@code byte[]} array is the profile data for the
2029 * profile. It will usually be {@code null} for the
2030 * predefined profiles.
2031 * <p>
2032 * If the string is recognized as a constant name for
2033 * predefined color space the object will be resolved into
2034 * profile obtained with
2035 * <code>getInstance(int cspace)</code> and the profile
2036 * data are ignored. Otherwise the object will be resolved
2037 * into profile obtained with
2038 * <code>getInstance(byte[] data)</code>.
2039 * @see #readResolve()
2040 * @see #getInstance(int)
2041 * @see #getInstance(byte[])
2042 */
2043 private void readObject(ObjectInputStream s)
2044 throws IOException, ClassNotFoundException
2045 {
2046 s.defaultReadObject();
2047
2048 String csName = (String)s.readObject();
2049 byte[] data = (byte[])s.readObject();
2050
2051 int cspace = 0; // ColorSpace.CS_* constant if known
2052 boolean isKnownPredefinedCS = false;
2053 if (csName != null) {
2054 isKnownPredefinedCS = true;
2055 if (csName.equals("CS_sRGB")) {
2056 cspace = ColorSpace.CS_sRGB;
2057 } else if (csName.equals("CS_CIEXYZ")) {
2058 cspace = ColorSpace.CS_CIEXYZ;
2059 } else if (csName.equals("CS_PYCC")) {
2060 cspace = ColorSpace.CS_PYCC;
2061 } else if (csName.equals("CS_GRAY")) {
2062 cspace = ColorSpace.CS_GRAY;
2063 } else if (csName.equals("CS_LINEAR_RGB")) {
2064 cspace = ColorSpace.CS_LINEAR_RGB;
2065 } else {
2066 isKnownPredefinedCS = false;
2067 }
2068 }
2069
2070 if (isKnownPredefinedCS) {
2071 resolvedDeserializedProfile = getInstance(cspace);
2072 } else {
2073 resolvedDeserializedProfile = getInstance(data);
2074 }
2075 }
2076
2077 /**
2078 * Resolves instances being deserialized into instances registered
2079 * with CMM.
2080 * @return ICC_Profile object for profile registered with CMM.
2081 * @throws ObjectStreamException
2082 * never thrown, but mandated by the serialization spec.
2083 * @since 1.3
2084 */
2085 protected Object readResolve() throws ObjectStreamException {
2086 return resolvedDeserializedProfile;
2087 }
2088 }
|
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /* ********************************************************************
27 **********************************************************************
28 **********************************************************************
29 *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
30 *** As an unpublished work pursuant to Title 17 of the United ***
31 *** States Code. All rights reserved. ***
32 **********************************************************************
33 **********************************************************************
34 **********************************************************************/
35
36 package java.awt.color;
37
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileOutputStream;
41 import java.io.FilePermission;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.ObjectInputStream;
45 import java.io.ObjectOutputStream;
46 import java.io.ObjectStreamException;
47 import java.io.OutputStream;
48 import java.io.Serializable;
49 import java.security.AccessController;
50 import java.security.PrivilegedAction;
51 import java.util.StringTokenizer;
52
53 import sun.java2d.cmm.CMSManager;
54 import sun.java2d.cmm.PCMM;
55 import sun.java2d.cmm.Profile;
56 import sun.java2d.cmm.ProfileActivator;
57 import sun.java2d.cmm.ProfileDataVerifier;
58 import sun.java2d.cmm.ProfileDeferralInfo;
59 import sun.java2d.cmm.ProfileDeferralMgr;
60
61 /**
62 * A representation of color profile data for device independent and device
63 * dependent color spaces based on the International Color Consortium
64 * Specification ICC.1:2001-12, File Format for Color Profiles, (see
65 * <a href="http://www.color.org"> http://www.color.org</a>).
66 * <p>
67 * An {@code ICC_ColorSpace} object can be constructed from an appropriate
68 * {@code ICC_Profile}. Typically, an {@code ICC_ColorSpace} would be associated
69 * with an ICC Profile which is either an input, display, or output profile (see
70 * the ICC specification). There are also device link, abstract, color space
71 * conversion, and named color profiles. These are less useful for tagging a
72 * color or image, but are useful for other purposes (in particular device link
73 * profiles can provide improved performance for converting from one device's
74 * color space to another's).
75 * <p>
76 * ICC Profiles represent transformations from the color space of the profile
77 * (e.g. a monitor) to a Profile Connection Space (PCS). Profiles of interest
78 * for tagging images or colors have a PCS which is one of the two specific
79 * device independent spaces (one CIEXYZ space and one CIELab space) defined in
80 * the ICC Profile Format Specification. Most profiles of interest either have
81 * invertible transformations or explicitly specify transformations going both
82 * directions.
83 *
84 * @see ICC_ColorSpace
85 */
86 public class ICC_Profile implements Serializable {
87
88 private static final long serialVersionUID = -3938515861990936766L;
89
90 private transient Profile cmmProfile;
91
92 private transient ProfileDeferralInfo deferralInfo;
93 private transient ProfileActivator profileActivator;
94
95 // Registry of singleton profile objects for specific color spaces
96 // defined in the ColorSpace class (e.g. CS_sRGB), see
97 // getInstance(int cspace) factory method.
98 private static ICC_Profile sRGBprofile;
99 private static ICC_Profile XYZprofile;
100 private static ICC_Profile PYCCprofile;
101 private static ICC_Profile GRAYprofile;
102 private static ICC_Profile LINEAR_RGBprofile;
103
104 /**
105 * Profile class is input.
106 */
107 public static final int CLASS_INPUT = 0;
108
109 /**
110 * Profile class is display.
111 */
112 public static final int CLASS_DISPLAY = 1;
113
114 /**
115 * Profile class is output.
116 */
117 public static final int CLASS_OUTPUT = 2;
118
119 /**
120 * Profile class is device link.
121 */
122 public static final int CLASS_DEVICELINK = 3;
123
124 /**
125 * Profile class is color space conversion.
126 */
127 public static final int CLASS_COLORSPACECONVERSION = 4;
128
129 /**
130 * Profile class is abstract.
131 */
132 public static final int CLASS_ABSTRACT = 5;
133
134 /**
135 * Profile class is named color.
136 */
137 public static final int CLASS_NAMEDCOLOR = 6;
138
139 /**
140 * ICC Profile Color Space Type Signature: 'XYZ '.
141 */
142 public static final int icSigXYZData = 0x58595A20; /* 'XYZ ' */
143
144 /**
145 * ICC Profile Color Space Type Signature: 'Lab '.
146 */
147 public static final int icSigLabData = 0x4C616220; /* 'Lab ' */
148
149 /**
150 * ICC Profile Color Space Type Signature: 'Luv '.
151 */
152 public static final int icSigLuvData = 0x4C757620; /* 'Luv ' */
153
154 /**
155 * ICC Profile Color Space Type Signature: 'YCbr'.
156 */
157 public static final int icSigYCbCrData = 0x59436272; /* 'YCbr' */
158
293 public static final int icSigColorSpaceClass = 0x73706163; /* 'spac' */
294
295 /**
296 * ICC Profile Class Signature: 'nmcl'.
297 */
298 public static final int icSigNamedColorClass = 0x6e6d636c; /* 'nmcl' */
299
300
301 /**
302 * ICC Profile Rendering Intent: Perceptual.
303 */
304 public static final int icPerceptual = 0;
305
306 /**
307 * ICC Profile Rendering Intent: RelativeColorimetric.
308 */
309 public static final int icRelativeColorimetric = 1;
310
311 /**
312 * ICC Profile Rendering Intent: Media-RelativeColorimetric.
313 *
314 * @since 1.5
315 */
316 public static final int icMediaRelativeColorimetric = 1;
317
318 /**
319 * ICC Profile Rendering Intent: Saturation.
320 */
321 public static final int icSaturation = 2;
322
323 /**
324 * ICC Profile Rendering Intent: AbsoluteColorimetric.
325 */
326 public static final int icAbsoluteColorimetric = 3;
327
328 /**
329 * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
330 *
331 * @since 1.5
332 */
333 public static final int icICCAbsoluteColorimetric = 3;
334
335
336 /**
337 * ICC Profile Tag Signature: 'head' - special.
338 */
339 public static final int icSigHead = 0x68656164; /* 'head' - special */
340
341 /**
342 * ICC Profile Tag Signature: 'A2B0'.
343 */
344 public static final int icSigAToB0Tag = 0x41324230; /* 'A2B0' */
345
346 /**
347 * ICC Profile Tag Signature: 'A2B1'.
348 */
349 public static final int icSigAToB1Tag = 0x41324231; /* 'A2B1' */
350
351 /**
352 * ICC Profile Tag Signature: 'A2B2'.
353 */
354 public static final int icSigAToB2Tag = 0x41324232; /* 'A2B2' */
355
356 /**
357 * ICC Profile Tag Signature: 'bXYZ'.
358 */
359 public static final int icSigBlueColorantTag = 0x6258595A; /* 'bXYZ' */
360
361 /**
362 * ICC Profile Tag Signature: 'bXYZ'.
363 *
364 * @since 1.5
365 */
366 public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
367
368 /**
369 * ICC Profile Tag Signature: 'bTRC'.
370 */
371 public static final int icSigBlueTRCTag = 0x62545243; /* 'bTRC' */
372
373 /**
374 * ICC Profile Tag Signature: 'B2A0'.
375 */
376 public static final int icSigBToA0Tag = 0x42324130; /* 'B2A0' */
377
378 /**
379 * ICC Profile Tag Signature: 'B2A1'.
380 */
381 public static final int icSigBToA1Tag = 0x42324131; /* 'B2A1' */
382
383 /**
421 */
422 public static final int icSigDeviceSettingsTag = 0x64657673; /* 'devs' */
423
424 /**
425 * ICC Profile Tag Signature: 'gamt'.
426 */
427 public static final int icSigGamutTag = 0x67616D74; /* 'gamt' */
428
429 /**
430 * ICC Profile Tag Signature: 'kTRC'.
431 */
432 public static final int icSigGrayTRCTag = 0x6b545243; /* 'kTRC' */
433
434 /**
435 * ICC Profile Tag Signature: 'gXYZ'.
436 */
437 public static final int icSigGreenColorantTag = 0x6758595A; /* 'gXYZ' */
438
439 /**
440 * ICC Profile Tag Signature: 'gXYZ'.
441 *
442 * @since 1.5
443 */
444 public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
445
446 /**
447 * ICC Profile Tag Signature: 'gTRC'.
448 */
449 public static final int icSigGreenTRCTag = 0x67545243; /* 'gTRC' */
450
451 /**
452 * ICC Profile Tag Signature: 'lumi'.
453 */
454 public static final int icSigLuminanceTag = 0x6C756d69; /* 'lumi' */
455
456 /**
457 * ICC Profile Tag Signature: 'meas'.
458 */
459 public static final int icSigMeasurementTag = 0x6D656173; /* 'meas' */
460
461 /**
526 public static final int icSigPs2CRD3Tag = 0x70736433; /* 'psd3' */
527
528 /**
529 * ICC Profile Tag Signature: 'ps2s'.
530 */
531 public static final int icSigPs2CSATag = 0x70733273; /* 'ps2s' */
532
533 /**
534 * ICC Profile Tag Signature: 'ps2i'.
535 */
536 public static final int icSigPs2RenderingIntentTag = 0x70733269;
537 /* 'ps2i' */
538
539 /**
540 * ICC Profile Tag Signature: 'rXYZ'.
541 */
542 public static final int icSigRedColorantTag = 0x7258595A; /* 'rXYZ' */
543
544 /**
545 * ICC Profile Tag Signature: 'rXYZ'.
546 *
547 * @since 1.5
548 */
549 public static final int icSigRedMatrixColumnTag = 0x7258595A; /* 'rXYZ' */
550
551 /**
552 * ICC Profile Tag Signature: 'rTRC'.
553 */
554 public static final int icSigRedTRCTag = 0x72545243; /* 'rTRC' */
555
556 /**
557 * ICC Profile Tag Signature: 'scrd'.
558 */
559 public static final int icSigScreeningDescTag = 0x73637264; /* 'scrd' */
560
561 /**
562 * ICC Profile Tag Signature: 'scrn'.
563 */
564 public static final int icSigScreeningTag = 0x7363726E; /* 'scrn' */
565
566 /**
573 */
574 public static final int icSigUcrBgTag = 0x62666420; /* 'bfd ' */
575
576 /**
577 * ICC Profile Tag Signature: 'vued'.
578 */
579 public static final int icSigViewingCondDescTag = 0x76756564; /* 'vued' */
580
581 /**
582 * ICC Profile Tag Signature: 'view'.
583 */
584 public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
585
586 /**
587 * ICC Profile Tag Signature: 'chrm'.
588 */
589 public static final int icSigChromaticityTag = 0x6368726d; /* 'chrm' */
590
591 /**
592 * ICC Profile Tag Signature: 'chad'.
593 *
594 * @since 1.5
595 */
596 public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
597
598 /**
599 * ICC Profile Tag Signature: 'clro'.
600 *
601 * @since 1.5
602 */
603 public static final int icSigColorantOrderTag = 0x636C726F; /* 'clro' */
604
605 /**
606 * ICC Profile Tag Signature: 'clrt'.
607 *
608 * @since 1.5
609 */
610 public static final int icSigColorantTableTag = 0x636C7274; /* 'clrt' */
611
612
613 /**
614 * ICC Profile Header Location: profile size in bytes.
615 */
616 public static final int icHdrSize = 0; /* Profile size in bytes */
617
618 /**
619 * ICC Profile Header Location: CMM for this profile.
620 */
621 public static final int icHdrCmmId = 4; /* CMM for this profile */
622
623 /**
624 * ICC Profile Header Location: format version number.
625 */
626 public static final int icHdrVersion = 8; /* Format version number */
627
675 */
676 public static final int icHdrAttributes = 56; /* Device attributes */
677
678 /**
679 * ICC Profile Header Location: rendering intent.
680 */
681 public static final int icHdrRenderingIntent = 64; /* Rendering intent */
682
683 /**
684 * ICC Profile Header Location: profile illuminant.
685 */
686 public static final int icHdrIlluminant = 68; /* Profile illuminant */
687
688 /**
689 * ICC Profile Header Location: profile creator.
690 */
691 public static final int icHdrCreator = 80; /* Profile creator */
692
693 /**
694 * ICC Profile Header Location: profile's ID.
695 *
696 * @since 1.5
697 */
698 public static final int icHdrProfileID = 84; /* Profile's ID */
699
700
701 /**
702 * ICC Profile Constant: tag type signature.
703 */
704 public static final int icTagType = 0; /* tag type signature */
705
706 /**
707 * ICC Profile Constant: reserved.
708 */
709 public static final int icTagReserved = 4; /* reserved */
710
711 /**
712 * ICC Profile Constant: curveType count.
713 */
714 public static final int icCurveCount = 8; /* curveType count */
715
716 /**
717 * ICC Profile Constant: curveType data.
718 */
719 public static final int icCurveData = 12; /* curveType data */
720
721 /**
722 * ICC Profile Constant: XYZNumber X.
723 */
724 public static final int icXYZNumberX = 8; /* XYZNumber X */
725
726
727 /**
728 * Constructs an {@code ICC_Profile} object with a given ID.
729 */
730 ICC_Profile(Profile p) {
731 this.cmmProfile = p;
732 }
733
734 /**
735 * Constructs an {@code ICC_Profile} object whose loading will be deferred.
736 * The ID will be 0 until the profile is loaded.
737 */
738 ICC_Profile(ProfileDeferralInfo pdi) {
739 this.deferralInfo = pdi;
740 this.profileActivator = new ProfileActivator() {
741 public void activate() throws ProfileDataException {
742 activateDeferredProfile();
743 }
744 };
745 ProfileDeferralMgr.registerDeferral(this.profileActivator);
746 }
747
748 /**
749 * Frees the resources associated with an {@code ICC_Profile} object.
750 *
751 * @deprecated The {@code finalize} method has been deprecated. Subclasses
752 * that override {@code finalize} in order to perform cleanup should
753 * be modified to use alternative cleanup mechanisms and to remove
754 * the overriding {@code finalize} method. When overriding the
755 * {@code finalize} method, its implementation must explicitly
756 * ensure that {@code super.finalize()} is invoked as described in
757 * {@link Object#finalize}. See the specification for {@link
758 * Object#finalize()} for further information about migration
759 * options.
760 */
761 @Deprecated(since="9")
762 protected void finalize () {
763 if (cmmProfile != null) {
764 CMSManager.getModule().freeProfile(cmmProfile);
765 } else if (profileActivator != null) {
766 ProfileDeferralMgr.unregisterDeferral(profileActivator);
767 }
768 }
769
770 /**
771 * Constructs an {@code ICC_Profile} object corresponding to the data in a
772 * byte array. Throws an {@code IllegalArgumentException} if the data does
773 * not correspond to a valid ICC Profile.
774 *
775 * @param data the specified ICC Profile data
776 * @return an {@code ICC_Profile} object corresponding to the data in the
777 * specified {@code data} array
778 */
779 public static ICC_Profile getInstance(byte[] data) {
780 ICC_Profile thisProfile;
781
782 Profile p = null;
783
784 if (ProfileDeferralMgr.deferring) {
785 ProfileDeferralMgr.activateProfiles();
786 }
787
788 ProfileDataVerifier.verify(data);
789
790 try {
791 p = CMSManager.getModule().loadProfile(data);
792 } catch (CMMException c) {
793 throw new IllegalArgumentException("Invalid ICC Profile Data");
794 }
795
796 try {
797 if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
801 }
802 else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
803 (getData (p, icSigMediaWhitePointTag) != null) &&
804 (getData (p, icSigRedColorantTag) != null) &&
805 (getData (p, icSigGreenColorantTag) != null) &&
806 (getData (p, icSigBlueColorantTag) != null) &&
807 (getData (p, icSigRedTRCTag) != null) &&
808 (getData (p, icSigGreenTRCTag) != null) &&
809 (getData (p, icSigBlueTRCTag) != null)) {
810 thisProfile = new ICC_ProfileRGB (p);
811 }
812 else {
813 thisProfile = new ICC_Profile (p);
814 }
815 } catch (CMMException c) {
816 thisProfile = new ICC_Profile (p);
817 }
818 return thisProfile;
819 }
820
821 /**
822 * Constructs an {@code ICC_Profile} corresponding to one of the specific
823 * color spaces defined by the {@code ColorSpace} class (for example
824 * {@code CS_sRGB}). Throws an {@code IllegalArgumentException} if cspace is
825 * not one of the defined color spaces.
826 *
827 * @param cspace the type of color space to create a profile for. The
828 * specified type is one of the color space constants defined in the
829 * {@code ColorSpace} class.
830 * @return an {@code ICC_Profile} object corresponding to the specified
831 * {@code ColorSpace} type
832 * @throws IllegalArgumentException If {@code cspace} is not one of the
833 * predefined color space types
834 */
835 public static ICC_Profile getInstance (int cspace) {
836 ICC_Profile thisProfile = null;
837 String fileName;
838
839 switch (cspace) {
840 case ColorSpace.CS_sRGB:
841 synchronized(ICC_Profile.class) {
842 if (sRGBprofile == null) {
843 /*
844 * Deferral is only used for standard profiles.
845 * Enabling the appropriate access privileges is handled
846 * at a lower level.
847 */
848 ProfileDeferralInfo pInfo =
849 new ProfileDeferralInfo("sRGB.pf",
850 ColorSpace.TYPE_RGB, 3,
851 CLASS_DISPLAY);
852 sRGBprofile = getDeferredInstance(pInfo);
853 }
908 synchronized(ICC_Profile.class) {
909 if (LINEAR_RGBprofile == null) {
910 ProfileDeferralInfo pInfo =
911 new ProfileDeferralInfo("LINEAR_RGB.pf",
912 ColorSpace.TYPE_RGB, 3,
913 CLASS_DISPLAY);
914 LINEAR_RGBprofile = getDeferredInstance(pInfo);
915 }
916 thisProfile = LINEAR_RGBprofile;
917 }
918
919 break;
920
921 default:
922 throw new IllegalArgumentException("Unknown color space");
923 }
924
925 return thisProfile;
926 }
927
928 /**
929 * This method asserts system privileges, so is used only for the standard
930 * profiles.
931 */
932 private static ICC_Profile getStandardProfile(final String name) {
933 return AccessController.doPrivileged(
934 new PrivilegedAction<ICC_Profile>() {
935 public ICC_Profile run() {
936 ICC_Profile p = null;
937 try {
938 p = getInstance(name);
939 } catch (IOException ex) {
940 throw new IllegalArgumentException(
941 "Can't load standard profile: " + name);
942 }
943 return p;
944 }
945 });
946 }
947
948 /**
949 * Constructs an {@code ICC_Profile} corresponding to the data in a file.
950 * {@code fileName} may be an absolute or a relative file specification.
951 * Relative file names are looked for in several places: first, relative to
952 * any directories specified by the {@code java.iccprofile.path} property;
953 * second, relative to any directories specified by the
954 * {@code java.class.path} property; finally, in a directory used to store
955 * profiles always available, such as the profile for sRGB. Built-in
956 * profiles use {@code .pf} as the file name extension for profiles, e.g.
957 * {@code sRGB.pf}. This method throws an {@code IOException} if the
958 * specified file cannot be opened or if an I/O error occurs while reading
959 * the file. It throws an {@code IllegalArgumentException} if the file does
960 * not contain valid ICC Profile data.
961 *
962 * @param fileName the file that contains the data for the profile
963 * @return an {@code ICC_Profile} object corresponding to the data in the
964 * specified file
965 * @throws IOException If the specified file cannot be opened or an I/O
966 * error occurs while reading the file
967 * @throws IllegalArgumentException If the file does not contain valid ICC
968 * Profile data
969 * @throws SecurityException If a security manager is installed and it does
970 * not permit read access to the given file
971 */
972 public static ICC_Profile getInstance(String fileName) throws IOException {
973 ICC_Profile thisProfile;
974 InputStream is = null;
975
976
977 File f = getProfileFile(fileName);
978 if (f != null) {
979 is = new FileInputStream(f);
980 } else {
981 is = getStandardProfileInputStream(fileName);
982 }
983 if (is == null) {
984 throw new IOException("Cannot open file " + fileName);
985 }
986
987 thisProfile = getInstance(is);
988
989 is.close(); /* close the file */
990
991 return thisProfile;
992 }
993
994 /**
995 * Constructs an {@code ICC_Profile} corresponding to the data in an
996 * {@code InputStream}. This method throws an
997 * {@code IllegalArgumentException} if the stream does not contain valid ICC
998 * Profile data. It throws an {@code IOException} if an I/O error occurs
999 * while reading the stream.
1000 *
1001 * @param s the input stream from which to read the profile data
1002 * @return an {@code ICC_Profile} object corresponding to the data in the
1003 * specified {@code InputStream}
1004 * @throws IOException If an I/O error occurs while reading the stream
1005 * @throws IllegalArgumentException If the stream does not contain valid ICC
1006 * Profile data
1007 */
1008 public static ICC_Profile getInstance(InputStream s) throws IOException {
1009 byte[] profileData;
1010
1011 if (s instanceof ProfileDeferralInfo) {
1012 /* hack to detect profiles whose loading can be deferred */
1013 return getDeferredInstance((ProfileDeferralInfo) s);
1014 }
1015
1016 if ((profileData = getProfileDataFromStream(s)) == null) {
1017 throw new IllegalArgumentException("Invalid ICC Profile Data");
1018 }
1019
1020 return getInstance(profileData);
1021 }
1022
1023
1024 static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1025 byte[] profileData;
1026 int profileSize;
1043 }
1044 profileSize = ((header[0] & 0xff) << 24) |
1045 ((header[1] & 0xff) << 16) |
1046 ((header[2] & 0xff) << 8) |
1047 (header[3] & 0xff);
1048 profileData = new byte[profileSize];
1049 System.arraycopy(header, 0, profileData, 0, 128);
1050 bytestoread = profileSize - 128;
1051 bytesread = 128;
1052 while (bytestoread != 0) {
1053 if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1054 return null;
1055 }
1056 bytesread += n;
1057 bytestoread -= n;
1058 }
1059
1060 return profileData;
1061 }
1062
1063 /**
1064 * Constructs an {@code ICC_Profile} for which the actual loading of the
1065 * profile data from a file and the initialization of the CMM should be
1066 * deferred as long as possible. Deferral is only used for standard
1067 * profiles. If deferring is disabled, then getStandardProfile() ensures
1068 * that all of the appropriate access privileges are granted when loading
1069 * this profile. If deferring is enabled, then the deferred activation code
1070 * will take care of access privileges.
1071 *
1072 * @see #activateDeferredProfile()
1073 */
1074 static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1075 if (!ProfileDeferralMgr.deferring) {
1076 return getStandardProfile(pdi.filename);
1077 }
1078 if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1079 return new ICC_ProfileRGB(pdi);
1080 } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1081 return new ICC_ProfileGray(pdi);
1082 } else {
1083 return new ICC_Profile(pdi);
1084 }
1085 }
1086
1087
1088 void activateDeferredProfile() throws ProfileDataException {
1089 byte[] profileData;
1090 final String fileName = deferralInfo.filename;
1091
1102 catch (IOException e) {
1103 ProfileDataException pde = new
1104 ProfileDataException("Invalid ICC Profile Data" + fileName);
1105 pde.initCause(e);
1106 throw pde;
1107 }
1108 if (profileData == null) {
1109 throw new ProfileDataException("Invalid ICC Profile Data" +
1110 fileName);
1111 }
1112 try {
1113 cmmProfile = CMSManager.getModule().loadProfile(profileData);
1114 } catch (CMMException c) {
1115 ProfileDataException pde = new
1116 ProfileDataException("Invalid ICC Profile Data" + fileName);
1117 pde.initCause(c);
1118 throw pde;
1119 }
1120 }
1121
1122 /**
1123 * Returns profile major version.
1124 *
1125 * @return the major version of the profile
1126 */
1127 public int getMajorVersion() {
1128 byte[] theHeader;
1129
1130 theHeader = getData(icSigHead); /* getData will activate deferred
1131 profiles if necessary */
1132
1133 return (int) theHeader[8];
1134 }
1135
1136 /**
1137 * Returns profile minor version.
1138 *
1139 * @return the minor version of the profile
1140 */
1141 public int getMinorVersion() {
1142 byte[] theHeader;
1143
1144 theHeader = getData(icSigHead); /* getData will activate deferred
1145 profiles if necessary */
1146
1147 return (int) theHeader[9];
1148 }
1149
1150 /**
1151 * Returns the profile class.
1152 *
1153 * @return one of the predefined profile class constants
1154 */
1155 public int getProfileClass() {
1156 byte[] theHeader;
1157 int theClassSig, theClass;
1158
1159 if (deferralInfo != null) {
1160 return deferralInfo.profileClass; /* Need to have this info for
1161 ICC_ColorSpace without
1162 causing a deferred profile
1163 to be loaded */
1164 }
1165
1166 theHeader = getData(icSigHead);
1167
1168 theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1169
1170 switch (theClassSig) {
1171 case icSigInputClass:
1172 theClass = CLASS_INPUT;
1173 break;
1188 theClass = CLASS_COLORSPACECONVERSION;
1189 break;
1190
1191 case icSigAbstractClass:
1192 theClass = CLASS_ABSTRACT;
1193 break;
1194
1195 case icSigNamedColorClass:
1196 theClass = CLASS_NAMEDCOLOR;
1197 break;
1198
1199 default:
1200 throw new IllegalArgumentException("Unknown profile class");
1201 }
1202
1203 return theClass;
1204 }
1205
1206 /**
1207 * Returns the color space type. Returns one of the color space type
1208 * constants defined by the {@code ColorSpace} class. This is the "input"
1209 * color space of the profile. The type defines the number of components of
1210 * the color space and the interpretation, e.g. {@code TYPE_RGB} identifies
1211 * a color space with three components - red, green, and blue. It does not
1212 * define the particular color characteristics of the space, e.g. the
1213 * chromaticities of the primaries.
1214 *
1215 * @return one of the color space type constants defined in the
1216 * {@code ColorSpace} class
1217 */
1218 public int getColorSpaceType() {
1219 if (deferralInfo != null) {
1220 return deferralInfo.colorSpaceType; /* Need to have this info for
1221 ICC_ColorSpace without
1222 causing a deferred profile
1223 to be loaded */
1224 }
1225 return getColorSpaceType(cmmProfile);
1226 }
1227
1228 static int getColorSpaceType(Profile p) {
1229 byte[] theHeader;
1230 int theColorSpaceSig, theColorSpace;
1231
1232 theHeader = getData(p, icSigHead);
1233 theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1234 theColorSpace = iccCStoJCS (theColorSpaceSig);
1235 return theColorSpace;
1236 }
1237
1238 /**
1239 * Returns the color space type of the Profile Connection Space (PCS).
1240 * Returns one of the color space type constants defined by the ColorSpace
1241 * class. This is the "output" color space of the profile. For an input,
1242 * display, or output profile useful for tagging colors or images, this will
1243 * be either {@code TYPE_XYZ} or {@code TYPE_Lab} and should be interpreted
1244 * as the corresponding specific color space defined in the ICC
1245 * specification. For a device link profile, this could be any of the color
1246 * space type constants.
1247 *
1248 * @return one of the color space type constants defined in the
1249 * {@code ColorSpace} class
1250 */
1251 public int getPCSType() {
1252 if (ProfileDeferralMgr.deferring) {
1253 ProfileDeferralMgr.activateProfiles();
1254 }
1255 return getPCSType(cmmProfile);
1256 }
1257
1258
1259 static int getPCSType(Profile p) {
1260 byte[] theHeader;
1261 int thePCSSig, thePCS;
1262
1263 theHeader = getData(p, icSigHead);
1264 thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1265 thePCS = iccCStoJCS(thePCSSig);
1266 return thePCS;
1267 }
1268
1269 /**
1270 * Write this {@code ICC_Profile} to a file.
1271 *
1272 * @param fileName the file to write the profile data to
1273 * @throws IOException If the file cannot be opened for writing or an I/O
1274 * error occurs while writing to the file
1275 */
1276 public void write(String fileName) throws IOException {
1277 FileOutputStream outputFile;
1278 byte[] profileData;
1279
1280 profileData = getData(); /* this will activate deferred
1281 profiles if necessary */
1282 outputFile = new FileOutputStream(fileName);
1283 outputFile.write(profileData);
1284 outputFile.close ();
1285 }
1286
1287 /**
1288 * Write this {@code ICC_Profile} to an {@code OutputStream}.
1289 *
1290 * @param s the stream to write the profile data to
1291 * @throws IOException If an I/O error occurs while writing to the stream
1292 */
1293 public void write(OutputStream s) throws IOException {
1294 byte[] profileData;
1295
1296 profileData = getData(); /* this will activate deferred
1297 profiles if necessary */
1298 s.write(profileData);
1299 }
1300
1301 /**
1302 * Returns a byte array corresponding to the data of this
1303 * {@code ICC_Profile}.
1304 *
1305 * @return a byte array that contains the profile data
1306 * @see #setData(int, byte[])
1307 */
1308 public byte[] getData() {
1309 int profileSize;
1310 byte[] profileData;
1311
1312 if (ProfileDeferralMgr.deferring) {
1313 ProfileDeferralMgr.activateProfiles();
1314 }
1315
1316 PCMM mdl = CMSManager.getModule();
1317
1318 /* get the number of bytes needed for this profile */
1319 profileSize = mdl.getProfileSize(cmmProfile);
1320
1321 profileData = new byte [profileSize];
1322
1323 /* get the data for the profile */
1324 mdl.getProfileData(cmmProfile, profileData);
1325
1326 return profileData;
1327 }
1328
1329 /**
1330 * Returns a particular tagged data element from the profile as a byte
1331 * array. Elements are identified by signatures as defined in the ICC
1332 * specification. The signature icSigHead can be used to get the header.
1333 * This method is useful for advanced applets or applications which need to
1334 * access profile data directly.
1335 *
1336 * @param tagSignature the ICC tag signature for the data element you want
1337 * to get
1338 * @return a byte array that contains the tagged data element. Returns
1339 * {@code null} if the specified tag doesn't exist.
1340 * @see #setData(int, byte[])
1341 */
1342 public byte[] getData(int tagSignature) {
1343
1344 if (ProfileDeferralMgr.deferring) {
1345 ProfileDeferralMgr.activateProfiles();
1346 }
1347
1348 return getData(cmmProfile, tagSignature);
1349 }
1350
1351
1352 static byte[] getData(Profile p, int tagSignature) {
1353 int tagSize;
1354 byte[] tagData;
1355
1356 try {
1357 PCMM mdl = CMSManager.getModule();
1358
1359 /* get the number of bytes needed for this tag */
1360 tagSize = mdl.getTagSize(p, tagSignature);
1361
1362 tagData = new byte[tagSize]; /* get an array for the tag */
1363
1364 /* get the tag's data */
1365 mdl.getTagData(p, tagSignature, tagData);
1366 } catch(CMMException c) {
1367 tagData = null;
1368 }
1369
1370 return tagData;
1371 }
1372
1373 /**
1374 * Sets a particular tagged data element in the profile from a byte array.
1375 * The array should contain data in a format, corresponded to the
1376 * {@code tagSignature} as defined in the ICC specification, section 10.
1377 * This method is useful for advanced applets or applications which need to
1378 * access profile data directly.
1379 *
1380 * @param tagSignature the ICC tag signature for the data element you want
1381 * to set
1382 * @param tagData the data to set for the specified tag signature
1383 * @throws IllegalArgumentException if {@code tagSignature} is not a
1384 * signature as defined in the ICC specification.
1385 * @throws IllegalArgumentException if a content of the {@code tagData}
1386 * array can not be interpreted as valid tag data, corresponding to
1387 * the {@code tagSignature}
1388 * @see #getData
1389 */
1390 public void setData(int tagSignature, byte[] tagData) {
1391
1392 if (ProfileDeferralMgr.deferring) {
1393 ProfileDeferralMgr.activateProfiles();
1394 }
1395
1396 CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
1397 }
1398
1399 /**
1400 * Sets the rendering intent of the profile. This is used to select the
1401 * proper transform from a profile that has multiple transforms.
1402 */
1403 void setRenderingIntent(int renderingIntent) {
1404 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1405 profiles if necessary */
1406 intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1407 /* set the rendering intent */
1408 setData (icSigHead, theHeader);
1409 }
1410
1411 /**
1412 * Returns the rendering intent of the profile. This is used to select the
1413 * proper transform from a profile that has multiple transforms. It is
1414 * typically set in a source profile to select a transform from an output
1415 * profile.
1416 */
1417 int getRenderingIntent() {
1418 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1419 profiles if necessary */
1420
1421 int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1422 /* set the rendering intent */
1423
1424 /* According to ICC spec, only the least-significant 16 bits shall be
1425 * used to encode the rendering intent. The most significant 16 bits
1426 * shall be set to zero. Thus, we are ignoring two most significant
1427 * bytes here.
1428 *
1429 * See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
1430 */
1431 return (0xffff & renderingIntent);
1432 }
1433
1434 /**
1435 * Returns the number of color components in the "input" color space of this
1436 * profile. For example if the color space type of this profile is
1437 * {@code TYPE_RGB}, then this method will return 3.
1438 *
1439 * @return the number of color components in the profile's input color space
1440 * @throws ProfileDataException if color space is in the profile is invalid
1441 */
1442 public int getNumComponents() {
1443 byte[] theHeader;
1444 int theColorSpaceSig, theNumComponents;
1445
1446 if (deferralInfo != null) {
1447 return deferralInfo.numComponents; /* Need to have this info for
1448 ICC_ColorSpace without
1449 causing a deferred profile
1450 to be loaded */
1451 }
1452 theHeader = getData(icSigHead);
1453
1454 theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1455
1456 switch (theColorSpaceSig) {
1457 case icSigGrayData:
1458 theNumComponents = 1;
1459 break;
1460
1514
1515 case icSigSpaceDCLR:
1516 theNumComponents = 13;
1517 break;
1518
1519 case icSigSpaceECLR:
1520 theNumComponents = 14;
1521 break;
1522
1523 case icSigSpaceFCLR:
1524 theNumComponents = 15;
1525 break;
1526
1527 default:
1528 throw new ProfileDataException ("invalid ICC color space");
1529 }
1530
1531 return theNumComponents;
1532 }
1533
1534 /**
1535 * Returns a float array of length 3 containing the X, Y, and Z components
1536 * of the mediaWhitePointTag in the ICC profile.
1537 */
1538 float[] getMediaWhitePoint() {
1539 return getXYZTag(icSigMediaWhitePointTag);
1540 /* get the media white point tag */
1541 }
1542
1543 /**
1544 * Returns a float array of length 3 containing the X, Y, and Z components
1545 * encoded in an XYZType tag.
1546 */
1547 float[] getXYZTag(int theTagSignature) {
1548 byte[] theData;
1549 float[] theXYZNumber;
1550 int i1, i2, theS15Fixed16;
1551
1552 theData = getData(theTagSignature); /* get the tag data */
1553 /* getData will activate deferred
1554 profiles if necessary */
1555
1556 theXYZNumber = new float [3]; /* array to return */
1557
1558 /* convert s15Fixed16Number to float */
1559 for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1560 theS15Fixed16 = intFromBigEndian(theData, i2);
1561 theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1562 }
1563 return theXYZNumber;
1564 }
1565
1566 /**
1567 * Returns a gamma value representing a tone reproduction curve (TRC). If
1568 * the profile represents the TRC as a table rather than a single gamma
1569 * value, then an exception is thrown. In this case the actual table can be
1570 * obtained via {@link #getTRC}. {@code theTagSignature} should be one of
1571 * {@code icSigGrayTRCTag}, {@code icSigRedTRCTag},
1572 * {@code icSigGreenTRCTag}, or {@code icSigBlueTRCTag}.
1573 *
1574 * @return the gamma value as a float
1575 * @throws ProfileDataException if the profile does not specify the TRC as a
1576 * single gamma value
1577 */
1578 float getGamma(int theTagSignature) {
1579 byte[] theTRCData;
1580 float theGamma;
1581 int theU8Fixed8;
1582
1583 theTRCData = getData(theTagSignature); /* get the TRC */
1584 /* getData will activate deferred
1585 profiles if necessary */
1586
1587 if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1588 throw new ProfileDataException ("TRC is not a gamma");
1589 }
1590
1591 /* convert u8Fixed8 to float */
1592 theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1593
1594 theGamma = ((float) theU8Fixed8) / 256.0f;
1595
1596 return theGamma;
1597 }
1598
1599 /**
1600 * Returns the TRC as an array of shorts. If the profile has specified the
1601 * TRC as linear (gamma = 1.0) or as a simple gamma value, this method
1602 * throws an exception, and the {@link #getGamma} method should be used to
1603 * get the gamma value. Otherwise the short array returned here represents a
1604 * lookup table where the input Gray value is conceptually in the range
1605 * [0.0, 1.0]. Value 0.0 maps to array index 0 and value 1.0 maps to array
1606 * index length-1. Interpolation may be used to generate output values for
1607 * input values which do not map exactly to an index in the array. Output
1608 * values also map linearly to the range [0.0, 1.0]. Value 0.0 is
1609 * represented by an array value of 0x0000 and value 1.0 by 0xFFFF, i.e. the
1610 * values are really unsigned short values, although they are returned in a
1611 * short array. {@code theTagSignature} should be one of
1612 * {@code icSigGrayTRCTag}, {@code icSigRedTRCTag},
1613 * {@code icSigGreenTRCTag}, or {@code icSigBlueTRCTag}.
1614 *
1615 * @return a short array representing the TRC
1616 * @throws ProfileDataException if the profile does not specify the TRC as a
1617 * table
1618 */
1619 short[] getTRC(int theTagSignature) {
1620 byte[] theTRCData;
1621 short[] theTRC;
1622 int i1, i2, nElements, theU8Fixed8;
1623
1624 theTRCData = getData(theTagSignature); /* get the TRC */
1625 /* getData will activate deferred
1626 profiles if necessary */
1627
1628 nElements = intFromBigEndian(theTRCData, icCurveCount);
1629
1630 if (nElements == 1) {
1631 throw new ProfileDataException("TRC is not a table");
1632 }
1633
1634 /* make the short array */
1635 theTRC = new short [nElements];
1636
1637 for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1638 theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1639 }
1640
1641 return theTRC;
1642 }
1643
1644 /**
1645 * Convert an ICC color space signature into a Java color space type.
1646 */
1647 static int iccCStoJCS(int theColorSpaceSig) {
1648 int theColorSpace;
1649
1650 switch (theColorSpaceSig) {
1651 case icSigXYZData:
1652 theColorSpace = ColorSpace.TYPE_XYZ;
1653 break;
1654
1655 case icSigLabData:
1656 theColorSpace = ColorSpace.TYPE_Lab;
1657 break;
1658
1659 case icSigLuvData:
1660 theColorSpace = ColorSpace.TYPE_Luv;
1661 break;
1662
1663 case icSigYCbCrData:
1664 theColorSpace = ColorSpace.TYPE_YCbCr;
1665 break;
1666
1734
1735 case icSigSpaceCCLR:
1736 theColorSpace = ColorSpace.TYPE_CCLR;
1737 break;
1738
1739 case icSigSpaceDCLR:
1740 theColorSpace = ColorSpace.TYPE_DCLR;
1741 break;
1742
1743 case icSigSpaceECLR:
1744 theColorSpace = ColorSpace.TYPE_ECLR;
1745 break;
1746
1747 case icSigSpaceFCLR:
1748 theColorSpace = ColorSpace.TYPE_FCLR;
1749 break;
1750
1751 default:
1752 throw new IllegalArgumentException ("Unknown color space");
1753 }
1754 return theColorSpace;
1755 }
1756
1757
1758 static int intFromBigEndian(byte[] array, int index) {
1759 return (((array[index] & 0xff) << 24) |
1760 ((array[index+1] & 0xff) << 16) |
1761 ((array[index+2] & 0xff) << 8) |
1762 (array[index+3] & 0xff));
1763 }
1764
1765
1766 static void intToBigEndian(int value, byte[] array, int index) {
1767 array[index] = (byte) (value >> 24);
1768 array[index+1] = (byte) (value >> 16);
1769 array[index+2] = (byte) (value >> 8);
1770 array[index+3] = (byte) (value);
1771 }
1772
1773
1774 static short shortFromBigEndian(byte[] array, int index) {
1775 return (short) (((array[index] & 0xff) << 8) |
1776 (array[index+1] & 0xff));
1777 }
1778
1779
1780 static void shortToBigEndian(short value, byte[] array, int index) {
1781 array[index] = (byte) (value >> 8);
1782 array[index+1] = (byte) (value);
1783 }
1784
1785 /**
1786 * {@code fileName} may be an absolute or a relative file specification.
1787 * Relative file names are looked for in several places: first, relative to
1788 * any directories specified by the {@code java.iccprofile.path} property;
1789 * second, relative to any directories specified by the
1790 * {@code java.class.path}. The built-in profile files are now loaded as
1791 * resources, since they may not be individual disk files, and so this
1792 * method will not find these and on a {@code null} return, the caller needs
1793 * to try as resources. Built-in profiles use {@code .pf} as the file name
1794 * extension for profiles, e.g. {@code sRGB.pf}.
1795 */
1796 private static File getProfileFile(String fileName) {
1797 String path, dir, fullPath;
1798
1799 File f = new File(fileName); /* try absolute file name */
1800 if (f.isAbsolute()) {
1801 /* Rest of code has little sense for an absolute pathname,
1802 so return here. */
1803 return f.isFile() ? f : null;
1804 }
1805 if ((!f.isFile()) &&
1806 ((path = System.getProperty("java.iccprofile.path")) != null)){
1807 /* try relative to java.iccprofile.path */
1808 StringTokenizer st =
1809 new StringTokenizer(path, File.pathSeparator);
1810 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1811 dir = st.nextToken();
1812 fullPath = dir + File.separatorChar + fileName;
1813 f = new File(fullPath);
1814 if (!isChildOf(f, dir)) {
1819
1820 if (((f == null) || (!f.isFile())) &&
1821 ((path = System.getProperty("java.class.path")) != null)) {
1822 /* try relative to java.class.path */
1823 StringTokenizer st =
1824 new StringTokenizer(path, File.pathSeparator);
1825 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1826 dir = st.nextToken();
1827 fullPath = dir + File.separatorChar + fileName;
1828 f = new File(fullPath);
1829 }
1830 }
1831
1832 if (f != null && !f.isFile()) {
1833 f = null;
1834 }
1835 return f;
1836 }
1837
1838 /**
1839 * Returns a stream corresponding to a built-in profile specified by
1840 * fileName. If there is no built-in profile with such name, then the method
1841 * returns {@code null}.
1842 */
1843 private static InputStream getStandardProfileInputStream(String fileName) {
1844 return AccessController.doPrivileged(
1845 new PrivilegedAction<InputStream>() {
1846 public InputStream run () {
1847 return
1848 PCMM.class.getResourceAsStream("profiles/" + fileName);
1849 }
1850 }, null, new FilePermission("<<ALL FILES>>", "read"),
1851 new RuntimePermission("accessSystemModules"));
1852 }
1853
1854 /**
1855 * Checks whether given file resides inside give directory.
1856 */
1857 private static boolean isChildOf(File f, String dirName) {
1858 try {
1859 File dir = new File(dirName);
1860 String canonicalDirName = dir.getCanonicalPath();
1861 if (!canonicalDirName.endsWith(File.separator)) {
1865 return canonicalFileName.startsWith(canonicalDirName);
1866 } catch (IOException e) {
1867 /* we do not expect the IOException here, because invocation
1868 * of this function is always preceded by isFile() call.
1869 */
1870 return false;
1871 }
1872 }
1873
1874 /**
1875 * Checks whether built-in profile specified by fileName exists.
1876 */
1877 private static boolean standardProfileExists(final String fileName) {
1878 return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1879 public Boolean run() {
1880 return PCMM.class.getResource("profiles/"+fileName) != null;
1881 }
1882 });
1883 }
1884
1885 /*
1886 * Serialization support.
1887 *
1888 * Directly deserialized profiles are useless since they are not registered
1889 * with CMM. We don't allow constructor to be called directly and instead
1890 * have clients to call one of getInstance factory methods that will
1891 * register the profile with CMM. For deserialization we implement
1892 * readResolve method that will resolve the bogus deserialized profile
1893 * object with one obtained with getInstance as well.
1894 *
1895 * There are two primary factory methods for construction of ICC profiles:
1896 * getInstance(int cspace) and getInstance(byte[] data). This implementation
1897 * of ICC_Profile uses the former to return a cached singleton profile
1898 * object, other implementations will likely use this technique too. To
1899 * preserve the singleton pattern across serialization we serialize cached
1900 * singleton profiles in such a way that deserializing VM could call
1901 * getInstance(int cspace) method that will resolve deserialized object into
1902 * the corresponding singleton as well.
1903 *
1904 * Since the singletons are private to ICC_Profile the readResolve method
1905 * have to be `protected' instead of `private' so that singletons that are
1906 * instances of subclasses of ICC_Profile could be correctly deserialized.
1907 */
1908
1909 /**
1910 * Version of the format of additional serialized data in the stream.
1911 * Version {@code 1} corresponds to Java 2 Platform, v1.3.
1912 *
1913 * @serial
1914 * @since 1.3
1915 */
1916 private int iccProfileSerializedDataVersion = 1;
1917
1918 /**
1919 * Writes default serializable fields to the stream. Writes a string and an
1920 * array of bytes to the stream as additional data.
1921 *
1922 * @param s stream used for serialization
1923 * @throws IOException thrown by {@code ObjectInputStream}
1924 * @serialData the {@code String} is the name of one of
1925 * <code>CS_<var>*</var></code> constants defined in the
1926 * {@link ColorSpace} class if the profile object is a profile for a
1927 * predefined color space (for example {@code "CS_sRGB"}). The
1928 * string is {@code null} otherwise.
1929 * <p>
1930 * The {@code byte[]} array is the profile data for the profile. For
1931 * predefined color spaces {@code null} is written instead of the
1932 * profile data. If in the future versions of Java API new
1933 * predefined color spaces will be added, future versions of this
1934 * class may choose to write for new predefined color spaces not
1935 * only the color space name, but the profile data as well so that
1936 * older versions could still deserialize the object.
1937 */
1938 private void writeObject(ObjectOutputStream s)
1939 throws IOException
1940 {
1941 s.defaultWriteObject();
1942
1943 String csName = null;
1944 if (this == sRGBprofile) {
1945 csName = "CS_sRGB";
1946 } else if (this == XYZprofile) {
1947 csName = "CS_CIEXYZ";
1948 } else if (this == PYCCprofile) {
1949 csName = "CS_PYCC";
1950 } else if (this == GRAYprofile) {
1951 csName = "CS_GRAY";
1952 } else if (this == LINEAR_RGBprofile) {
1953 csName = "CS_LINEAR_RGB";
1954 }
1955
1956 // Future versions may choose to write profile data for new
1957 // predefined color spaces as well, if any will be introduced,
1958 // so that old versions that don't recognize the new CS name
1959 // may fall back to constructing profile from the data.
1960 byte[] data = null;
1961 if (csName == null) {
1962 // getData will activate deferred profile if necessary
1963 data = getData();
1964 }
1965
1966 s.writeObject(csName);
1967 s.writeObject(data);
1968 }
1969
1970 // Temporary storage used by readObject to store resolved profile
1971 // (obtained with getInstance) for readResolve to return.
1972 private transient ICC_Profile resolvedDeserializedProfile;
1973
1974 /**
1975 * Reads default serializable fields from the stream. Reads from the stream
1976 * a string and an array of bytes as additional data.
1977 *
1978 * @param s stream used for deserialization
1979 * @throws IOException thrown by {@code ObjectInputStream}
1980 * @throws ClassNotFoundException thrown by {@code
1981 * ObjectInputStream}
1982 * @serialData the {@code String} is the name of one of
1983 * <code>CS_<var>*</var></code> constants defined in the
1984 * {@link ColorSpace} class if the profile object is a profile for a
1985 * predefined color space (for example {@code "CS_sRGB"}). The
1986 * string is {@code null} otherwise.
1987 * <p>
1988 * The {@code byte[]} array is the profile data for the profile. It
1989 * will usually be {@code null} for the predefined profiles.
1990 * <p>
1991 * If the string is recognized as a constant name for predefined
1992 * color space the object will be resolved into profile obtained
1993 * with
1994 * <code>getInstance(int cspace)</code> and the profile data
1995 * are
1996 * ignored. Otherwise the object will be resolved into profile
1997 * obtained with
1998 * <code>getInstance(byte[] data)</code>.
1999 * @see #readResolve()
2000 * @see #getInstance(int)
2001 * @see #getInstance(byte[])
2002 */
2003 private void readObject(ObjectInputStream s)
2004 throws IOException, ClassNotFoundException
2005 {
2006 s.defaultReadObject();
2007
2008 String csName = (String)s.readObject();
2009 byte[] data = (byte[])s.readObject();
2010
2011 int cspace = 0; // ColorSpace.CS_* constant if known
2012 boolean isKnownPredefinedCS = false;
2013 if (csName != null) {
2014 isKnownPredefinedCS = true;
2015 if (csName.equals("CS_sRGB")) {
2016 cspace = ColorSpace.CS_sRGB;
2017 } else if (csName.equals("CS_CIEXYZ")) {
2018 cspace = ColorSpace.CS_CIEXYZ;
2019 } else if (csName.equals("CS_PYCC")) {
2020 cspace = ColorSpace.CS_PYCC;
2021 } else if (csName.equals("CS_GRAY")) {
2022 cspace = ColorSpace.CS_GRAY;
2023 } else if (csName.equals("CS_LINEAR_RGB")) {
2024 cspace = ColorSpace.CS_LINEAR_RGB;
2025 } else {
2026 isKnownPredefinedCS = false;
2027 }
2028 }
2029
2030 if (isKnownPredefinedCS) {
2031 resolvedDeserializedProfile = getInstance(cspace);
2032 } else {
2033 resolvedDeserializedProfile = getInstance(data);
2034 }
2035 }
2036
2037 /**
2038 * Resolves instances being deserialized into instances registered with CMM.
2039 *
2040 * @return ICC_Profile object for profile registered with CMM
2041 * @throws ObjectStreamException never thrown, but mandated by the
2042 * serialization spec
2043 * @since 1.3
2044 */
2045 protected Object readResolve() throws ObjectStreamException {
2046 return resolvedDeserializedProfile;
2047 }
2048 }
|