1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. 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. 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 159 /** 160 * ICC Profile Color Space Type Signature: 'Yxy '. 161 */ 162 public static final int icSigYxyData = 0x59787920; /* 'Yxy ' */ 163 164 /** 165 * ICC Profile Color Space Type Signature: 'RGB '. 166 */ 167 public static final int icSigRgbData = 0x52474220; /* 'RGB ' */ 168 169 /** 170 * ICC Profile Color Space Type Signature: 'GRAY'. 171 */ 172 public static final int icSigGrayData = 0x47524159; /* 'GRAY' */ 173 174 /** 175 * ICC Profile Color Space Type Signature: 'HSV'. 176 */ 177 public static final int icSigHsvData = 0x48535620; /* 'HSV ' */ 178 179 /** 180 * ICC Profile Color Space Type Signature: 'HLS'. 181 */ 182 public static final int icSigHlsData = 0x484C5320; /* 'HLS ' */ 183 184 /** 185 * ICC Profile Color Space Type Signature: 'CMYK'. 186 */ 187 public static final int icSigCmykData = 0x434D594B; /* 'CMYK' */ 188 189 /** 190 * ICC Profile Color Space Type Signature: 'CMY '. 191 */ 192 public static final int icSigCmyData = 0x434D5920; /* 'CMY ' */ 193 194 /** 195 * ICC Profile Color Space Type Signature: '2CLR'. 196 */ 197 public static final int icSigSpace2CLR = 0x32434C52; /* '2CLR' */ 198 199 /** 200 * ICC Profile Color Space Type Signature: '3CLR'. 201 */ 202 public static final int icSigSpace3CLR = 0x33434C52; /* '3CLR' */ 203 204 /** 205 * ICC Profile Color Space Type Signature: '4CLR'. 206 */ 207 public static final int icSigSpace4CLR = 0x34434C52; /* '4CLR' */ 208 209 /** 210 * ICC Profile Color Space Type Signature: '5CLR'. 211 */ 212 public static final int icSigSpace5CLR = 0x35434C52; /* '5CLR' */ 213 214 /** 215 * ICC Profile Color Space Type Signature: '6CLR'. 216 */ 217 public static final int icSigSpace6CLR = 0x36434C52; /* '6CLR' */ 218 219 /** 220 * ICC Profile Color Space Type Signature: '7CLR'. 221 */ 222 public static final int icSigSpace7CLR = 0x37434C52; /* '7CLR' */ 223 224 /** 225 * ICC Profile Color Space Type Signature: '8CLR'. 226 */ 227 public static final int icSigSpace8CLR = 0x38434C52; /* '8CLR' */ 228 229 /** 230 * ICC Profile Color Space Type Signature: '9CLR'. 231 */ 232 public static final int icSigSpace9CLR = 0x39434C52; /* '9CLR' */ 233 234 /** 235 * ICC Profile Color Space Type Signature: 'ACLR'. 236 */ 237 public static final int icSigSpaceACLR = 0x41434C52; /* 'ACLR' */ 238 239 /** 240 * ICC Profile Color Space Type Signature: 'BCLR'. 241 */ 242 public static final int icSigSpaceBCLR = 0x42434C52; /* 'BCLR' */ 243 244 /** 245 * ICC Profile Color Space Type Signature: 'CCLR'. 246 */ 247 public static final int icSigSpaceCCLR = 0x43434C52; /* 'CCLR' */ 248 249 /** 250 * ICC Profile Color Space Type Signature: 'DCLR'. 251 */ 252 public static final int icSigSpaceDCLR = 0x44434C52; /* 'DCLR' */ 253 254 /** 255 * ICC Profile Color Space Type Signature: 'ECLR'. 256 */ 257 public static final int icSigSpaceECLR = 0x45434C52; /* 'ECLR' */ 258 259 /** 260 * ICC Profile Color Space Type Signature: 'FCLR'. 261 */ 262 public static final int icSigSpaceFCLR = 0x46434C52; /* 'FCLR' */ 263 264 265 /** 266 * ICC Profile Class Signature: 'scnr'. 267 */ 268 public static final int icSigInputClass = 0x73636E72; /* 'scnr' */ 269 270 /** 271 * ICC Profile Class Signature: 'mntr'. 272 */ 273 public static final int icSigDisplayClass = 0x6D6E7472; /* 'mntr' */ 274 275 /** 276 * ICC Profile Class Signature: 'prtr'. 277 */ 278 public static final int icSigOutputClass = 0x70727472; /* 'prtr' */ 279 280 /** 281 * ICC Profile Class Signature: 'link'. 282 */ 283 public static final int icSigLinkClass = 0x6C696E6B; /* 'link' */ 284 285 /** 286 * ICC Profile Class Signature: 'abst'. 287 */ 288 public static final int icSigAbstractClass = 0x61627374; /* 'abst' */ 289 290 /** 291 * ICC Profile Class Signature: 'spac'. 292 */ 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 /** 384 * ICC Profile Tag Signature: 'B2A2'. 385 */ 386 public static final int icSigBToA2Tag = 0x42324132; /* 'B2A2' */ 387 388 /** 389 * ICC Profile Tag Signature: 'calt'. 390 */ 391 public static final int icSigCalibrationDateTimeTag = 0x63616C74; 392 /* 'calt' */ 393 394 /** 395 * ICC Profile Tag Signature: 'targ'. 396 */ 397 public static final int icSigCharTargetTag = 0x74617267; /* 'targ' */ 398 399 /** 400 * ICC Profile Tag Signature: 'cprt'. 401 */ 402 public static final int icSigCopyrightTag = 0x63707274; /* 'cprt' */ 403 404 /** 405 * ICC Profile Tag Signature: 'crdi'. 406 */ 407 public static final int icSigCrdInfoTag = 0x63726469; /* 'crdi' */ 408 409 /** 410 * ICC Profile Tag Signature: 'dmnd'. 411 */ 412 public static final int icSigDeviceMfgDescTag = 0x646D6E64; /* 'dmnd' */ 413 414 /** 415 * ICC Profile Tag Signature: 'dmdd'. 416 */ 417 public static final int icSigDeviceModelDescTag = 0x646D6464; /* 'dmdd' */ 418 419 /** 420 * ICC Profile Tag Signature: 'devs'. 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 /** 462 * ICC Profile Tag Signature: 'bkpt'. 463 */ 464 public static final int icSigMediaBlackPointTag = 0x626B7074; /* 'bkpt' */ 465 466 /** 467 * ICC Profile Tag Signature: 'wtpt'. 468 */ 469 public static final int icSigMediaWhitePointTag = 0x77747074; /* 'wtpt' */ 470 471 /** 472 * ICC Profile Tag Signature: 'ncl2'. 473 */ 474 public static final int icSigNamedColor2Tag = 0x6E636C32; /* 'ncl2' */ 475 476 /** 477 * ICC Profile Tag Signature: 'resp'. 478 */ 479 public static final int icSigOutputResponseTag = 0x72657370; /* 'resp' */ 480 481 /** 482 * ICC Profile Tag Signature: 'pre0'. 483 */ 484 public static final int icSigPreview0Tag = 0x70726530; /* 'pre0' */ 485 486 /** 487 * ICC Profile Tag Signature: 'pre1'. 488 */ 489 public static final int icSigPreview1Tag = 0x70726531; /* 'pre1' */ 490 491 /** 492 * ICC Profile Tag Signature: 'pre2'. 493 */ 494 public static final int icSigPreview2Tag = 0x70726532; /* 'pre2' */ 495 496 /** 497 * ICC Profile Tag Signature: 'desc'. 498 */ 499 public static final int icSigProfileDescriptionTag = 0x64657363; 500 /* 'desc' */ 501 502 /** 503 * ICC Profile Tag Signature: 'pseq'. 504 */ 505 public static final int icSigProfileSequenceDescTag = 0x70736571; 506 /* 'pseq' */ 507 508 /** 509 * ICC Profile Tag Signature: 'psd0'. 510 */ 511 public static final int icSigPs2CRD0Tag = 0x70736430; /* 'psd0' */ 512 513 /** 514 * ICC Profile Tag Signature: 'psd1'. 515 */ 516 public static final int icSigPs2CRD1Tag = 0x70736431; /* 'psd1' */ 517 518 /** 519 * ICC Profile Tag Signature: 'psd2'. 520 */ 521 public static final int icSigPs2CRD2Tag = 0x70736432; /* 'psd2' */ 522 523 /** 524 * ICC Profile Tag Signature: 'psd3'. 525 */ 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 /** 567 * ICC Profile Tag Signature: 'tech'. 568 */ 569 public static final int icSigTechnologyTag = 0x74656368; /* 'tech' */ 570 571 /** 572 * ICC Profile Tag Signature: 'bfd '. 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 628 /** 629 * ICC Profile Header Location: type of profile. 630 */ 631 public static final int icHdrDeviceClass = 12; /* Type of profile */ 632 633 /** 634 * ICC Profile Header Location: color space of data. 635 */ 636 public static final int icHdrColorSpace = 16; /* Color space of data */ 637 638 /** 639 * ICC Profile Header Location: PCS - XYZ or Lab only. 640 */ 641 public static final int icHdrPcs = 20; /* PCS - XYZ or Lab only */ 642 643 /** 644 * ICC Profile Header Location: date profile was created. 645 */ 646 public static final int icHdrDate = 24; /* Date profile was created */ 647 648 /** 649 * ICC Profile Header Location: icMagicNumber. 650 */ 651 public static final int icHdrMagic = 36; /* icMagicNumber */ 652 653 /** 654 * ICC Profile Header Location: primary platform. 655 */ 656 public static final int icHdrPlatform = 40; /* Primary Platform */ 657 658 /** 659 * ICC Profile Header Location: various bit settings. 660 */ 661 public static final int icHdrFlags = 44; /* Various bit settings */ 662 663 /** 664 * ICC Profile Header Location: device manufacturer. 665 */ 666 public static final int icHdrManufacturer = 48; /* Device manufacturer */ 667 668 /** 669 * ICC Profile Header Location: device model number. 670 */ 671 public static final int icHdrModel = 52; /* Device model number */ 672 673 /** 674 * ICC Profile Header Location: device attributes. 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) && 798 (getData (p, icSigMediaWhitePointTag) != null) && 799 (getData (p, icSigGrayTRCTag) != null)) { 800 thisProfile = new ICC_ProfileGray (p); 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 } 854 thisProfile = sRGBprofile; 855 } 856 857 break; 858 859 case ColorSpace.CS_CIEXYZ: 860 synchronized(ICC_Profile.class) { 861 if (XYZprofile == null) { 862 ProfileDeferralInfo pInfo = 863 new ProfileDeferralInfo("CIEXYZ.pf", 864 ColorSpace.TYPE_XYZ, 3, 865 CLASS_DISPLAY); 866 XYZprofile = getDeferredInstance(pInfo); 867 } 868 thisProfile = XYZprofile; 869 } 870 871 break; 872 873 case ColorSpace.CS_PYCC: 874 synchronized(ICC_Profile.class) { 875 if (PYCCprofile == null) { 876 if (standardProfileExists("PYCC.pf")) 877 { 878 ProfileDeferralInfo pInfo = 879 new ProfileDeferralInfo("PYCC.pf", 880 ColorSpace.TYPE_3CLR, 3, 881 CLASS_DISPLAY); 882 PYCCprofile = getDeferredInstance(pInfo); 883 } else { 884 throw new IllegalArgumentException( 885 "Can't load standard profile: PYCC.pf"); 886 } 887 } 888 thisProfile = PYCCprofile; 889 } 890 891 break; 892 893 case ColorSpace.CS_GRAY: 894 synchronized(ICC_Profile.class) { 895 if (GRAYprofile == null) { 896 ProfileDeferralInfo pInfo = 897 new ProfileDeferralInfo("GRAY.pf", 898 ColorSpace.TYPE_GRAY, 1, 899 CLASS_DISPLAY); 900 GRAYprofile = getDeferredInstance(pInfo); 901 } 902 thisProfile = GRAYprofile; 903 } 904 905 break; 906 907 case ColorSpace.CS_LINEAR_RGB: 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; 1027 1028 byte[] header = new byte[128]; 1029 int bytestoread = 128; 1030 int bytesread = 0; 1031 int n; 1032 1033 while (bytestoread != 0) { 1034 if ((n = s.read(header, bytesread, bytestoread)) < 0) { 1035 return null; 1036 } 1037 bytesread += n; 1038 bytestoread -= n; 1039 } 1040 if (header[36] != 0x61 || header[37] != 0x63 || 1041 header[38] != 0x73 || header[39] != 0x70) { 1042 return null; /* not a valid profile */ 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 1092 profileActivator = null; 1093 deferralInfo = null; 1094 InputStream is = getStandardProfileInputStream(fileName); 1095 if (is == null) { 1096 throw new ProfileDataException("Cannot open file " + fileName); 1097 } 1098 try { 1099 profileData = getProfileDataFromStream(is); 1100 is.close(); /* close the file */ 1101 } 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; 1174 1175 case icSigDisplayClass: 1176 theClass = CLASS_DISPLAY; 1177 break; 1178 1179 case icSigOutputClass: 1180 theClass = CLASS_OUTPUT; 1181 break; 1182 1183 case icSigLinkClass: 1184 theClass = CLASS_DEVICELINK; 1185 break; 1186 1187 case icSigColorSpaceClass: 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 1461 case icSigSpace2CLR: 1462 theNumComponents = 2; 1463 break; 1464 1465 case icSigXYZData: 1466 case icSigLabData: 1467 case icSigLuvData: 1468 case icSigYCbCrData: 1469 case icSigYxyData: 1470 case icSigRgbData: 1471 case icSigHsvData: 1472 case icSigHlsData: 1473 case icSigCmyData: 1474 case icSigSpace3CLR: 1475 theNumComponents = 3; 1476 break; 1477 1478 case icSigCmykData: 1479 case icSigSpace4CLR: 1480 theNumComponents = 4; 1481 break; 1482 1483 case icSigSpace5CLR: 1484 theNumComponents = 5; 1485 break; 1486 1487 case icSigSpace6CLR: 1488 theNumComponents = 6; 1489 break; 1490 1491 case icSigSpace7CLR: 1492 theNumComponents = 7; 1493 break; 1494 1495 case icSigSpace8CLR: 1496 theNumComponents = 8; 1497 break; 1498 1499 case icSigSpace9CLR: 1500 theNumComponents = 9; 1501 break; 1502 1503 case icSigSpaceACLR: 1504 theNumComponents = 10; 1505 break; 1506 1507 case icSigSpaceBCLR: 1508 theNumComponents = 11; 1509 break; 1510 1511 case icSigSpaceCCLR: 1512 theNumComponents = 12; 1513 break; 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 1667 case icSigYxyData: 1668 theColorSpace = ColorSpace.TYPE_Yxy; 1669 break; 1670 1671 case icSigRgbData: 1672 theColorSpace = ColorSpace.TYPE_RGB; 1673 break; 1674 1675 case icSigGrayData: 1676 theColorSpace = ColorSpace.TYPE_GRAY; 1677 break; 1678 1679 case icSigHsvData: 1680 theColorSpace = ColorSpace.TYPE_HSV; 1681 break; 1682 1683 case icSigHlsData: 1684 theColorSpace = ColorSpace.TYPE_HLS; 1685 break; 1686 1687 case icSigCmykData: 1688 theColorSpace = ColorSpace.TYPE_CMYK; 1689 break; 1690 1691 case icSigCmyData: 1692 theColorSpace = ColorSpace.TYPE_CMY; 1693 break; 1694 1695 case icSigSpace2CLR: 1696 theColorSpace = ColorSpace.TYPE_2CLR; 1697 break; 1698 1699 case icSigSpace3CLR: 1700 theColorSpace = ColorSpace.TYPE_3CLR; 1701 break; 1702 1703 case icSigSpace4CLR: 1704 theColorSpace = ColorSpace.TYPE_4CLR; 1705 break; 1706 1707 case icSigSpace5CLR: 1708 theColorSpace = ColorSpace.TYPE_5CLR; 1709 break; 1710 1711 case icSigSpace6CLR: 1712 theColorSpace = ColorSpace.TYPE_6CLR; 1713 break; 1714 1715 case icSigSpace7CLR: 1716 theColorSpace = ColorSpace.TYPE_7CLR; 1717 break; 1718 1719 case icSigSpace8CLR: 1720 theColorSpace = ColorSpace.TYPE_8CLR; 1721 break; 1722 1723 case icSigSpace9CLR: 1724 theColorSpace = ColorSpace.TYPE_9CLR; 1725 break; 1726 1727 case icSigSpaceACLR: 1728 theColorSpace = ColorSpace.TYPE_ACLR; 1729 break; 1730 1731 case icSigSpaceBCLR: 1732 theColorSpace = ColorSpace.TYPE_BCLR; 1733 break; 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)) { 1815 f = null; 1816 } 1817 } 1818 } 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)) { 1862 canonicalDirName += File.separator; 1863 } 1864 String canonicalFileName = f.getCanonicalPath(); 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 }