@@ -759,6 +759,9 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
759759 cmsUInt32Number ICCIntents [256 ];
760760 cmsStage * CLUT ;
761761 cmsUInt32Number i , nGridPoints ;
762+ cmsUInt32Number lastProfilePos ;
763+ cmsUInt32Number preservationProfilesCount ;
764+ cmsHPROFILE hLastProfile ;
762765
763766
764767 // Sanity check
@@ -768,20 +771,36 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
768771 for (i = 0 ; i < nProfiles ; i ++ )
769772 ICCIntents [i ] = TranslateNonICCIntents (TheIntents [i ]);
770773
774+
775+ // Trim all CMYK devicelinks at the end
776+ lastProfilePos = nProfiles - 1 ;
777+ hLastProfile = hProfiles [lastProfilePos ];
778+
779+ while (lastProfilePos > 1 )
780+ {
781+ hLastProfile = hProfiles [-- lastProfilePos ];
782+ if (cmsGetColorSpace (hLastProfile ) != cmsSigCmykData ||
783+ cmsGetDeviceClass (hLastProfile ) != cmsSigLinkClass )
784+ break ;
785+ }
786+
787+ preservationProfilesCount = lastProfilePos + 1 ;
788+
771789 // Check for non-cmyk profiles
772790 if (cmsGetColorSpace (hProfiles [0 ]) != cmsSigCmykData ||
773- cmsGetColorSpace (hProfiles [nProfiles - 1 ]) != cmsSigCmykData )
791+ !(cmsGetColorSpace (hLastProfile ) == cmsSigCmykData ||
792+ cmsGetDeviceClass (hLastProfile ) == cmsSigOutputClass ))
774793 return DefaultICCintents (ContextID , nProfiles , ICCIntents , hProfiles , BPC , AdaptationStates , dwFlags );
775794
776- memset (& bp , 0 , sizeof (bp ));
777-
778795 // Allocate an empty LUT for holding the result
779796 Result = cmsPipelineAlloc (ContextID , 4 , 4 );
780797 if (Result == NULL ) return NULL ;
781798
799+ memset (& bp , 0 , sizeof (bp ));
800+
782801 // Create a LUT holding normal ICC transform
783802 bp .cmyk2cmyk = DefaultICCintents (ContextID ,
784- nProfiles ,
803+ preservationProfilesCount ,
785804 ICCIntents ,
786805 hProfiles ,
787806 BPC ,
@@ -793,7 +812,7 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
793812 // Now, compute the tone curve
794813 bp .KTone = _cmsBuildKToneCurve (ContextID ,
795814 4096 ,
796- nProfiles ,
815+ preservationProfilesCount ,
797816 ICCIntents ,
798817 hProfiles ,
799818 BPC ,
@@ -818,6 +837,19 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
818837 if (!cmsStageSampleCLut16bit (CLUT , BlackPreservingGrayOnlySampler , (void * ) & bp , 0 ))
819838 goto Error ;
820839
840+
841+ // Insert possible devicelinks at the end
842+ for (i = lastProfilePos + 1 ; i < nProfiles ; i ++ )
843+ {
844+ cmsPipeline * devlink = _cmsReadDevicelinkLUT (hProfiles [i ], ICCIntents [i ]);
845+ if (devlink == NULL )
846+ goto Error ;
847+
848+ if (!cmsPipelineCat (Result , devlink ))
849+ goto Error ;
850+ }
851+
852+
821853 // Get rid of xform and tone curve
822854 cmsPipelineFree (bp .cmyk2cmyk );
823855 cmsFreeToneCurve (bp .KTone );
@@ -936,6 +968,8 @@ int BlackPreservingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER c
936968 return TRUE;
937969}
938970
971+
972+
939973// This is the entry for black-plane preserving, which are non-ICC
940974static
941975cmsPipeline * BlackPreservingKPlaneIntents (cmsContext ContextID ,
@@ -947,10 +981,14 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
947981 cmsUInt32Number dwFlags )
948982{
949983 PreserveKPlaneParams bp ;
984+
950985 cmsPipeline * Result = NULL ;
951986 cmsUInt32Number ICCIntents [256 ];
952987 cmsStage * CLUT ;
953988 cmsUInt32Number i , nGridPoints ;
989+ cmsUInt32Number lastProfilePos ;
990+ cmsUInt32Number preservationProfilesCount ;
991+ cmsHPROFILE hLastProfile ;
954992 cmsHPROFILE hLab ;
955993
956994 // Sanity check
@@ -960,32 +998,45 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
960998 for (i = 0 ; i < nProfiles ; i ++ )
961999 ICCIntents [i ] = TranslateNonICCIntents (TheIntents [i ]);
9621000
1001+ // Trim all CMYK devicelinks at the end
1002+ lastProfilePos = nProfiles - 1 ;
1003+ hLastProfile = hProfiles [lastProfilePos ];
1004+
1005+ while (lastProfilePos > 1 )
1006+ {
1007+ hLastProfile = hProfiles [-- lastProfilePos ];
1008+ if (cmsGetColorSpace (hLastProfile ) != cmsSigCmykData ||
1009+ cmsGetDeviceClass (hLastProfile ) != cmsSigLinkClass )
1010+ break ;
1011+ }
1012+
1013+ preservationProfilesCount = lastProfilePos + 1 ;
1014+
9631015 // Check for non-cmyk profiles
9641016 if (cmsGetColorSpace (hProfiles [0 ]) != cmsSigCmykData ||
965- !(cmsGetColorSpace (hProfiles [ nProfiles - 1 ] ) == cmsSigCmykData ||
966- cmsGetDeviceClass (hProfiles [ nProfiles - 1 ] ) == cmsSigOutputClass ))
1017+ !(cmsGetColorSpace (hLastProfile ) == cmsSigCmykData ||
1018+ cmsGetDeviceClass (hLastProfile ) == cmsSigOutputClass ))
9671019 return DefaultICCintents (ContextID , nProfiles , ICCIntents , hProfiles , BPC , AdaptationStates , dwFlags );
9681020
9691021 // Allocate an empty LUT for holding the result
9701022 Result = cmsPipelineAlloc (ContextID , 4 , 4 );
9711023 if (Result == NULL ) return NULL ;
9721024
973-
9741025 memset (& bp , 0 , sizeof (bp ));
9751026
9761027 // We need the input LUT of the last profile, assuming this one is responsible of
9771028 // black generation. This LUT will be searched in inverse order.
978- bp .LabK2cmyk = _cmsReadInputLUT (hProfiles [ nProfiles - 1 ] , INTENT_RELATIVE_COLORIMETRIC );
1029+ bp .LabK2cmyk = _cmsReadInputLUT (hLastProfile , INTENT_RELATIVE_COLORIMETRIC );
9791030 if (bp .LabK2cmyk == NULL ) goto Cleanup ;
9801031
9811032 // Get total area coverage (in 0..1 domain)
982- bp .MaxTAC = cmsDetectTAC (hProfiles [ nProfiles - 1 ] ) / 100.0 ;
1033+ bp .MaxTAC = cmsDetectTAC (hLastProfile ) / 100.0 ;
9831034 if (bp .MaxTAC <= 0 ) goto Cleanup ;
9841035
9851036
9861037 // Create a LUT holding normal ICC transform
9871038 bp .cmyk2cmyk = DefaultICCintents (ContextID ,
988- nProfiles ,
1039+ preservationProfilesCount ,
9891040 ICCIntents ,
9901041 hProfiles ,
9911042 BPC ,
@@ -994,7 +1045,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
9941045 if (bp .cmyk2cmyk == NULL ) goto Cleanup ;
9951046
9961047 // Now the tone curve
997- bp .KTone = _cmsBuildKToneCurve (ContextID , 4096 , nProfiles ,
1048+ bp .KTone = _cmsBuildKToneCurve (ContextID , 4096 , preservationProfilesCount ,
9981049 ICCIntents ,
9991050 hProfiles ,
10001051 BPC ,
@@ -1004,14 +1055,14 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
10041055
10051056 // To measure the output, Last profile to Lab
10061057 hLab = cmsCreateLab4ProfileTHR (ContextID , NULL );
1007- bp .hProofOutput = cmsCreateTransformTHR (ContextID , hProfiles [ nProfiles - 1 ] ,
1058+ bp .hProofOutput = cmsCreateTransformTHR (ContextID , hLastProfile ,
10081059 CHANNELS_SH (4 )|BYTES_SH (2 ), hLab , TYPE_Lab_DBL ,
10091060 INTENT_RELATIVE_COLORIMETRIC ,
10101061 cmsFLAGS_NOCACHE |cmsFLAGS_NOOPTIMIZE );
10111062 if ( bp .hProofOutput == NULL ) goto Cleanup ;
10121063
10131064 // Same as anterior, but lab in the 0..1 range
1014- bp .cmyk2Lab = cmsCreateTransformTHR (ContextID , hProfiles [ nProfiles - 1 ] ,
1065+ bp .cmyk2Lab = cmsCreateTransformTHR (ContextID , hLastProfile ,
10151066 FLOAT_SH (1 )|CHANNELS_SH (4 )|BYTES_SH (4 ), hLab ,
10161067 FLOAT_SH (1 )|CHANNELS_SH (3 )|BYTES_SH (4 ),
10171068 INTENT_RELATIVE_COLORIMETRIC ,
@@ -1034,6 +1085,18 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
10341085
10351086 cmsStageSampleCLut16bit (CLUT , BlackPreservingSampler , (void * ) & bp , 0 );
10361087
1088+ // Insert possible devicelinks at the end
1089+ for (i = lastProfilePos + 1 ; i < nProfiles ; i ++ )
1090+ {
1091+ cmsPipeline * devlink = _cmsReadDevicelinkLUT (hProfiles [i ], ICCIntents [i ]);
1092+ if (devlink == NULL )
1093+ goto Cleanup ;
1094+
1095+ if (!cmsPipelineCat (Result , devlink ))
1096+ goto Cleanup ;
1097+ }
1098+
1099+
10371100Cleanup :
10381101
10391102 if (bp .cmyk2cmyk ) cmsPipelineFree (bp .cmyk2cmyk );
@@ -1046,6 +1109,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
10461109 return Result ;
10471110}
10481111
1112+
1113+
10491114// Link routines ------------------------------------------------------------------------------------------------------
10501115
10511116// Chain several profiles into a single LUT. It just checks the parameters and then calls the handler
0 commit comments