13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2017 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
54 //
55
56 #include "lcms2_internal.h"
57
58
59 // Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point
60 // compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS
61 // after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1)
62 cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
63 cmsUInt32Number nProfiles,
64 cmsUInt32Number Intents[],
65 cmsHPROFILE hProfiles[],
66 cmsBool BPC[],
67 cmsFloat64Number AdaptationStates[],
68 cmsUInt32Number dwFlags);
69
70 //---------------------------------------------------------------------------------
71
72 // This is the default routine for ICC-style intents. A user may decide to override it by using a plugin.
73 // Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric
74 static
75 cmsPipeline* DefaultICCintents(cmsContext ContextID,
76 cmsUInt32Number nProfiles,
77 cmsUInt32Number Intents[],
78 cmsHPROFILE hProfiles[],
79 cmsBool BPC[],
80 cmsFloat64Number AdaptationStates[],
81 cmsUInt32Number dwFlags);
82
83 //---------------------------------------------------------------------------------
84
85 // This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile
86 // to do the trick (no devicelinks allowed at that position)
87 static
88 cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
89 cmsUInt32Number nProfiles,
90 cmsUInt32Number Intents[],
91 cmsHPROFILE hProfiles[],
722
723 case INTENT_PRESERVE_K_ONLY_SATURATION:
724 case INTENT_PRESERVE_K_PLANE_SATURATION:
725 return INTENT_SATURATION;
726
727 default: return Intent;
728 }
729 }
730
731 // Sampler for Black-only preserving CMYK->CMYK transforms
732
733 typedef struct {
734 cmsPipeline* cmyk2cmyk; // The original transform
735 cmsToneCurve* KTone; // Black-to-black tone curve
736
737 } GrayOnlyParams;
738
739
740 // Preserve black only if that is the only ink used
741 static
742 int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
743 {
744 GrayOnlyParams* bp = (GrayOnlyParams*) Cargo;
745
746 // If going across black only, keep black only
747 if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
748
749 // TAC does not apply because it is black ink!
750 Out[0] = Out[1] = Out[2] = 0;
751 Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]);
752 return TRUE;
753 }
754
755 // Keep normal transform for other colors
756 bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data);
757 return TRUE;
758 }
759
760 // This is the entry for black-preserving K-only intents, which are non-ICC
761 static
762 cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
849 // K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------
850
851 typedef struct {
852
853 cmsPipeline* cmyk2cmyk; // The original transform
854 cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile)
855 cmsHTRANSFORM cmyk2Lab; // The input chain
856 cmsToneCurve* KTone; // Black-to-black tone curve
857 cmsPipeline* LabK2cmyk; // The output profile
858 cmsFloat64Number MaxError;
859
860 cmsHTRANSFORM hRoundTrip;
861 cmsFloat64Number MaxTAC;
862
863
864 } PreserveKPlaneParams;
865
866
867 // The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision
868 static
869 int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
870 {
871 int i;
872 cmsFloat32Number Inf[4], Outf[4];
873 cmsFloat32Number LabK[4];
874 cmsFloat64Number SumCMY, SumCMYK, Error, Ratio;
875 cmsCIELab ColorimetricLab, BlackPreservingLab;
876 PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo;
877
878 // Convert from 16 bits to floating point
879 for (i=0; i < 4; i++)
880 Inf[i] = (cmsFloat32Number) (In[i] / 65535.0);
881
882 // Get the K across Tone curve
883 LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]);
884
885 // If going across black only, keep black only
886 if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
887
888 Out[0] = Out[1] = Out[2] = 0;
889 Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0);
890 return TRUE;
891 }
892
893 // Try the original transform,
894 cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk);
895
896 // Store a copy of the floating point result into 16-bit
897 for (i=0; i < 4; i++)
898 Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0);
899
900 // Maybe K is already ok (mostly on K=0)
901 if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) {
902 return TRUE;
903 }
904
905 // K differ, mesure and keep Lab measurement for further usage
906 // this is done in relative colorimetric intent
907 cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1);
908
909 // Is not black only and the transform doesn't keep black.
910 // Obtain the Lab of output CMYK. After that we have Lab + K
911 cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1);
912
913 // Obtain the corresponding CMY using reverse interpolation
914 // (K is fixed in LabK[3])
915 if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) {
916
917 // Cannot find a suitable value, so use colorimetric xform
918 // which is already stored in Out[]
919 return TRUE;
920 }
921
922 // Make sure to pass through K (which now is fixed)
923 Outf[3] = LabK[3];
924
925 // Apply TAC if needed
926 SumCMY = Outf[0] + Outf[1] + Outf[2];
927 SumCMYK = SumCMY + Outf[3];
928
929 if (SumCMYK > bp ->MaxTAC) {
930
931 Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY);
932 if (Ratio < 0)
933 Ratio = 0;
934 }
935 else
936 Ratio = 1.0;
937
938 Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C
939 Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M
940 Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y
941 Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0);
942
943 // Estimate the error (this goes 16 bits to Lab DBL)
944 cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
945 Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
946 if (Error > bp -> MaxError)
|
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2020 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
54 //
55
56 #include "lcms2_internal.h"
57
58
59 // This is the default routine for ICC-style intents. A user may decide to override it by using a plugin.
60 // Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric
61 static
62 cmsPipeline* DefaultICCintents(cmsContext ContextID,
63 cmsUInt32Number nProfiles,
64 cmsUInt32Number Intents[],
65 cmsHPROFILE hProfiles[],
66 cmsBool BPC[],
67 cmsFloat64Number AdaptationStates[],
68 cmsUInt32Number dwFlags);
69
70 //---------------------------------------------------------------------------------
71
72 // This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile
73 // to do the trick (no devicelinks allowed at that position)
74 static
75 cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
76 cmsUInt32Number nProfiles,
77 cmsUInt32Number Intents[],
78 cmsHPROFILE hProfiles[],
709
710 case INTENT_PRESERVE_K_ONLY_SATURATION:
711 case INTENT_PRESERVE_K_PLANE_SATURATION:
712 return INTENT_SATURATION;
713
714 default: return Intent;
715 }
716 }
717
718 // Sampler for Black-only preserving CMYK->CMYK transforms
719
720 typedef struct {
721 cmsPipeline* cmyk2cmyk; // The original transform
722 cmsToneCurve* KTone; // Black-to-black tone curve
723
724 } GrayOnlyParams;
725
726
727 // Preserve black only if that is the only ink used
728 static
729 int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
730 {
731 GrayOnlyParams* bp = (GrayOnlyParams*) Cargo;
732
733 // If going across black only, keep black only
734 if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
735
736 // TAC does not apply because it is black ink!
737 Out[0] = Out[1] = Out[2] = 0;
738 Out[3] = cmsEvalToneCurve16(bp->KTone, In[3]);
739 return TRUE;
740 }
741
742 // Keep normal transform for other colors
743 bp ->cmyk2cmyk ->Eval16Fn(In, Out, bp ->cmyk2cmyk->Data);
744 return TRUE;
745 }
746
747 // This is the entry for black-preserving K-only intents, which are non-ICC
748 static
749 cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
836 // K Plane-preserving CMYK to CMYK ------------------------------------------------------------------------------------
837
838 typedef struct {
839
840 cmsPipeline* cmyk2cmyk; // The original transform
841 cmsHTRANSFORM hProofOutput; // Output CMYK to Lab (last profile)
842 cmsHTRANSFORM cmyk2Lab; // The input chain
843 cmsToneCurve* KTone; // Black-to-black tone curve
844 cmsPipeline* LabK2cmyk; // The output profile
845 cmsFloat64Number MaxError;
846
847 cmsHTRANSFORM hRoundTrip;
848 cmsFloat64Number MaxTAC;
849
850
851 } PreserveKPlaneParams;
852
853
854 // The CLUT will be stored at 16 bits, but calculations are performed at cmsFloat32Number precision
855 static
856 int BlackPreservingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
857 {
858 int i;
859 cmsFloat32Number Inf[4], Outf[4];
860 cmsFloat32Number LabK[4];
861 cmsFloat64Number SumCMY, SumCMYK, Error, Ratio;
862 cmsCIELab ColorimetricLab, BlackPreservingLab;
863 PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo;
864
865 // Convert from 16 bits to floating point
866 for (i=0; i < 4; i++)
867 Inf[i] = (cmsFloat32Number) (In[i] / 65535.0);
868
869 // Get the K across Tone curve
870 LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]);
871
872 // If going across black only, keep black only
873 if (In[0] == 0 && In[1] == 0 && In[2] == 0) {
874
875 Out[0] = Out[1] = Out[2] = 0;
876 Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0);
877 return TRUE;
878 }
879
880 // Try the original transform,
881 cmsPipelineEvalFloat(Inf, Outf, bp ->cmyk2cmyk);
882
883 // Store a copy of the floating point result into 16-bit
884 for (i=0; i < 4; i++)
885 Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0);
886
887 // Maybe K is already ok (mostly on K=0)
888 if (fabsf(Outf[3] - LabK[3]) < (3.0 / 65535.0)) {
889 return TRUE;
890 }
891
892 // K differ, measure and keep Lab measurement for further usage
893 // this is done in relative colorimetric intent
894 cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1);
895
896 // Is not black only and the transform doesn't keep black.
897 // Obtain the Lab of output CMYK. After that we have Lab + K
898 cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1);
899
900 // Obtain the corresponding CMY using reverse interpolation
901 // (K is fixed in LabK[3])
902 if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) {
903
904 // Cannot find a suitable value, so use colorimetric xform
905 // which is already stored in Out[]
906 return TRUE;
907 }
908
909 // Make sure to pass through K (which now is fixed)
910 Outf[3] = LabK[3];
911
912 // Apply TAC if needed
913 SumCMY = (cmsFloat64Number) Outf[0] + Outf[1] + Outf[2];
914 SumCMYK = SumCMY + Outf[3];
915
916 if (SumCMYK > bp ->MaxTAC) {
917
918 Ratio = 1 - ((SumCMYK - bp->MaxTAC) / SumCMY);
919 if (Ratio < 0)
920 Ratio = 0;
921 }
922 else
923 Ratio = 1.0;
924
925 Out[0] = _cmsQuickSaturateWord(Outf[0] * Ratio * 65535.0); // C
926 Out[1] = _cmsQuickSaturateWord(Outf[1] * Ratio * 65535.0); // M
927 Out[2] = _cmsQuickSaturateWord(Outf[2] * Ratio * 65535.0); // Y
928 Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0);
929
930 // Estimate the error (this goes 16 bits to Lab DBL)
931 cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1);
932 Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab);
933 if (Error > bp -> MaxError)
|