This source file includes following definitions.
- Word2Byte
- WriteByte
- RemoveCR
- EmitHeader
- EmitWhiteBlackD50
- EmitRangeCheck
- EmitIntent
- EmitLab2XYZ
- Emit1Gamma
- GammaTableEquals
- EmitNGamma
- OutputValueSampler
- WriteCLUT
- EmitCIEBasedA
- EmitCIEBasedABC
- EmitCIEBasedDEF
- ExtractGray2Y
- WriteInputLUT
- GetPtrToMatrix
- WriteInputMatrixShaper
- WriteNamedColorCSA
- GenerateCSA
- EmitPQRStage
- EmitXYZ2Lab
- WriteOutputLUT
- BuildColorantList
- WriteNamedColorCRD
- GenerateCRD
- cmsGetPostScriptColorResource
- cmsGetPostScriptCRD
- cmsGetPostScriptCSA
#include "lcms2_internal.h"
#define MAXPSCOLS 60
typedef struct {
_cmsStageCLutData* Pipeline;
cmsIOHANDLER* m;
int FirstComponent;
int SecondComponent;
const char* PreMaj;
const char* PostMaj;
const char* PreMin;
const char* PostMin;
int FixWhite;
cmsColorSpaceSignature ColorSpace;
} cmsPsSamplerCargo;
static int _cmsPSActualColumn = 0;
static
cmsUInt8Number Word2Byte(cmsUInt16Number w)
{
return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
}
static
void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
{
_cmsIOPrintf(m, "%02x", b);
_cmsPSActualColumn += 2;
if (_cmsPSActualColumn > MAXPSCOLS) {
_cmsIOPrintf(m, "\n");
_cmsPSActualColumn = 0;
}
}
static
char* RemoveCR(const char* txt)
{
static char Buffer[2048];
char* pt;
strncpy(Buffer, txt, 2047);
Buffer[2047] = 0;
for (pt = Buffer; *pt; pt++)
if (*pt == '\n' || *pt == '\r') *pt = ' ';
return Buffer;
}
static
void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
{
time_t timer;
cmsMLU *Description, *Copyright;
char DescASCII[256], CopyrightASCII[256];
time(&timer);
Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
Copyright = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
DescASCII[0] = DescASCII[255] = 0;
CopyrightASCII[0] = CopyrightASCII[255] = 0;
if (Description != NULL) cmsMLUgetASCII(Description, cmsNoLanguage, cmsNoCountry, DescASCII, 255);
if (Copyright != NULL) cmsMLUgetASCII(Copyright, cmsNoLanguage, cmsNoCountry, CopyrightASCII, 255);
_cmsIOPrintf(m, "%%!PS-Adobe-3.0\n");
_cmsIOPrintf(m, "%%\n");
_cmsIOPrintf(m, "%% %s\n", Title);
_cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII));
_cmsIOPrintf(m, "%% %s\n", RemoveCR(CopyrightASCII));
_cmsIOPrintf(m, "%% Created: %s", ctime(&timer));
_cmsIOPrintf(m, "%%\n");
_cmsIOPrintf(m, "%%%%BeginResource\n");
}
static
void EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint)
{
_cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
BlackPoint -> Y,
BlackPoint -> Z);
_cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
cmsD50_XYZ()->Y,
cmsD50_XYZ()->Z);
}
static
void EmitRangeCheck(cmsIOHANDLER* m)
{
_cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if "
"dup 1.0 gt { pop 1.0 } if ");
}
static
void EmitIntent(cmsIOHANDLER* m, int RenderingIntent)
{
const char *intent;
switch (RenderingIntent) {
case INTENT_PERCEPTUAL: intent = "Perceptual"; break;
case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break;
case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break;
case INTENT_SATURATION: intent = "Saturation"; break;
default: intent = "Undefined"; break;
}
_cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
}
static
void EmitLab2XYZ(cmsIOHANDLER* m)
{
_cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
_cmsIOPrintf(m, "/DecodeABC [\n");
_cmsIOPrintf(m, "{100 mul 16 add 116 div } bind\n");
_cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
_cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
_cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
_cmsIOPrintf(m, "/DecodeLMN [\n");
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
_cmsIOPrintf(m, "]\n");
}
static
void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
{
cmsUInt32Number i;
cmsFloat64Number gamma;
if (Table == NULL) return;
if (Table ->nEntries <= 0) return;
if (cmsIsToneCurveLinear(Table)) return;
gamma = cmsEstimateGamma(Table, 0.001);
if (gamma > 0) {
_cmsIOPrintf(m, "{ %g exp } bind ", gamma);
return;
}
_cmsIOPrintf(m, "{ ");
EmitRangeCheck(m);
_cmsIOPrintf(m, " [");
for (i=0; i < Table->nEntries; i++) {
_cmsIOPrintf(m, "%d ", Table->Table16[i]);
}
_cmsIOPrintf(m, "] ");
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "length 1 sub ");
_cmsIOPrintf(m, "3 -1 roll ");
_cmsIOPrintf(m, "mul ");
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "floor cvi ");
_cmsIOPrintf(m, "exch ");
_cmsIOPrintf(m, "ceiling cvi ");
_cmsIOPrintf(m, "3 index ");
_cmsIOPrintf(m, "exch ");
_cmsIOPrintf(m, "get ");
_cmsIOPrintf(m, "4 -1 roll ");
_cmsIOPrintf(m, "3 -1 roll ");
_cmsIOPrintf(m, "get ");
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "3 1 roll ");
_cmsIOPrintf(m, "sub ");
_cmsIOPrintf(m, "3 -1 roll ");
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "floor cvi ");
_cmsIOPrintf(m, "sub ");
_cmsIOPrintf(m, "mul ");
_cmsIOPrintf(m, "add ");
_cmsIOPrintf(m, "65535 div ");
_cmsIOPrintf(m, " } bind ");
}
static
cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
{
return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
}
static
void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
{
int i;
for( i=0; i < n; i++ )
{
if (g[i] == NULL) return;
if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
_cmsIOPrintf(m, "dup ");
}
else {
Emit1Gamma(m, g[i]);
}
}
}
static
int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
cmsUInt32Number i;
if (sc -> FixWhite) {
if (In[0] == 0xFFFF) {
if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
(In[2] >= 0x7800 && In[2] <= 0x8800)) {
cmsUInt16Number* Black;
cmsUInt16Number* White;
cmsUInt32Number nOutputs;
if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
return 0;
for (i=0; i < nOutputs; i++)
Out[i] = White[i];
}
}
}
if (In[0] != sc ->FirstComponent) {
if (sc ->FirstComponent != -1) {
_cmsIOPrintf(sc ->m, sc ->PostMin);
sc ->SecondComponent = -1;
_cmsIOPrintf(sc ->m, sc ->PostMaj);
}
_cmsPSActualColumn = 0;
_cmsIOPrintf(sc ->m, sc ->PreMaj);
sc ->FirstComponent = In[0];
}
if (In[1] != sc ->SecondComponent) {
if (sc ->SecondComponent != -1) {
_cmsIOPrintf(sc ->m, sc ->PostMin);
}
_cmsIOPrintf(sc ->m, sc ->PreMin);
sc ->SecondComponent = In[1];
}
for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) {
cmsUInt16Number wWordOut = Out[i];
cmsUInt8Number wByteOut;
wByteOut = Word2Byte(wWordOut);
WriteByte(sc -> m, wByteOut);
}
return 1;
}
static
void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
const char* PostMaj,
const char* PreMin,
const char* PostMin,
int FixWhite,
cmsColorSpaceSignature ColorSpace)
{
cmsUInt32Number i;
cmsPsSamplerCargo sc;
sc.FirstComponent = -1;
sc.SecondComponent = -1;
sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
sc.m = m;
sc.PreMaj = PreMaj;
sc.PostMaj= PostMaj;
sc.PreMin = PreMin;
sc.PostMin = PostMin;
sc.FixWhite = FixWhite;
sc.ColorSpace = ColorSpace;
_cmsIOPrintf(m, "[");
for (i=0; i < sc.Pipeline->Params->nInputs; i++)
_cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
_cmsIOPrintf(m, " [\n");
cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
_cmsIOPrintf(m, PostMin);
_cmsIOPrintf(m, PostMaj);
_cmsIOPrintf(m, "] ");
}
static
int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
{
_cmsIOPrintf(m, "[ /CIEBasedA\n");
_cmsIOPrintf(m, " <<\n");
_cmsIOPrintf(m, "/DecodeA ");
Emit1Gamma(m, Curve);
_cmsIOPrintf(m, " \n");
_cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
_cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
EmitWhiteBlackD50(m, BlackPoint);
EmitIntent(m, INTENT_PERCEPTUAL);
_cmsIOPrintf(m, ">>\n");
_cmsIOPrintf(m, "]\n");
return 1;
}
static
int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
{
int i;
_cmsIOPrintf(m, "[ /CIEBasedABC\n");
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/DecodeABC [ ");
EmitNGamma(m, 3, CurveSet);
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/MatrixABC [ " );
for( i=0; i < 3; i++ ) {
_cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
Matrix[i + 3*1],
Matrix[i + 3*2]);
}
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
EmitWhiteBlackD50(m, BlackPoint);
EmitIntent(m, INTENT_PERCEPTUAL);
_cmsIOPrintf(m, ">>\n");
_cmsIOPrintf(m, "]\n");
return 1;
}
static
int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint)
{
const char* PreMaj;
const char* PostMaj;
const char* PreMin, *PostMin;
cmsStage* mpe;
mpe = Pipeline ->Elements;
switch (cmsStageInputChannels(mpe)) {
case 3:
_cmsIOPrintf(m, "[ /CIEBasedDEF\n");
PreMaj ="<";
PostMaj= ">\n";
PreMin = PostMin = "";
break;
case 4:
_cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
PreMaj = "[";
PostMaj = "]\n";
PreMin = "<";
PostMin = ">\n";
break;
default:
return 0;
}
_cmsIOPrintf(m, "<<\n");
if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
_cmsIOPrintf(m, "/DecodeDEF [ ");
EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
_cmsIOPrintf(m, "]\n");
mpe = mpe ->Next;
}
if (cmsStageType(mpe) == cmsSigCLutElemType) {
_cmsIOPrintf(m, "/Table ");
WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
_cmsIOPrintf(m, "]\n");
}
EmitLab2XYZ(m);
EmitWhiteBlackD50(m, BlackPoint);
EmitIntent(m, Intent);
_cmsIOPrintf(m, " >>\n");
_cmsIOPrintf(m, "]\n");
return 1;
}
static
cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
{
cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
cmsHPROFILE hXYZ = cmsCreateXYZProfile();
cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
int i;
if (Out != NULL) {
for (i=0; i < 256; i++) {
cmsUInt8Number Gray = (cmsUInt8Number) i;
cmsCIEXYZ XYZ;
cmsDoTransform(xform, &Gray, &XYZ, 1);
Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
}
}
cmsDeleteTransform(xform);
cmsCloseProfile(hXYZ);
return Out;
}
static
int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
cmsUInt32Number nChannels;
cmsUInt32Number InputFormat;
int rc;
cmsHPROFILE Profiles[2];
cmsCIEXYZ BlackPointAdaptedToD50;
InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
nChannels = T_CHANNELS(InputFormat);
cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
Profiles[0] = hProfile;
Profiles[1] = hLab;
xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0);
cmsCloseProfile(hLab);
if (xform == NULL) {
cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab");
return 0;
}
switch (nChannels) {
case 1: {
cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
cmsFreeToneCurve(Gray2Y);
}
break;
case 3:
case 4: {
cmsUInt32Number OutFrm = TYPE_Lab_16;
cmsPipeline* DeviceLink;
_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
DeviceLink = cmsPipelineDup(v ->Lut);
if (DeviceLink == NULL) return 0;
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
cmsPipelineFree(DeviceLink);
if (rc == 0) return 0;
}
break;
default:
cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
return 0;
}
cmsDeleteTransform(xform);
return 1;
}
static
cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
{
_cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
return Data -> Double;
}
static
int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper)
{
cmsColorSpaceSignature ColorSpace;
int rc;
cmsCIEXYZ BlackPointAdaptedToD50;
ColorSpace = cmsGetColorSpace(hProfile);
cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
if (ColorSpace == cmsSigGrayData) {
cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
}
else
if (ColorSpace == cmsSigRgbData) {
cmsMAT3 Mat;
int i, j;
memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
for (i=0; i < 3; i++)
for (j=0; j < 3; j++)
Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat,
_cmsStageGetPtrToCurveSet(Shaper),
&BlackPointAdaptedToD50);
}
else {
cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
return 0;
}
return rc;
}
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
cmsUInt32Number GenerateCSA(cmsContext ContextID,
cmsHPROFILE hProfile,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags,
cmsIOHANDLER* mem)
{
cmsUInt32Number dwBytesUsed;
cmsPipeline* lut = NULL;
cmsStage* Matrix, *Shaper;
if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error;
}
else {
cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
if (ColorSpace != cmsSigXYZData &&
ColorSpace != cmsSigLabData) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
goto Error;
}
lut = _cmsReadInputLUT(hProfile, Intent);
if (lut == NULL) goto Error;
if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) {
if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error;
}
else {
if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
}
}
dwBytesUsed = mem ->UsedSpace;
if (lut != NULL) cmsPipelineFree(lut);
return dwBytesUsed;
Error:
if (lut != NULL) cmsPipelineFree(lut);
return 0;
}
static
void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
{
if (lIsAbsolute) {
cmsCIEXYZ White;
_cmsReadMediaWhitePoint(&White, hProfile);
_cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
_cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
_cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
"/TransformPQR [\n"
"{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n"
"{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n"
"{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n",
White.X, White.Y, White.Z);
return;
}
_cmsIOPrintf(m,"%% Bradford Cone Space\n"
"/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n");
_cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
if (!DoBPC) {
_cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n"
"/TransformPQR [\n"
"{exch pop exch 3 get mul exch pop exch 3 get div} bind\n"
"{exch pop exch 4 get mul exch pop exch 4 get div} bind\n"
"{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n");
} else {
_cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
"/TransformPQR [\n");
_cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
"2 index 3 get 2 index 3 get sub mul "
"2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
"3 index 3 get 3 index 3 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n");
_cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
"2 index 4 get 2 index 4 get sub mul "
"2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
"3 index 4 get 3 index 4 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n");
_cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
"2 index 5 get 2 index 5 get sub mul "
"2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
"3 index 5 get 3 index 5 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n]\n");
}
}
static
void EmitXYZ2Lab(cmsIOHANDLER* m)
{
_cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
_cmsIOPrintf(m, "/EncodeLMN [\n");
_cmsIOPrintf(m, "{ 0.964200 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
_cmsIOPrintf(m, "{ 1.000000 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
_cmsIOPrintf(m, "{ 0.824900 div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
_cmsIOPrintf(m, "/EncodeABC [\n");
_cmsIOPrintf(m, "{ 116 mul 16 sub 100 div } bind\n");
_cmsIOPrintf(m, "{ 500 mul 128 add 256 div } bind\n");
_cmsIOPrintf(m, "{ 200 mul 128 add 256 div } bind\n");
_cmsIOPrintf(m, "]\n");
}
static
int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
int i, nChannels;
cmsUInt32Number OutputFormat;
_cmsTRANSFORM* v;
cmsPipeline* DeviceLink;
cmsHPROFILE Profiles[3];
cmsCIEXYZ BlackPointAdaptedToD50;
cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
cmsUInt32Number InFrm = TYPE_Lab_16;
int RelativeEncodingIntent;
cmsColorSpaceSignature ColorSpace;
hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
if (hLab == NULL) return 0;
OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
nChannels = T_CHANNELS(OutputFormat);
ColorSpace = cmsGetColorSpace(hProfile);
RelativeEncodingIntent = Intent;
if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
Profiles[0] = hLab;
Profiles[1] = hProfile;
xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
Profiles, 2, TYPE_Lab_DBL,
OutputFormat, RelativeEncodingIntent, 0);
cmsCloseProfile(hLab);
if (xform == NULL) {
cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
return 0;
}
v = (_cmsTRANSFORM*) xform;
DeviceLink = cmsPipelineDup(v ->Lut);
if (DeviceLink == NULL) return 0;
dwFlags |= cmsFLAGS_FORCE_CLUT;
_cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/ColorRenderingType 1\n");
cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
EmitXYZ2Lab(m);
if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
lFixWhite = FALSE;
_cmsIOPrintf(m, "/RenderTable ");
WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
_cmsIOPrintf(m, " %d {} bind ", nChannels);
for (i=1; i < nChannels; i++)
_cmsIOPrintf(m, "dup ");
_cmsIOPrintf(m, "]\n");
EmitIntent(m, Intent);
_cmsIOPrintf(m, ">>\n");
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
_cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
}
cmsPipelineFree(DeviceLink);
cmsDeleteTransform(xform);
return 1;
}
static
void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
{
char Buff[32];
int j;
Colorant[0] = 0;
if (nColorant > cmsMAXCHANNELS)
nColorant = cmsMAXCHANNELS;
for (j=0; j < nColorant; j++) {
sprintf(Buff, "%.3f", Out[j] / 65535.0);
strcat(Colorant, Buff);
if (j < nColorant -1)
strcat(Colorant, " ");
}
}
static
int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags)
{
cmsHTRANSFORM xform;
int i, nColors, nColorant;
cmsUInt32Number OutputFormat;
char ColorName[32];
char Colorant[128];
cmsNAMEDCOLORLIST* NamedColorList;
OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
nColorant = T_CHANNELS(OutputFormat);
xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
if (xform == NULL) return 0;
NamedColorList = cmsGetNamedColorList(xform);
if (NamedColorList == NULL) return 0;
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
_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];
cmsUInt16Number Out[cmsMAXCHANNELS];
In[0] = (cmsUInt16Number) i;
if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
continue;
cmsDoTransform(xform, In, Out, 1);
BuildColorantList(Colorant, nColorant, Out);
_cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant);
}
_cmsIOPrintf(m, " >>");
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
_cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n");
}
cmsDeleteTransform(xform);
return 1;
}
static
cmsUInt32Number GenerateCRD(cmsContext ContextID,
cmsHPROFILE hProfile,
cmsUInt32Number Intent, cmsUInt32Number dwFlags,
cmsIOHANDLER* mem)
{
cmsUInt32Number dwBytesUsed;
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
}
if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) {
return 0;
}
}
else {
if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
return 0;
}
}
if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
_cmsIOPrintf(mem, "%%%%EndResource\n");
_cmsIOPrintf(mem, "\n%% CRD End\n");
}
dwBytesUsed = mem ->UsedSpace;
return dwBytesUsed;
cmsUNUSED_PARAMETER(ContextID);
}
cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
cmsPSResourceType Type,
cmsHPROFILE hProfile,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags,
cmsIOHANDLER* io)
{
cmsUInt32Number rc;
switch (Type) {
case cmsPS_RESOURCE_CSA:
rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
break;
default:
case cmsPS_RESOURCE_CRD:
rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
break;
}
return rc;
}
cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID,
cmsHPROFILE hProfile,
cmsUInt32Number Intent, cmsUInt32Number dwFlags,
void* Buffer, cmsUInt32Number dwBufferLen)
{
cmsIOHANDLER* mem;
cmsUInt32Number dwBytesUsed;
if (Buffer == NULL)
mem = cmsOpenIOhandlerFromNULL(ContextID);
else
mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
if (!mem) return 0;
dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem);
cmsCloseIOhandler(mem);
return dwBytesUsed;
}
cmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID,
cmsHPROFILE hProfile,
cmsUInt32Number Intent,
cmsUInt32Number dwFlags,
void* Buffer,
cmsUInt32Number dwBufferLen)
{
cmsIOHANDLER* mem;
cmsUInt32Number dwBytesUsed;
if (Buffer == NULL)
mem = cmsOpenIOhandlerFromNULL(ContextID);
else
mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
if (!mem) return 0;
dwBytesUsed = cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem);
cmsCloseIOhandler(mem);
return dwBytesUsed;
}