LCMSBOOL LCMSEXPORT cmsNamedColorInfo(cmsHTRANSFORM xform, int nColor, char* Name, char* Prefix, char* Suffix) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; if (v ->NamedColorList == NULL) return FALSE; if (nColor < 0 || nColor >= cmsNamedColorCount(xform)) return FALSE; if (Name) { strncpy(Name, v ->NamedColorList->List[nColor].Name, 31); Name[31] = 0; } if (Prefix) { strncpy(Prefix, v ->NamedColorList->Prefix, 31); Prefix[31] = 0; } if (Suffix) { strncpy(Suffix, v ->NamedColorList->Suffix, 31); Suffix[31] = 0; } return TRUE; }
// This function creates a named color profile dumping all the contents of transform to a single profile // In this way, LittleCMS may be used to "group" several named color databases into a single profile. // It has, however, several minor limitations. PCS is always Lab, which is not very critic since this // is the normal PCS for named color profiles. static cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) { _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; cmsHPROFILE hICC = NULL; int i, nColors; cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL; // Create an empty placeholder hICC = cmsCreateProfilePlaceholder(v->ContextID); if (hICC == NULL) return NULL; // Critical information cmsSetDeviceClass(hICC, cmsSigNamedColorClass); cmsSetColorSpace(hICC, v ->ExitColorSpace); cmsSetPCS(hICC, cmsSigLabData); // Tag profile with information if (!SetTextTags(hICC, L"Named color devicelink")) goto Error; Original = cmsGetNamedColorList(xform); if (Original == NULL) goto Error; nColors = cmsNamedColorCount(Original); nc2 = cmsDupNamedColorList(Original); if (nc2 == NULL) goto Error; // Colorant count now depends on the output space nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut); // Make sure we have proper formatters cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX, FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace)) | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace))); // Apply the transfor to colorants. for (i=0; i < nColors; i++) { cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); } if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error; cmsFreeNamedColorList(nc2); return hICC; Error: if (hICC != NULL) cmsCloseProfile(hICC); return NULL; }
int LCMSEXPORT cmsNamedColorIndex(cmsHTRANSFORM xform, const char* Name) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; int i, n; if (v ->NamedColorList == NULL) return -1; n = cmsNamedColorCount(xform); for (i=0; i < n; i++) { if (stricmp(Name, v ->NamedColorList->List[i].Name) == 0) return i; } return -1; }
static int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) { cmsHTRANSFORM xform; cmsHPROFILE hLab; int i, nColors; char ColorName[32]; cmsNAMEDCOLORLIST* NamedColorList; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); nColors = cmsNamedColorCount(NamedColorList); for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; cmsCIELab Lab; In[0] = (cmsUInt16Number) i; if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; cmsDoTransform(xform, In, &Lab, 1); _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); } _cmsIOPrintf(m, ">>\n"); cmsDeleteTransform(xform); cmsCloseProfile(hLab); return 1; }
static cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) { _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) xform; cmsHPROFILE hICC; cmsCIEXYZ WhitePoint; int i, nColors; size_t Size; LPcmsNAMEDCOLORLIST nc2; hICC = _cmsCreateProfilePlaceholder(); if (hICC == NULL) return NULL; cmsSetRenderingIntent(hICC, v -> Intent); cmsSetDeviceClass(hICC, icSigNamedColorClass); cmsSetColorSpace(hICC, v ->ExitColorSpace); cmsSetPCS(hICC, cmsGetPCS(v ->InputProfile)); cmsTakeMediaWhitePoint(&WhitePoint, v ->InputProfile); cmsAddTag(hICC, icSigMediaWhitePointTag, &WhitePoint); cmsAddTag(hICC, icSigDeviceMfgDescTag, (LPVOID) "LittleCMS"); cmsAddTag(hICC, icSigProfileDescriptionTag, (LPVOID) "Named color Device link"); cmsAddTag(hICC, icSigDeviceModelDescTag, (LPVOID) "Named color Device link"); nColors = cmsNamedColorCount(xform); nc2 = cmsAllocNamedColorList(nColors); Size = sizeof(cmsNAMEDCOLORLIST) + (sizeof(cmsNAMEDCOLOR) * (nColors-1)); CopyMemory(nc2, v->NamedColorList, Size); nc2 ->ColorantCount = _cmsChannelsOf(v ->ExitColorSpace); for (i=0; i < nColors; i++) { cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1); } cmsAddTag(hICC, icSigNamedColor2Tag, (void*) nc2); cmsFreeNamedColorList(nc2); return hICC; }
/* Create a link to return device values inside the named color profile or link it with a destination profile and potentially a proofing profile. If the output_colorspace and the proof_color space are NULL, then we will be returning the device values that are contained in the named color profile. i.e. in namedcolor_information. Note that an ICC named color profile need NOT contain the device values but must contain the CIELAB values. */ void gscms_get_name2device_link(gsicc_link_t *icclink, gcmmhprofile_t lcms_srchandle, gcmmhprofile_t lcms_deshandle, gcmmhprofile_t lcms_proofhandle, gsicc_rendering_param_t *rendering_params, gs_memory_t *memory) { cmsHTRANSFORM hTransform; cmsUInt32Number dwOutputFormat; cmsUInt32Number lcms_proof_flag; int number_colors; /* NOTE: We need to add a test here to check that we even HAVE device values in here and NOT just CIELAB values */ if ( lcms_proofhandle != NULL ) { lcms_proof_flag = cmsFLAGS_GAMUTCHECK | cmsFLAGS_SOFTPROOFING; } else { lcms_proof_flag = 0; } /* Create the transform */ /* ToDo: Adjust rendering intent */ hTransform = cmsCreateProofingTransformTHR(memory, lcms_srchandle, TYPE_NAMED_COLOR_INDEX, lcms_deshandle, TYPE_CMYK_8, lcms_proofhandle,INTENT_PERCEPTUAL, INTENT_ABSOLUTE_COLORIMETRIC, lcms_proof_flag); /* In littleCMS there is no easy way to find out the size of the device space returned by the named color profile until after the transform is made. Hence we adjust our output format after creating the transform. It is set to CMYK8 initially. */ number_colors = cmsNamedColorCount(cmsGetNamedColorList(hTransform)); /* NOTE: Output size of gx_color_value with no color space type check */ dwOutputFormat = (CHANNELS_SH(number_colors)|BYTES_SH(sizeof(gx_color_value))); /* Change the formatters */ cmsChangeBuffersFormat(hTransform,TYPE_NAMED_COLOR_INDEX,dwOutputFormat); icclink->link_handle = hTransform; cmsCloseProfile(lcms_srchandle); if(lcms_deshandle) cmsCloseProfile(lcms_deshandle); if(lcms_proofhandle) cmsCloseProfile(lcms_proofhandle); return; }
static WORD GetIndex(void) { char Buffer[4096], Name[40], Prefix[40], Suffix[40]; int index, max; max = cmsNamedColorCount(hTrans)-1; if (xisatty(stdin)) printf("Color index (0..%d)? ", max); GetLine(Buffer); index = atoi(Buffer); if (index > max) FatalError("Named color %d out of range!", index); cmsNamedColorInfo(hTrans, index, Name, Prefix, Suffix); printf("\n%s %s %s: ", Prefix, Name, Suffix); return index; }
// Get a named-color index static cmsUInt16Number GetIndex(void) { char Buffer[4096], Name[40], Prefix[40], Suffix[40]; int index, max; const cmsNAMEDCOLORLIST* NamedColorList; NamedColorList = cmsGetNamedColorList(hTrans); if (NamedColorList == NULL) return 0; max = cmsNamedColorCount(NamedColorList)-1; GetLine(Buffer, "Color index (0..%d)? ", max); index = atoi(Buffer); if (index > max) FatalError("Named color %d out of range!", index); cmsNamedColorInfo(NamedColorList, index, Name, Prefix, Suffix, NULL, NULL); printf("\n%s %s %s\n", Prefix, Name, Suffix); return (cmsUInt16Number) index; }
// Info aboout a given color cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, char* Name, char* Prefix, char* Suffix, cmsUInt16Number* PCS, cmsUInt16Number* Colorant) { if (NamedColorList == NULL) return FALSE; if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; if (Name) strcpy(Name, NamedColorList->List[nColor].Name); if (Prefix) strcpy(Prefix, NamedColorList->Prefix); if (Suffix) strcpy(Suffix, NamedColorList->Suffix); if (PCS) memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); if (Colorant) memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); return TRUE; }
// Creates all needed color transforms static cmsBool OpenTransforms(void) { cmsHPROFILE hInput, hOutput, hProof; cmsUInt32Number dwIn, dwOut, dwFlags; cmsNAMEDCOLORLIST* List; int i; // We don't need cache dwFlags = cmsFLAGS_NOCACHE; if (lIsDeviceLink) { hInput = OpenStockProfile(0, cInProf); if (hInput == NULL) return FALSE; hOutput = NULL; hProof = NULL; if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) { OutputColorSpace = cmsGetColorSpace(hInput); InputColorSpace = cmsGetPCS(hInput); } else { InputColorSpace = cmsGetColorSpace(hInput); OutputColorSpace = cmsGetPCS(hInput); } // Read colorant tables if present if (cmsIsTag(hInput, cmsSigColorantTableTag)) { List = cmsReadTag(hInput, cmsSigColorantTableTag); InputColorant = cmsDupNamedColorList(List); InputRange = 1; } else InputColorant = ComponentNames(InputColorSpace, TRUE); if (cmsIsTag(hInput, cmsSigColorantTableOutTag)){ List = cmsReadTag(hInput, cmsSigColorantTableOutTag); OutputColorant = cmsDupNamedColorList(List); OutputRange = 1; } else OutputColorant = ComponentNames(OutputColorSpace, FALSE); } else { hInput = OpenStockProfile(0, cInProf); if (hInput == NULL) return FALSE; hOutput = OpenStockProfile(0, cOutProf); if (hOutput == NULL) return FALSE; hProof = NULL; if (cmsGetDeviceClass(hInput) == cmsSigLinkClass || cmsGetDeviceClass(hOutput) == cmsSigLinkClass) FatalError("Use %cl flag for devicelink profiles!\n", SW); InputColorSpace = cmsGetColorSpace(hInput); OutputColorSpace = cmsGetColorSpace(hOutput); // Read colorant tables if present if (cmsIsTag(hInput, cmsSigColorantTableTag)) { List = cmsReadTag(hInput, cmsSigColorantTableTag); InputColorant = cmsDupNamedColorList(List); if (cmsNamedColorCount(InputColorant) <= 3) SetRange(255, TRUE); else SetRange(1, TRUE); // Inks are already divided by 100 in the formatter } else InputColorant = ComponentNames(InputColorSpace, TRUE); if (cmsIsTag(hOutput, cmsSigColorantTableTag)){ List = cmsReadTag(hOutput, cmsSigColorantTableTag); OutputColorant = cmsDupNamedColorList(List); if (cmsNamedColorCount(OutputColorant) <= 3) SetRange(255, FALSE); else SetRange(1, FALSE); // Inks are already divided by 100 in the formatter } else OutputColorant = ComponentNames(OutputColorSpace, FALSE); if (cProofing != NULL) { hProof = OpenStockProfile(0, cProofing); if (hProof == NULL) return FALSE; dwFlags |= cmsFLAGS_SOFTPROOFING; } } // Print information on profiles if (Verbose > 2) { printf("Profile:\n"); PrintProfileInformation(hInput); if (hOutput) { printf("Output profile:\n"); PrintProfileInformation(hOutput); } if (hProof != NULL) { printf("Proofing profile:\n"); PrintProfileInformation(hProof); } } // Input is always in floating point dwIn = cmsFormatterForColorspaceOfProfile(hInput, 0, TRUE); if (lIsDeviceLink) { dwOut = cmsFormatterForPCSOfProfile(hInput, lIsFloat ? 0 : 2, lIsFloat); } else { // 16 bits or floating point (only on output) dwOut = cmsFormatterForColorspaceOfProfile(hOutput, lIsFloat ? 0 : 2, lIsFloat); } // For named color, there is a specialized formatter if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) { dwIn = TYPE_NAMED_COLOR_INDEX; InputNamedColor = TRUE; } // Precision mode switch (PrecalcMode) { case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break; case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break; case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break; case 1: break; default: FatalError("Unknown precalculation mode '%d'", PrecalcMode); } if (BlackPointCompensation) dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; if (GamutCheck) { cmsUInt16Number Alarm[cmsMAXCHANNELS]; if (hProof == NULL) FatalError("I need proofing profile -p for gamut checking!"); for (i=0; i < cmsMAXCHANNELS; i++) Alarm[i] = 0xFFFF; cmsSetAlarmCodes(Alarm); dwFlags |= cmsFLAGS_GAMUTCHECK; } // The main transform hTrans = cmsCreateProofingTransform(hInput, dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags); if (hProof) cmsCloseProfile(hProof); if (hTrans == NULL) return FALSE; // PCS Dump if requested hTransXYZ = NULL; hTransLab = NULL; if (hOutput && Verbose > 1) { cmsHPROFILE hXYZ = cmsCreateXYZProfile(); cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); hTransXYZ = cmsCreateTransform(hInput, dwIn, hXYZ, lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE); if (hTransXYZ == NULL) return FALSE; hTransLab = cmsCreateTransform(hInput, dwIn, hLab, lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE); if (hTransLab == NULL) return FALSE; cmsCloseProfile(hXYZ); cmsCloseProfile(hLab); } if (hInput) cmsCloseProfile(hInput); if (hOutput) cmsCloseProfile(hOutput); return TRUE; }