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