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