654 // G = ((G’sRGB + 0.055) / 1.055)^2.4 655 // B = ((B’sRGB + 0.055) / 1.055)^2.4 656 657 static 658 cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) 659 { 660 cmsFloat64Number Parameters[5]; 661 662 Parameters[0] = 2.4; 663 Parameters[1] = 1. / 1.055; 664 Parameters[2] = 0.055 / 1.055; 665 Parameters[3] = 1. / 12.92; 666 Parameters[4] = 0.04045; 667 668 return cmsBuildParametricToneCurve(ContextID, 4, Parameters); 669 } 670 671 // Create the ICC virtual profile for sRGB space 672 cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) 673 { 674 cmsCIExyY D65; 675 cmsCIExyYTRIPLE Rec709Primaries = { 676 {0.6400, 0.3300, 1.0}, 677 {0.3000, 0.6000, 1.0}, 678 {0.1500, 0.0600, 1.0} 679 }; 680 cmsToneCurve* Gamma22[3]; 681 cmsHPROFILE hsRGB; 682 683 cmsWhitePointFromTemp(&D65, 6504); 684 Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); 685 if (Gamma22[0] == NULL) return NULL; 686 687 hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); 688 cmsFreeToneCurve(Gamma22[0]); 689 if (hsRGB == NULL) return NULL; 690 691 if (!SetTextTags(hsRGB, L"sRGB built-in")) { 692 cmsCloseProfile(hsRGB); 693 return NULL; 694 } 695 696 return hsRGB; 697 } 698 699 cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) 700 { 701 return cmsCreate_sRGBProfileTHR(NULL); 702 } 703 704 705 706 typedef struct { 707 cmsFloat64Number Brightness; 708 cmsFloat64Number Contrast; 709 cmsFloat64Number Hue; 710 cmsFloat64Number Saturation; 711 cmsCIEXYZ WPsrc, WPdest; 712 713 } BCHSWADJUSTS, *LPBCHSWADJUSTS; 714 715 716 static 717 int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) 718 { 719 cmsCIELab LabIn, LabOut; 720 cmsCIELCh LChIn, LChOut; 721 cmsCIEXYZ XYZ; 722 LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; 723 724 725 cmsLabEncoded2Float(&LabIn, In); 726 727 728 cmsLab2LCh(&LChIn, &LabIn); 729 730 // Do some adjusts on LCh 731 732 LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; 733 LChOut.C = LChIn.C + bchsw -> Saturation; 734 LChOut.h = LChIn.h + bchsw -> Hue; 735 736 737 cmsLCh2Lab(&LabOut, &LChOut); 738 739 // Move white point in Lab 740 741 cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); 742 cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); 743 744 // Back to encoded 745 746 cmsFloat2LabEncoded(Out, &LabOut); 747 748 return TRUE; 749 } 750 751 752 // Creates an abstract profile operating in Lab space for Brightness, 753 // contrast, Saturation and white point displacement 754 755 cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, 756 int nLUTPoints, 757 cmsFloat64Number Bright, 758 cmsFloat64Number Contrast, 759 cmsFloat64Number Hue, 760 cmsFloat64Number Saturation, 761 int TempSrc, 762 int TempDest) 763 { 764 cmsHPROFILE hICC; 765 cmsPipeline* Pipeline; 766 BCHSWADJUSTS bchsw; 767 cmsCIExyY WhitePnt; 768 cmsStage* CLUT; 769 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 770 int i; 771 772 bchsw.Brightness = Bright; 773 bchsw.Contrast = Contrast; 774 bchsw.Hue = Hue; 775 bchsw.Saturation = Saturation; 776 777 cmsWhitePointFromTemp(&WhitePnt, TempSrc ); 778 cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); 779 780 cmsWhitePointFromTemp(&WhitePnt, TempDest); 781 cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); 782 783 hICC = cmsCreateProfilePlaceholder(ContextID); 784 if (!hICC) // can't allocate 785 return NULL; 786 787 788 cmsSetDeviceClass(hICC, cmsSigAbstractClass); 789 cmsSetColorSpace(hICC, cmsSigLabData); 790 cmsSetPCS(hICC, cmsSigLabData); 791 792 cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 793 794 // Creates a Pipeline with 3D grid only 795 Pipeline = cmsPipelineAlloc(ContextID, 3, 3); 796 if (Pipeline == NULL) { 797 cmsCloseProfile(hICC); 798 return NULL; 799 } 800 801 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; 802 CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); 803 if (CLUT == NULL) return NULL; 804 805 806 if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { 807 1000 1001 return hICC; 1002 1003 Error: 1004 if (hICC != NULL) cmsCloseProfile(hICC); 1005 return NULL; 1006 } 1007 1008 1009 // This structure holds information about which MPU can be stored on a profile based on the version 1010 1011 typedef struct { 1012 cmsBool IsV4; // Is a V4 tag? 1013 cmsTagSignature RequiredTag; // Set to 0 for both types 1014 cmsTagTypeSignature LutType; // The LUT type 1015 int nTypes; // Number of types (up to 5) 1016 cmsStageSignature MpeTypes[5]; // 5 is the maximum number 1017 1018 } cmsAllowedLUT; 1019 1020 static const cmsAllowedLUT AllowedLUTTypes[] = { 1021 1022 { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, 1023 { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, 1024 { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, 1025 { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, 1026 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, 1027 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, 1028 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1029 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, 1030 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1031 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, 1032 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} 1033 }; 1034 1035 #define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) 1036 1037 // Check a single entry 1038 static 1039 cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) 1040 { 1041 cmsStage* mpe; 1042 int n; 1043 1044 for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { 1045 | 654 // G = ((G’sRGB + 0.055) / 1.055)^2.4 655 // B = ((B’sRGB + 0.055) / 1.055)^2.4 656 657 static 658 cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) 659 { 660 cmsFloat64Number Parameters[5]; 661 662 Parameters[0] = 2.4; 663 Parameters[1] = 1. / 1.055; 664 Parameters[2] = 0.055 / 1.055; 665 Parameters[3] = 1. / 12.92; 666 Parameters[4] = 0.04045; 667 668 return cmsBuildParametricToneCurve(ContextID, 4, Parameters); 669 } 670 671 // Create the ICC virtual profile for sRGB space 672 cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) 673 { 674 cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; 675 cmsCIExyYTRIPLE Rec709Primaries = { 676 {0.6400, 0.3300, 1.0}, 677 {0.3000, 0.6000, 1.0}, 678 {0.1500, 0.0600, 1.0} 679 }; 680 cmsToneCurve* Gamma22[3]; 681 cmsHPROFILE hsRGB; 682 683 // cmsWhitePointFromTemp(&D65, 6504); 684 Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); 685 if (Gamma22[0] == NULL) return NULL; 686 687 hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22); 688 cmsFreeToneCurve(Gamma22[0]); 689 if (hsRGB == NULL) return NULL; 690 691 if (!SetTextTags(hsRGB, L"sRGB built-in")) { 692 cmsCloseProfile(hsRGB); 693 return NULL; 694 } 695 696 return hsRGB; 697 } 698 699 cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) 700 { 701 return cmsCreate_sRGBProfileTHR(NULL); 702 } 703 704 705 706 typedef struct { 707 cmsFloat64Number Brightness; 708 cmsFloat64Number Contrast; 709 cmsFloat64Number Hue; 710 cmsFloat64Number Saturation; 711 cmsBool lAdjustWP; 712 cmsCIEXYZ WPsrc, WPdest; 713 714 } BCHSWADJUSTS, *LPBCHSWADJUSTS; 715 716 717 static 718 int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) 719 { 720 cmsCIELab LabIn, LabOut; 721 cmsCIELCh LChIn, LChOut; 722 cmsCIEXYZ XYZ; 723 LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; 724 725 726 cmsLabEncoded2Float(&LabIn, In); 727 728 729 cmsLab2LCh(&LChIn, &LabIn); 730 731 // Do some adjusts on LCh 732 733 LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness; 734 LChOut.C = LChIn.C + bchsw -> Saturation; 735 LChOut.h = LChIn.h + bchsw -> Hue; 736 737 738 cmsLCh2Lab(&LabOut, &LChOut); 739 740 // Move white point in Lab 741 if (bchsw->lAdjustWP) { 742 cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut); 743 cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ); 744 } 745 746 // Back to encoded 747 748 cmsFloat2LabEncoded(Out, &LabOut); 749 750 return TRUE; 751 } 752 753 754 // Creates an abstract profile operating in Lab space for Brightness, 755 // contrast, Saturation and white point displacement 756 757 cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, 758 int nLUTPoints, 759 cmsFloat64Number Bright, 760 cmsFloat64Number Contrast, 761 cmsFloat64Number Hue, 762 cmsFloat64Number Saturation, 763 int TempSrc, 764 int TempDest) 765 { 766 cmsHPROFILE hICC; 767 cmsPipeline* Pipeline; 768 BCHSWADJUSTS bchsw; 769 cmsCIExyY WhitePnt; 770 cmsStage* CLUT; 771 cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 772 int i; 773 774 bchsw.Brightness = Bright; 775 bchsw.Contrast = Contrast; 776 bchsw.Hue = Hue; 777 bchsw.Saturation = Saturation; 778 if (TempSrc == TempDest) { 779 780 bchsw.lAdjustWP = FALSE; 781 } 782 else { 783 bchsw.lAdjustWP = TRUE; 784 cmsWhitePointFromTemp(&WhitePnt, TempSrc); 785 cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); 786 cmsWhitePointFromTemp(&WhitePnt, TempDest); 787 cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); 788 789 } 790 791 hICC = cmsCreateProfilePlaceholder(ContextID); 792 if (!hICC) // can't allocate 793 return NULL; 794 795 cmsSetDeviceClass(hICC, cmsSigAbstractClass); 796 cmsSetColorSpace(hICC, cmsSigLabData); 797 cmsSetPCS(hICC, cmsSigLabData); 798 799 cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); 800 801 // Creates a Pipeline with 3D grid only 802 Pipeline = cmsPipelineAlloc(ContextID, 3, 3); 803 if (Pipeline == NULL) { 804 cmsCloseProfile(hICC); 805 return NULL; 806 } 807 808 for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; 809 CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); 810 if (CLUT == NULL) return NULL; 811 812 813 if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { 814 1007 1008 return hICC; 1009 1010 Error: 1011 if (hICC != NULL) cmsCloseProfile(hICC); 1012 return NULL; 1013 } 1014 1015 1016 // This structure holds information about which MPU can be stored on a profile based on the version 1017 1018 typedef struct { 1019 cmsBool IsV4; // Is a V4 tag? 1020 cmsTagSignature RequiredTag; // Set to 0 for both types 1021 cmsTagTypeSignature LutType; // The LUT type 1022 int nTypes; // Number of types (up to 5) 1023 cmsStageSignature MpeTypes[5]; // 5 is the maximum number 1024 1025 } cmsAllowedLUT; 1026 1027 #define cmsSig0 ((cmsTagSignature) 0) 1028 1029 static const cmsAllowedLUT AllowedLUTTypes[] = { 1030 1031 { FALSE, cmsSig0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, 1032 { FALSE, cmsSig0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, 1033 { FALSE, cmsSig0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } }, 1034 { TRUE, cmsSig0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } }, 1035 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, 1036 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, 1037 { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1038 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, 1039 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, 1040 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, 1041 { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} 1042 }; 1043 1044 #define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT)) 1045 1046 // Check a single entry 1047 static 1048 cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) 1049 { 1050 cmsStage* mpe; 1051 int n; 1052 1053 for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { 1054 |