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