2193 lines
67 KiB
C
2193 lines
67 KiB
C
#include "generic.h"
|
|
#include "icmstr.h"
|
|
|
|
#pragma code_seg(_ICM3SEG)
|
|
|
|
#define MAXCOLOR8 255
|
|
|
|
#pragma optimize("", off)
|
|
|
|
static SINT
|
|
CreateHostInputOutputArray (MEMPTR lpMem, PMEMPTR ppArray,
|
|
SINT numChan, SINT tableSize, SINT Offset, CSIG Tag, MEMPTR Buff);
|
|
static BOOL
|
|
CheckInputOutputTable(LPHOSTCLUT lpHostClut, float far *fTemp, BOOL, BOOL);
|
|
BOOL
|
|
GetHostCSA_Intent (CHANDLE cp, MEMPTR lpBuffer, LPDWORD lpcbSize,
|
|
CSIG Intent, int Type);
|
|
static BOOL
|
|
CheckColorLookupTable(LPHOSTCLUT lpHostClut, float far *fTemp);
|
|
static BOOL
|
|
DoHostConversionCRD (LPHOSTCLUT lpHostCRD, LPHOSTCLUT lpHostCSA,
|
|
float far *Input, float far *Output,
|
|
CSIG ColorSpace, BOOL bCheckOutputTable);
|
|
static BOOL
|
|
DoHostConversionCSA (LPHOSTCLUT lpHostClut, float far *Input, float far *Output);
|
|
static BOOL
|
|
GetCRDInputOutputArraySize(CHANDLE cp, DWORD Intent,
|
|
LPSINT lpInTbSize, LPSINT lpOutTbSize,
|
|
LPCSIG lpIntentTag, LPSINT lpGrids);
|
|
static void
|
|
LabToXYZ(float far *Input, float far *Output, float far *whitePoint);
|
|
|
|
/*
|
|
* CreateHostInputOutputArray
|
|
* function:
|
|
* this is the function which creates the output array from the data
|
|
* supplied in the ColorProfile's LUT8 or LUT16 tag.
|
|
* parameters:
|
|
* MEMPTR lpMem : The buffer to save output array.
|
|
* LPHOSTCLUT lpHostClut :
|
|
* SINT nOutputCh : Number of input channel.
|
|
* SINT nOutputTable : The size of each input table.
|
|
* SINT Offset : The position of source output data(in icc profile).
|
|
* CSIG Tag : To determin the Output table is 8 or 16 bits.
|
|
* MEMPTR Buff : The buffer that contains source data(copyed from icc profile)
|
|
|
|
* returns:
|
|
* SINT Returns number of bytes of Output Array
|
|
|
|
*/
|
|
|
|
static SINT
|
|
CreateHostInputOutputArray (MEMPTR lpMem, PMEMPTR ppArray,
|
|
SINT numChan, SINT tableSize,
|
|
SINT Offset, CSIG Tag, MEMPTR Buff)
|
|
{
|
|
SINT i, j;
|
|
PUSHORT lpMemPtr16;
|
|
MEMPTR lpMemPtr8;
|
|
MEMPTR lpTable;
|
|
|
|
if (Tag == icSigLut8Type)
|
|
lpMemPtr8 = lpMem;
|
|
else
|
|
lpMemPtr16 = (PUSHORT)lpMem;
|
|
|
|
for (i = 0; i < numChan; i++)
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
ppArray[i] = lpMemPtr8;
|
|
lpTable = (MEMPTR) (((lpcpLut8Type) Buff)->lut.data) +
|
|
Offset +
|
|
tableSize * i;
|
|
MemCopy(lpMemPtr8, lpTable, tableSize);
|
|
lpMemPtr8 += tableSize;
|
|
}
|
|
else
|
|
{
|
|
ppArray[i] = (MEMPTR)lpMemPtr16;
|
|
lpTable = (MEMPTR) (((lpcpLut16Type) Buff)->lut.data) +
|
|
2 * Offset +
|
|
2 * tableSize * i;
|
|
for (j = 0; j < tableSize; j++)
|
|
{
|
|
*lpMemPtr16++ = (USHORT) ui16toSINT (lpTable);
|
|
lpTable += sizeof (icUInt16Number);
|
|
}
|
|
}
|
|
}
|
|
if (Tag == icSigLut8Type)
|
|
return ((SINT) ((MEMPTR)lpMemPtr8 - lpMem));
|
|
else
|
|
return ((SINT) ((MEMPTR)lpMemPtr16 - lpMem));
|
|
|
|
}
|
|
|
|
VOID
|
|
GetCLUTinfo(CSIG LutTag, MEMPTR lpLut, LPSINT nInputCh, LPSINT nOutputCh,
|
|
LPSINT nGrids, LPSINT nInputTable, LPSINT nOutputTable, LPSINT size)
|
|
{
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
*nInputCh = ui8toSINT (((lpcpLut8Type) lpLut)->lut.inputChan);
|
|
*nOutputCh = ui8toSINT (((lpcpLut8Type) lpLut)->lut.outputChan);
|
|
*nGrids = ui8toSINT (((lpcpLut8Type) lpLut)->lut.clutPoints);
|
|
*nInputTable = 256L;
|
|
*nOutputTable = 256L;
|
|
*size = 1; // one byte for each input\output table entry
|
|
} else
|
|
{
|
|
*nInputCh = ui8toSINT (((lpcpLut16Type) lpLut)->lut.inputChan);
|
|
*nOutputCh = ui8toSINT (((lpcpLut16Type) lpLut)->lut.outputChan);
|
|
*nGrids = ui8toSINT (((lpcpLut16Type) lpLut)->lut.clutPoints);
|
|
*nInputTable = ui16toSINT (((lpcpLut16Type) lpLut)->lut.inputEnt);
|
|
*nOutputTable = ui16toSINT (((lpcpLut16Type) lpLut)->lut.outputEnt);
|
|
*size = 2; // two bytes for each input\output table entry
|
|
}
|
|
}
|
|
|
|
/*
|
|
* GetHostCSA
|
|
* function:
|
|
* this is the function which creates a Host CSA
|
|
* parameters:
|
|
* CHANDLE cp -- Color Profile handle
|
|
* MEMPTR lpMem -- Pointer to the memory block. If this point is NULL,
|
|
* require buffer size.
|
|
* LPDWORD lpcbSize -- Size of the memory block
|
|
* CSIG InputIntent --
|
|
* SINT Index -- to the icc profile tag that contains the data of Intent
|
|
* int Type -- DEF or DEFG
|
|
* returns:
|
|
* BOOL -- TRUE if the function was successful,
|
|
* FALSE otherwise.
|
|
*/
|
|
static BOOL
|
|
GetHostCSA (CHANDLE cp, MEMPTR lpMem, LPDWORD lpcbSize,
|
|
CSIG InputIntent, SINT Index, int Type)
|
|
{
|
|
CSIG PCS, LutTag;
|
|
CSIG IntentSig;
|
|
SINT nInputCh, nOutputCh, nGrids, SecondGrids;
|
|
SINT nInputTable, nOutputTable, nNumbers;
|
|
SINT i, j, k;
|
|
MEMPTR lpTable;
|
|
MEMPTR lpOldMem = lpMem;
|
|
MEMPTR lpLut = NULL;
|
|
HGLOBAL hLut = 0;
|
|
SINT LutSize;
|
|
LPHOSTCLUT lpHostClut;
|
|
|
|
// Check if we can generate the CS.
|
|
// If we cannot find the required tag - we will return false
|
|
if (!GetCPConnSpace (cp, (LPCSIG) & PCS) ||
|
|
(PCS != icSigLabData) && (PCS != icSigXYZData) ||
|
|
!GetCPTagSig (cp, Index, (LPCSIG) & IntentSig))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
if (!GetCPElementType (cp, Index, (LPCSIG) & LutTag) ||
|
|
((LutTag != icSigLut8Type) && (LutTag != icSigLut16Type)) ||
|
|
!GetCPElementSize (cp, Index, (LPSINT) & LutSize) ||
|
|
!MemAlloc (LutSize, (HGLOBAL FAR *) &hLut, (LPMEMPTR) & lpLut) ||
|
|
!GetCPElement (cp, Index, lpLut, LutSize))
|
|
{
|
|
if (0 != hLut)
|
|
{
|
|
MemFree (hLut);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
// Estimate the memory size required to hold CS
|
|
GetCLUTinfo(LutTag, lpLut, &nInputCh, &nOutputCh,
|
|
&nGrids, &nInputTable, &nOutputTable, &i);
|
|
|
|
if (!(nOutputCh == 3) ||
|
|
!((nInputCh == 3) && (Type == TYPE_CIEBASEDDEF)) &&
|
|
!((nInputCh == 4) && (Type == TYPE_CIEBASEDDEFG)))
|
|
{
|
|
SetCPLastError (CP_POSTSCRIPT_ERR);
|
|
MemFree (hLut);
|
|
return (FALSE);
|
|
}
|
|
|
|
// First Pass. This is a size request
|
|
if (lpMem == NULL)
|
|
{
|
|
if (Type == TYPE_CIEBASEDDEFG)
|
|
*lpcbSize = nOutputCh * nGrids * nGrids * nGrids * nGrids;
|
|
else
|
|
*lpcbSize = nOutputCh * nGrids * nGrids * nGrids;
|
|
*lpcbSize = *lpcbSize + // size of RenderTable 8-bits only
|
|
nInputCh * nInputTable * i + // size of input table 8/16-bits
|
|
nOutputCh * nOutputTable * i + // size of output table 8/16-bits
|
|
sizeof(HOSTCLUT) + 1024; // data structure + extra safe space
|
|
MemFree (hLut);
|
|
return (TRUE);
|
|
}
|
|
|
|
// Second pass. constructure real HostCSA
|
|
lpHostClut = (LPHOSTCLUT)lpMem;
|
|
lpMem += sizeof(HOSTCLUT);
|
|
lpHostClut->size = sizeof(HOSTCLUT);
|
|
lpHostClut->pcs = PCS;
|
|
lpHostClut->intent = InputIntent;
|
|
lpHostClut->lutBits = (LutTag == icSigLut8Type)? 8:16;
|
|
|
|
// Get info about Illuminant White Point from the header
|
|
GetCPWhitePoint (cp, (LPSFLOAT)lpHostClut->whitePoint); // .. Illuminant
|
|
|
|
lpHostClut->inputChan = (unsigned char)nInputCh;
|
|
lpHostClut->outputChan = (unsigned char)nOutputCh;
|
|
lpHostClut->clutPoints = (unsigned char)nGrids;
|
|
lpHostClut->inputEnt = (USHORT)nInputTable;
|
|
lpHostClut->outputEnt = (USHORT)nOutputTable;
|
|
// Input Array
|
|
lpMem += CreateHostInputOutputArray (lpMem, lpHostClut->inputArray,
|
|
nInputCh, nInputTable, 0, LutTag, lpLut);
|
|
|
|
if (Type == TYPE_CIEBASEDDEFG)
|
|
{
|
|
i = nInputTable * nInputCh +
|
|
nGrids * nGrids * nGrids * nGrids * nOutputCh;
|
|
} else
|
|
{
|
|
i = nInputTable * nInputCh +
|
|
nGrids * nGrids * nGrids * nOutputCh;
|
|
}
|
|
// ourput array
|
|
lpMem += CreateHostInputOutputArray (lpMem, lpHostClut->outputArray,
|
|
nOutputCh, nOutputTable, i, LutTag, lpLut);
|
|
//********** /Table
|
|
|
|
lpHostClut->clut = lpMem;
|
|
nNumbers = nGrids * nGrids * nOutputCh;
|
|
SecondGrids = 1;
|
|
if (Type == TYPE_CIEBASEDDEFG)
|
|
{
|
|
SecondGrids = nGrids;
|
|
}
|
|
for (i = 0; i < nGrids; i++) // Nh strings should be sent
|
|
{
|
|
for (k = 0; k < SecondGrids; k++)
|
|
{
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
lpTable = (MEMPTR) (((lpcpLut8Type) lpLut)->lut.data) +
|
|
nInputTable * nInputCh +
|
|
nNumbers * (i * SecondGrids + k);
|
|
} else
|
|
{
|
|
lpTable = (MEMPTR) (((lpcpLut16Type) lpLut)->lut.data) +
|
|
2 * nInputTable * nInputCh +
|
|
2 * nNumbers * (i * SecondGrids + k);
|
|
}
|
|
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
// Copy 8-bit data.
|
|
MemCopy(lpMem, lpTable, nNumbers);
|
|
lpMem += nNumbers;
|
|
}
|
|
else
|
|
{
|
|
// convert 16 bit integer to right format. then copy only 8 bits.
|
|
for (j = 0; j < nNumbers; j++)
|
|
{
|
|
*lpMem++ = (BYTE)(ui16toSINT (lpTable) / 256);
|
|
lpTable += sizeof (icUInt16Number);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*lpcbSize = (DWORD) (lpMem - lpOldMem);
|
|
|
|
MemFree (hLut);
|
|
return (TRUE);
|
|
}
|
|
|
|
// BUGBUG -- MOVE to CSPROF.C
|
|
HGLOBAL GetTRCData(CHANDLE cp,
|
|
LPMEMPTR lpRed, LPMEMPTR lpGreen, LPMEMPTR lpBlue,
|
|
LPSINT lpnRed, LPSINT lpnGreen, LPSINT lpnBlue)
|
|
{
|
|
SINT RedTRCIndex, GreenTRCIndex, BlueTRCIndex;
|
|
SINT RedTRCSize = 0, GreenTRCSize = 0, BlueTRCSize = 0;
|
|
SINT MemSize;
|
|
HGLOBAL hMem;
|
|
|
|
// Check if we can generate the CRD
|
|
if (!GetTRCElementSize(cp, icSigRedTRCTag, &RedTRCIndex, &RedTRCSize) ||
|
|
!GetTRCElementSize(cp, icSigGreenTRCTag, &GreenTRCIndex, &GreenTRCSize) ||
|
|
!GetTRCElementSize(cp, icSigBlueTRCTag, &BlueTRCIndex, &BlueTRCSize))
|
|
{
|
|
return 0;
|
|
}
|
|
MemSize = RedTRCSize + GreenTRCSize + BlueTRCSize;
|
|
if (!MemAlloc (MemSize, (HGLOBAL FAR *)&hMem, (LPMEMPTR) lpRed))
|
|
return 0;
|
|
|
|
*lpGreen = *lpRed + RedTRCSize;
|
|
*lpBlue = *lpGreen + GreenTRCSize;
|
|
if (!GetCPElement (cp, RedTRCIndex, *lpRed, RedTRCSize) ||
|
|
!GetCPElement (cp, GreenTRCIndex, *lpGreen, GreenTRCSize ) ||
|
|
!GetCPElement (cp, BlueTRCIndex, *lpBlue, BlueTRCSize ))
|
|
{
|
|
MemFree (hMem);
|
|
return (NULL);
|
|
}
|
|
*lpnRed = ui32toSINT (((lpcpCurveType) *lpRed)->curve.count);
|
|
*lpnGreen = ui32toSINT (((lpcpCurveType) *lpGreen)->curve.count);
|
|
*lpnBlue = ui32toSINT (((lpcpCurveType) *lpBlue)->curve.count);
|
|
|
|
return (hMem);
|
|
}
|
|
|
|
|
|
static SINT
|
|
CreateHostTRCInputTable(MEMPTR lpMem, LPHOSTCLUT lpHostClut,
|
|
MEMPTR lpRed, MEMPTR lpGreen, MEMPTR lpBlue)
|
|
{
|
|
SINT i;
|
|
PUSHORT lpPtr16;
|
|
MEMPTR lpTable;
|
|
|
|
lpPtr16 = (PUSHORT)lpMem;
|
|
|
|
lpHostClut->inputArray[0] = (MEMPTR)lpPtr16;
|
|
lpTable = (MEMPTR)(((lpcpCurveType) lpRed)->curve.data);
|
|
for (i = 0; i < (SINT)(lpHostClut->inputEnt); i++)
|
|
{
|
|
*lpPtr16++ = (USHORT) ui16toSINT(lpTable);
|
|
lpTable += sizeof(icUInt16Number);
|
|
}
|
|
|
|
lpHostClut->inputArray[1] = (MEMPTR)lpPtr16;
|
|
lpTable = (MEMPTR)(((lpcpCurveType) lpGreen)->curve.data);
|
|
for (i = 0; i < (SINT)(lpHostClut->inputEnt); i++)
|
|
{
|
|
*lpPtr16++ = (USHORT) ui16toSINT(lpTable);
|
|
lpTable += sizeof(icUInt16Number);
|
|
}
|
|
|
|
lpHostClut->inputArray[2] = (MEMPTR)lpPtr16;
|
|
lpTable = (MEMPTR)(((lpcpCurveType) lpBlue)->curve.data);
|
|
for (i = 0; i < (SINT)(lpHostClut->inputEnt); i++)
|
|
{
|
|
*lpPtr16++ = (USHORT) ui16toSINT(lpTable);
|
|
lpTable += sizeof(icUInt16Number);
|
|
}
|
|
return ((MEMPTR)lpPtr16 - lpMem);
|
|
}
|
|
|
|
static SINT
|
|
CreateHostRevTRCInputTable(MEMPTR lpMem, LPHOSTCLUT lpHostClut,
|
|
MEMPTR lpRed, MEMPTR lpGreen, MEMPTR lpBlue)
|
|
{
|
|
HGLOBAL hTemp;
|
|
MEMPTR lpTemp;
|
|
|
|
if (!MemAlloc (lpHostClut->outputEnt * (REVCURVE_RATIO + 1) * 2 ,
|
|
(HGLOBAL FAR *) &hTemp, (LPMEMPTR) &lpTemp))
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
lpHostClut->outputArray[0] = lpMem;
|
|
GetRevCurve (lpRed, lpTemp, lpHostClut->outputArray[0]);
|
|
lpHostClut->outputArray[1] = lpHostClut->outputArray[0] +
|
|
2 * REVCURVE_RATIO * lpHostClut->outputEnt;
|
|
GetRevCurve (lpGreen, lpTemp, lpHostClut->outputArray[1]);
|
|
lpHostClut->outputArray[2] = lpHostClut->outputArray[1] +
|
|
2 * REVCURVE_RATIO * lpHostClut->outputEnt;
|
|
GetRevCurve (lpBlue, lpTemp, lpHostClut->outputArray[2]);
|
|
|
|
MemFree (hTemp);
|
|
return ( 2 * REVCURVE_RATIO * lpHostClut->outputEnt * 3);
|
|
}
|
|
|
|
static BOOL
|
|
GetHostMatrixCSAorCRD(CHANDLE cp, MEMPTR lpMem, LPDWORD lpcbSize, BOOL bCSA)
|
|
{
|
|
SINT nRedCount, nGreenCount, nBlueCount;
|
|
MEMPTR lpRed = NULL,lpGreen, lpBlue;
|
|
HGLOBAL hMem;
|
|
LPHOSTCLUT lpHostClut;
|
|
MEMPTR lpOldMem = lpMem;
|
|
double pArray[9], pRevArray[9], pTemp[9];
|
|
SINT i;
|
|
|
|
hMem = GetTRCData(cp,
|
|
(LPMEMPTR)&lpRed, (LPMEMPTR)&lpGreen, (LPMEMPTR)&lpBlue,
|
|
(LPSINT)&nRedCount,(LPSINT)&nGreenCount, (LPSINT)&nBlueCount);
|
|
|
|
// Estimate the memory size required to hold CRD
|
|
*lpcbSize = (nRedCount + nGreenCount + nBlueCount) * 2 +
|
|
sizeof(HOSTCLUT) + 1024; // data structure + extra safe space
|
|
|
|
if (lpMem == NULL) // This is a size request
|
|
{
|
|
MemFree (hMem);
|
|
return TRUE;
|
|
}
|
|
|
|
lpHostClut = (LPHOSTCLUT)lpMem;
|
|
lpMem += sizeof(HOSTCLUT);
|
|
lpHostClut->size = sizeof(HOSTCLUT);
|
|
lpHostClut->dataType = DATA_matrix;
|
|
lpHostClut->clutPoints = 2;
|
|
lpHostClut->pcs = icSigXYZData;
|
|
GetCPWhitePoint(cp, (LPSFLOAT)lpHostClut->whitePoint);
|
|
|
|
if (bCSA)
|
|
{
|
|
lpHostClut->inputEnt = (USHORT)nRedCount;
|
|
lpHostClut->inputChan = 3;
|
|
lpMem += CreateHostTRCInputTable(lpMem, lpHostClut,
|
|
lpRed, lpGreen, lpBlue);
|
|
}
|
|
else
|
|
{
|
|
lpHostClut->outputEnt = (USHORT)nRedCount;
|
|
lpHostClut->outputChan = 3;
|
|
lpMem += CreateHostRevTRCInputTable(lpMem, lpHostClut,
|
|
lpRed, lpGreen, lpBlue);
|
|
}
|
|
|
|
MemFree (hMem);
|
|
*lpcbSize = (DWORD) (lpMem - lpOldMem);
|
|
|
|
if (!CreateColorantArray(cp, &pTemp[0], icSigRedColorantTag) ||
|
|
!CreateColorantArray(cp, &pTemp[3], icSigGreenColorantTag) ||
|
|
!CreateColorantArray(cp, &pTemp[6], icSigBlueColorantTag))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
pArray[i] = pTemp[i/8*8 + i*3%8];
|
|
}
|
|
|
|
if (bCSA)
|
|
{
|
|
for (i = 0; i < 9; i++)
|
|
lpHostClut->e[i] = (float)pArray[i];
|
|
}
|
|
else
|
|
{
|
|
InvertMatrix(pArray, pRevArray);
|
|
for (i = 0; i < 9; i++)
|
|
lpHostClut->e[i] = (float)pRevArray[i];
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* GetHostCSA_Intent
|
|
* function:
|
|
* This is the function which creates the Host DEF or DEFGColorSpace array
|
|
* based on Intent.
|
|
* parameters:
|
|
* cp -- Color Profile handle
|
|
* lpBuffer -- Pointer to the memory block. If this point is NULL,
|
|
* require buffer size.
|
|
* lpcbSize -- Size of the memory block
|
|
* Intent -- Intent.
|
|
* Type -- CieBasedDEF or CieBasedDEF.
|
|
* returns:
|
|
* BOOL -- TRUE if the function was successful,
|
|
* FALSE otherwise.
|
|
*/
|
|
|
|
BOOL
|
|
GetHostCSA_Intent (CHANDLE cp, MEMPTR lpBuffer, LPDWORD lpcbSize,
|
|
CSIG Intent, int Type)
|
|
{
|
|
SINT Index;
|
|
BOOL Success = FALSE;
|
|
CSIG AToBxTag;
|
|
|
|
switch (Intent)
|
|
{
|
|
case icPerceptual:
|
|
AToBxTag = icSigAToB0Tag;
|
|
break;
|
|
case icRelativeColorimetric:
|
|
case icAbsoluteColorimetric:
|
|
// use RelativeColorimetric data to build it.
|
|
AToBxTag = icSigAToB1Tag;
|
|
break;
|
|
case icSaturation:
|
|
AToBxTag = icSigAToB2Tag;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
break;
|
|
}
|
|
if (DoesCPTagExist (cp, AToBxTag) &&
|
|
GetCPTagIndex (cp, AToBxTag, (LPSINT) & Index))
|
|
{
|
|
Success = GetHostCSA(cp, lpBuffer, lpcbSize, Intent, Index, Type);
|
|
}
|
|
else if ((DoesTRCAndColorantTagExist(cp)) &&
|
|
(Type == TYPE_CIEBASEDDEF))
|
|
{
|
|
Success = GetHostMatrixCSAorCRD(cp, lpBuffer, lpcbSize, TRUE);
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
/*
|
|
* GetHostColorSpaceArray
|
|
* function:
|
|
* This is the main function which creates the Host CSA
|
|
* from the data supplied in the Profile.
|
|
* parameters:
|
|
* cp -- Color Profile handle
|
|
* InputIntent -- Intent.
|
|
* lpBuffer -- Pointer to the memory block. If this point is NULL,
|
|
* require buffer size.
|
|
* lpcbSize -- Size of the memory block
|
|
* returns:
|
|
* BOOL -- TRUE if the function was successful,
|
|
* FALSE otherwise.
|
|
*/
|
|
static BOOL
|
|
GetHostColorSpaceArray (CHANDLE cp, DWORD InputIntent,
|
|
MEMPTR lpBuffer, LPDWORD lpcbSize)
|
|
{
|
|
CSIG ColorSpace, Intent;
|
|
BOOL Success = FALSE;
|
|
|
|
if (!cp)
|
|
return Success;
|
|
|
|
if (!GetCPDevSpace (cp, (LPCSIG) & ColorSpace) ||
|
|
!GetCPRenderIntent (cp, (LPCSIG) & Intent))
|
|
{
|
|
return Success;
|
|
}
|
|
if (InputIntent == icUseRenderingIntent)
|
|
InputIntent = (DWORD)Intent;
|
|
|
|
if (!Success)
|
|
{
|
|
switch (ColorSpace)
|
|
{
|
|
case icSigRgbData:
|
|
Success = GetHostCSA_Intent (cp, lpBuffer, lpcbSize,
|
|
(CSIG) InputIntent, TYPE_CIEBASEDDEF);
|
|
break;
|
|
case icSigCmykData:
|
|
Success = GetHostCSA_Intent (cp, lpBuffer, lpcbSize,
|
|
(CSIG) InputIntent, TYPE_CIEBASEDDEFG);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* CreateHostLutCRD
|
|
* function:
|
|
* this is the function which creates the Host CRD
|
|
* from the data supplied in the ColorProfile's LUT8 or LUT16 tag.
|
|
* parameters:
|
|
* cp -- Color Profile handle
|
|
* Index -- Index of the tag
|
|
* lpMem -- Pointer to the memory block.If this point is NULL,
|
|
* require buffer size.
|
|
* InputIntent -- Intent.
|
|
|
|
* returns:
|
|
* SINT -- Size of Host CRD.
|
|
*/
|
|
|
|
static SINT
|
|
CreateHostLutCRD (CHANDLE cp, SINT Index, MEMPTR lpMem, DWORD InputIntent)
|
|
{
|
|
SINT nInputCh, nOutputCh, nGrids;
|
|
SINT nInputTable, nOutputTable, nNumbers;
|
|
CSIG Tag, PCS;
|
|
CSIG IntentSig;
|
|
|
|
SINT Ret;
|
|
SINT i, j;
|
|
MEMPTR lpTable;
|
|
|
|
MEMPTR Buff = NULL;
|
|
SINT MemSize = 0;
|
|
MEMPTR lpOldMem = lpMem;
|
|
HGLOBAL hMem;
|
|
LPHOSTCLUT lpHostClut;
|
|
|
|
// Check if we can generate the CRD
|
|
if (!GetCPTagSig (cp, Index, (LPCSIG) & IntentSig) ||
|
|
!GetCPElementType (cp, Index, (LPCSIG) & Tag) ||
|
|
((Tag != icSigLut8Type) && (Tag != icSigLut16Type)) ||
|
|
!GetCPConnSpace (cp, (LPCSIG) & PCS) ||
|
|
!GetCPElementSize (cp, Index, (LPSINT) & MemSize) ||
|
|
!MemAlloc (MemSize, (HGLOBAL FAR *)&hMem, (LPMEMPTR) & Buff) ||
|
|
!GetCPElement (cp, Index, Buff, MemSize))
|
|
{
|
|
if (NULL != Buff)
|
|
{
|
|
MemFree (hMem);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
GetCLUTinfo(Tag, Buff, &nInputCh, &nOutputCh,
|
|
&nGrids, &nInputTable, &nOutputTable, &i);
|
|
|
|
if (((nOutputCh != 3) && (nOutputCh != 4)) ||
|
|
(nInputCh != 3))
|
|
{
|
|
SetCPLastError (CP_POSTSCRIPT_ERR);
|
|
MemFree (hMem);
|
|
return (0);
|
|
}
|
|
|
|
// First Pass. This is a size request
|
|
if (lpMem == NULL)
|
|
{
|
|
Ret = nInputCh * nInputTable * i + // Input table 8/16-bits
|
|
nOutputCh * nOutputTable * i + // Output table 8/16-bits
|
|
nOutputCh * nGrids * nGrids * nGrids + // CLUT 8-bits only
|
|
sizeof(HOSTCLUT) + // Data structure
|
|
1024; // safe
|
|
|
|
MemFree (hMem);
|
|
return (Ret);
|
|
}
|
|
|
|
// Second Pass. Get a HostCRD
|
|
lpHostClut = (LPHOSTCLUT)lpMem;
|
|
lpMem += sizeof(HOSTCLUT);
|
|
lpHostClut->size = sizeof(HOSTCLUT);
|
|
lpHostClut->pcs = PCS;
|
|
lpHostClut->intent = InputIntent;
|
|
lpHostClut->lutBits = (Tag == icSigLut8Type)? 8:16;
|
|
|
|
GetCPWhitePoint (cp, (LPSFLOAT)lpHostClut->whitePoint); // .. Illuminant
|
|
|
|
// Support absolute whitePoint
|
|
if (!GetCPMediaWhitePoint (cp, (LPSFLOAT)lpHostClut->mediaWP)) // .. Media WhitePoint
|
|
{
|
|
lpHostClut->mediaWP[0] = lpHostClut->whitePoint[0];
|
|
lpHostClut->mediaWP[1] = lpHostClut->whitePoint[1];
|
|
lpHostClut->mediaWP[2] = lpHostClut->whitePoint[2];
|
|
}
|
|
lpHostClut->inputChan = (unsigned char)nInputCh;
|
|
lpHostClut->outputChan = (unsigned char)nOutputCh;
|
|
lpHostClut->clutPoints = (unsigned char)nGrids;
|
|
lpHostClut->inputEnt = (USHORT)nInputTable;
|
|
lpHostClut->outputEnt = (USHORT)nOutputTable;
|
|
|
|
//******** Input array
|
|
lpMem += CreateHostInputOutputArray (lpMem, lpHostClut->inputArray,
|
|
nInputCh, nInputTable, 0, Tag, Buff);
|
|
//******** the offset to the position of output array.
|
|
i = nInputTable * nInputCh +
|
|
nGrids * nGrids * nGrids * nOutputCh;
|
|
//******** Output array
|
|
lpMem += CreateHostInputOutputArray (lpMem, lpHostClut->outputArray,
|
|
nOutputCh, nOutputTable, i, Tag, Buff);
|
|
//******** Matrix.
|
|
if (PCS == icSigXYZData)
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpTable = (MEMPTR) & ((lpcpLut8Type) Buff)->lut.e00;
|
|
} else
|
|
{
|
|
lpTable = (MEMPTR) & ((lpcpLut16Type) Buff)->lut.e00;
|
|
}
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
lpHostClut->e[i] = (float)((si16f16toSFLOAT (lpTable)) / CIEXYZRange);
|
|
lpTable += sizeof (icS15Fixed16Number);
|
|
}
|
|
}
|
|
//********** RenderTable
|
|
nNumbers = nGrids * nGrids * nOutputCh;
|
|
lpHostClut->clut = lpMem;
|
|
for (i = 0; i < nGrids; i++) // Na strings should be sent
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpTable = (MEMPTR) (((lpcpLut8Type) Buff)->lut.data) +
|
|
nInputTable * nInputCh +
|
|
nNumbers * i;
|
|
} else
|
|
{
|
|
lpTable = (MEMPTR) (((lpcpLut16Type) Buff)->lut.data) +
|
|
2 * nInputTable * nInputCh +
|
|
2 * nNumbers * i;
|
|
}
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
MemCopy(lpMem, lpTable, nNumbers);
|
|
lpMem += nNumbers;
|
|
}
|
|
else
|
|
{
|
|
for (j = 0; j < nNumbers; j++)
|
|
{
|
|
*lpMem++ = (BYTE)(ui16toSINT (lpTable) / 256);
|
|
lpTable += sizeof (icUInt16Number);
|
|
}
|
|
}
|
|
}
|
|
|
|
MemFree (hMem);
|
|
return ((SINT) ((unsigned long) (lpMem - lpOldMem)));
|
|
}
|
|
|
|
|
|
/*
|
|
* GetHostColorRenderingDictionary
|
|
* function:
|
|
* this is the main function which creates the Host CRD
|
|
* parameters:
|
|
* cp -- Color Profile handle
|
|
* Intent -- Intent.
|
|
* lpMem -- Pointer to the memory block.If this point is NULL,
|
|
* require buffer size.
|
|
* lpcbSize -- size of memory block.
|
|
|
|
* returns:
|
|
* SINT -- !=0 if the function was successful,
|
|
* 0 otherwise.
|
|
* Returns number of bytes required/transferred
|
|
*/
|
|
static BOOL
|
|
GetHostColorRenderingDictionary (CHANDLE cp, DWORD Intent,
|
|
MEMPTR lpMem, LPDWORD lpcbSize)
|
|
{
|
|
SINT Index;
|
|
CSIG BToAxTag;
|
|
|
|
if (!cp)
|
|
return FALSE;
|
|
|
|
if ((lpMem == NULL) || (*lpcbSize == 0))
|
|
{
|
|
lpMem = NULL;
|
|
*lpcbSize = 0;
|
|
}
|
|
|
|
switch (Intent)
|
|
{
|
|
case icPerceptual:
|
|
BToAxTag = icSigBToA0Tag;
|
|
break;
|
|
|
|
case icRelativeColorimetric:
|
|
case icAbsoluteColorimetric:
|
|
// Use RelativeColorimetric to calculate this CRD.
|
|
BToAxTag = icSigBToA1Tag;
|
|
break;
|
|
|
|
case icSaturation:
|
|
BToAxTag = icSigBToA2Tag;
|
|
break;
|
|
|
|
default:
|
|
*lpcbSize = (DWORD) 0;
|
|
return FALSE;
|
|
}
|
|
|
|
if (DoesCPTagExist (cp, BToAxTag) &&
|
|
GetCPTagIndex (cp, BToAxTag, (LPSINT) & Index))
|
|
{
|
|
*lpcbSize = CreateHostLutCRD (cp, Index, lpMem, Intent);
|
|
}
|
|
else if(DoesTRCAndColorantTagExist(cp))
|
|
{
|
|
GetHostMatrixCSAorCRD(cp, lpMem, lpcbSize, FALSE);
|
|
}
|
|
return (*lpcbSize > 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* g
|
|
* function:
|
|
* Calculate function y = g(x). used in Lab->XYZ conversion
|
|
* y = g(x): g(x) = x*x*x if x >= 6/29
|
|
* g(x) = 108/841*(x-4/29) otherwise
|
|
* parameters:
|
|
* f -- x
|
|
* returns:
|
|
* SINT -- y
|
|
*/
|
|
|
|
static float g(float f)
|
|
{
|
|
float frc;
|
|
if (f >= (6/29))
|
|
{
|
|
frc = f * f * f;
|
|
}
|
|
else
|
|
{
|
|
frc = f - (4.0f / 29.0f) * (108.0f / 841.0f);
|
|
}
|
|
return frc;
|
|
}
|
|
|
|
/*
|
|
* inverse_g
|
|
* function:
|
|
* Calculate inverse function y = g(x). used in XYZ->Lab conversion
|
|
* parameters:
|
|
* f -- y
|
|
* returns:
|
|
* SINT -- x
|
|
*/
|
|
static float inverse_g(float f)
|
|
{
|
|
double frc;
|
|
if (f >= (6.0*6.0*6.0)/(29.0*29.0*29.0))
|
|
{
|
|
frc = pow(f, 1.0 / 3.0);
|
|
}
|
|
else
|
|
{
|
|
frc = f * (841.0 / 108.0) + (4.0 / 29.0);
|
|
}
|
|
return (float)frc;
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
|
TableInterp3(LPHOSTCLUT lpHostClut, float far *fTemp)
|
|
{
|
|
int tmpA, tmpBC;
|
|
int cellA, cellB, cellC;
|
|
float a, b, c;
|
|
short Grids;
|
|
short outputChan;
|
|
MEMPTR v000, v001, v010, v011;
|
|
MEMPTR v100, v101, v110, v111;
|
|
float vx0x, vx1x;
|
|
float v0xx, v1xx;
|
|
int idx;
|
|
|
|
cellA = (int)(fTemp[0]);
|
|
a = fTemp[0] - cellA;
|
|
|
|
cellB = (int)(fTemp[1]);
|
|
b = fTemp[1] - cellB;
|
|
|
|
cellC = (int)(fTemp[2]);
|
|
c = fTemp[2] - cellC;
|
|
|
|
Grids = lpHostClut->clutPoints;
|
|
outputChan = lpHostClut->outputChan;
|
|
tmpA = outputChan * Grids * Grids;
|
|
tmpBC = outputChan * (Grids * cellB + cellC);
|
|
|
|
// Calculate 8 surrounding cells.
|
|
v000 = lpHostClut->clut + tmpA * cellA + tmpBC;
|
|
v001 = (cellC < (Grids - 1))? v000 + outputChan : v000;
|
|
v010 = (cellB < (Grids - 1))? v000 + outputChan * Grids : v000;
|
|
v011 = (cellC < (Grids - 1))? v010 + outputChan : v010 ;
|
|
|
|
v100 = (cellA < (Grids - 1))? v000 + tmpA : v000;
|
|
v101 = (cellC < (Grids - 1))? v100 + outputChan : v100;
|
|
v110 = (cellB < (Grids - 1))? v100 + outputChan * Grids : v100;
|
|
v111 = (cellC < (Grids - 1))? v110 + outputChan : v110;
|
|
|
|
for (idx = 0; idx < outputChan; idx++)
|
|
{
|
|
// Calculate the average of 4 bottom cells.
|
|
vx0x = *v000 + c * (int)((int)*v001 - (int)*v000);
|
|
vx1x = *v010 + c * (int)((int)*v011 - (int)*v010);
|
|
v0xx = vx0x + b * (vx1x - vx0x);
|
|
|
|
// Calculate the average of 4 upper cells.
|
|
vx0x = *v100 + c * (int)((int)*v101 - (int)*v100);
|
|
vx1x = *v110 + c * (int)((int)*v111 - (int)*v110);
|
|
v1xx = vx0x + b * (vx1x - vx0x);
|
|
|
|
// Calculate the bottom and upper average.
|
|
fTemp[idx] = (v0xx + a * (v1xx - v0xx)) / MAXCOLOR8;
|
|
|
|
if ( idx < (outputChan - 1))
|
|
{
|
|
v000++;
|
|
v001++;
|
|
v010++;
|
|
v011++;
|
|
v100++;
|
|
v101++;
|
|
v110++;
|
|
v111++;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
TableInterp4(LPHOSTCLUT lpHostClut, float far *fTemp)
|
|
{
|
|
int tmpH, tmpI, tmpJK;
|
|
int cellH, cellI, cellJ, cellK;
|
|
float h, i, j, k;
|
|
short Grids;
|
|
short outputChan;
|
|
MEMPTR v0000, v0001, v0010, v0011;
|
|
MEMPTR v0100, v0101, v0110, v0111;
|
|
MEMPTR v1000, v1001, v1010, v1011;
|
|
MEMPTR v1100, v1101, v1110, v1111;
|
|
float vxx0x, vxx1x;
|
|
float vx0xx, vx1xx;
|
|
float v0xxx, v1xxx;
|
|
int idx;
|
|
|
|
cellH = (int)(fTemp[0]);
|
|
h = fTemp[0] - cellH;
|
|
|
|
cellI = (int)(fTemp[1]);
|
|
i = fTemp[1] - cellI;
|
|
|
|
cellJ = (int)(fTemp[2]);
|
|
j = fTemp[2] - cellJ;
|
|
|
|
cellK = (int)(fTemp[3]);
|
|
k = fTemp[3] - cellK;
|
|
|
|
Grids = lpHostClut->clutPoints;
|
|
outputChan = lpHostClut->outputChan;
|
|
tmpI = outputChan * Grids * Grids;
|
|
tmpH = tmpI * Grids;
|
|
tmpJK = outputChan * (Grids * cellJ + cellK);
|
|
|
|
// Calculate 16 surrounding cells.
|
|
v0000 = lpHostClut->clut + tmpH * cellH + tmpI * cellI + tmpJK;
|
|
v0001 = (cellK < (Grids - 1))? v0000 + outputChan : v0000;
|
|
v0010 = (cellJ < (Grids - 1))? v0000 + outputChan * Grids : v0000;
|
|
v0011 = (cellK < (Grids - 1))? v0010 + outputChan : v0010;
|
|
|
|
v0100 = (cellI < (Grids - 1))? v0000 + tmpI : v0000;
|
|
v0101 = (cellK < (Grids - 1))? v0100 + outputChan : v0100;
|
|
v0110 = (cellJ < (Grids - 1))? v0100 + outputChan * Grids : v0100;
|
|
v0111 = (cellK < (Grids - 1))? v0110 + outputChan : v0110;
|
|
|
|
v1000 = (cellH < (Grids - 1))? v0000 + tmpH : v0000;
|
|
v1001 = (cellK < (Grids - 1))? v1000 + outputChan : v1000;
|
|
v1010 = (cellJ < (Grids - 1))? v1000 + outputChan * Grids : v1000;
|
|
v1011 = (cellK < (Grids - 1))? v1010 + outputChan : v1010;
|
|
|
|
v1100 = (cellI < (Grids - 1))? v1000 + tmpI : v1000;
|
|
v1101 = (cellK < (Grids - 1))? v1100 + outputChan : v1100;
|
|
v1110 = (cellJ < (Grids - 1))? v1100 + outputChan * Grids : v1100;
|
|
v1111 = (cellK < (Grids - 1))? v1110 + outputChan : v1110;
|
|
|
|
for (idx = 0; idx < outputChan; idx++)
|
|
{
|
|
// Calculate the average of 8 bottom cells.
|
|
vxx0x = *v0000 + k * (int)((int)*v0001 - (int)*v0000);
|
|
vxx1x = *v0010 + k * (int)((int)*v0011 - (int)*v0010);
|
|
vx0xx = vxx0x + j * (vxx1x - vxx0x);
|
|
vxx0x = *v0100 + k * (int)((int)*v0101 - (int)*v0100);
|
|
vxx1x = *v0110 + k * (int)((int)*v0111 - (int)*v0110);
|
|
vx1xx = vxx0x + j * (vxx1x - vxx0x);
|
|
v0xxx = vx0xx + i * (vx1xx - vx0xx);
|
|
|
|
// Calculate the average of 8 upper cells.
|
|
vxx0x = *v1000 + k * (int)((int)*v1001 - (int)*v1000);
|
|
vxx1x = *v1010 + k * (int)((int)*v1011 - (int)*v1010);
|
|
vx0xx = vxx0x + j * (vxx1x - vxx0x);
|
|
vxx0x = *v1100 + k * (int)((int)*v1101 - (int)*v1100);
|
|
vxx1x = *v1110 + k * (int)((int)*v1111 - (int)*v1110);
|
|
vx1xx = vxx0x + j * (vxx1x - vxx0x);
|
|
v1xxx = vx0xx + i * (vx1xx - vx0xx);
|
|
|
|
// Calculate the bottom and upper average.
|
|
fTemp[idx] = (v0xxx + h * (v1xxx - v0xxx)) / MAXCOLOR8;
|
|
|
|
if ( idx < (outputChan - 1))
|
|
{
|
|
v0000++;
|
|
v0001++;
|
|
v0010++;
|
|
v0011++;
|
|
v0100++;
|
|
v0101++;
|
|
v0110++;
|
|
v0111++;
|
|
v1000++;
|
|
v1001++;
|
|
v1010++;
|
|
v1011++;
|
|
v1100++;
|
|
v1101++;
|
|
v1110++;
|
|
v1111++;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* CheckColorLookupTable
|
|
* function:
|
|
* This function check RenderTable.
|
|
* parameters:
|
|
* LPHOSTCLUT lpHostClut --
|
|
* float far *fTemp -- Input (in range [0 gred-1]) /
|
|
* output(in range [0 1)
|
|
* returns:
|
|
* BOOL -- TRUE
|
|
*/
|
|
|
|
static BOOL
|
|
CheckColorLookupTable(LPHOSTCLUT lpHostClut, float far *fTemp)
|
|
{
|
|
if (lpHostClut->inputChan == 3)
|
|
{
|
|
TableInterp3(lpHostClut, fTemp);
|
|
}
|
|
else if(lpHostClut->inputChan == 4)
|
|
{
|
|
TableInterp4(lpHostClut, fTemp);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* CheckInputOutputTable
|
|
* function:
|
|
* This function check inputTable.
|
|
* parameters:
|
|
* LPHOSTCLUT lpHostClut --
|
|
* float far *fTemp -- Input / output data
|
|
* returns:
|
|
* BOOL -- TRUE
|
|
*/
|
|
static BOOL
|
|
CheckInputOutputTable(LPHOSTCLUT lpHostClut, float far *fTemp,
|
|
BOOL bCSA, BOOL bInputTable)
|
|
{
|
|
int i;
|
|
short Grids;
|
|
USHORT floor1, ceiling1;
|
|
float fIndex;
|
|
int numChan;
|
|
int numEnt;
|
|
PMEMPTR ppArray;
|
|
|
|
if (bInputTable)
|
|
{
|
|
numChan = lpHostClut->inputChan;
|
|
numEnt = lpHostClut->inputEnt - 1;
|
|
ppArray = lpHostClut->inputArray;
|
|
}
|
|
else
|
|
{
|
|
numChan = lpHostClut->outputChan;
|
|
numEnt = lpHostClut->outputEnt - 1;
|
|
ppArray = lpHostClut->outputArray;
|
|
}
|
|
|
|
Grids = lpHostClut->clutPoints;
|
|
for (i = 0; (i <= MAXCHANNELS) && (i < numChan); i++)
|
|
{
|
|
fTemp[i] = (fTemp[i] < 0)? 0: ((fTemp[i] > 1)? 1: fTemp[i]);
|
|
fIndex = fTemp[i] * numEnt;
|
|
if (lpHostClut->lutBits == 8)
|
|
{
|
|
floor1 = ppArray[i][(int)fIndex];
|
|
ceiling1 = ppArray[i][((int)fIndex) + 1];
|
|
fTemp[i] = (float)(floor1 + (ceiling1 - floor1) * (fIndex - floor(fIndex)));
|
|
if (bCSA && !bInputTable)
|
|
fTemp[i] = (float)(fTemp[i] / 127.0);
|
|
else
|
|
fTemp[i] = (float)(fTemp[i] / 255.0);
|
|
}
|
|
else
|
|
{
|
|
floor1 = ((PUSHORT)(ppArray[i]))[(int)fIndex];
|
|
ceiling1 = ((PUSHORT)(ppArray[i]))[((int)fIndex) + 1];
|
|
fTemp[i] = (float)(floor1 + (ceiling1 - floor1) * (fIndex - floor(fIndex)));
|
|
if (bCSA && !bInputTable)
|
|
fTemp[i] = (float)(fTemp[i] / 32767.0);
|
|
else
|
|
fTemp[i] = (float)(fTemp[i] / 65535.0);
|
|
|
|
}
|
|
if (bInputTable)
|
|
{
|
|
fTemp[i] *= (Grids - 1);
|
|
if (fTemp[i] > (Grids - 1))
|
|
fTemp[i] = (float)(Grids - 1);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
LabToXYZ(float far *Input, float far *Output, float far *whitePoint)
|
|
{
|
|
float fL, fa, fb;
|
|
|
|
fL = (Input[0] * 50 + 16) / 116;
|
|
fa = (Input[1] * 128 - 128) / 500;
|
|
fb = (Input[2] * 128 - 128) / 200;
|
|
Output[0] = whitePoint[0] * g(fL + fa);
|
|
Output[1] = whitePoint[1] * g(fL);
|
|
Output[2] = whitePoint[2] * g(fL - fb);
|
|
}
|
|
|
|
static void
|
|
XYZToLab(float far *Input, float far *Output, float far *whitePoint)
|
|
{
|
|
float fL, fa, fb;
|
|
|
|
fL = inverse_g(Input[0] / whitePoint[0]);
|
|
fa = inverse_g(Input[1] / whitePoint[1]);
|
|
fb = inverse_g(Input[2] / whitePoint[2]);
|
|
Output[0] = (fa * 116 - 16) / 100;
|
|
Output[1] = (fL * 500 - fa * 500 + 128) / 255;
|
|
Output[2] = (fa * 200 - fb * 200 + 128) / 255;
|
|
}
|
|
|
|
static void
|
|
ApplyMatrix(PFLOAT e, float far *Input, float far *Output)
|
|
{
|
|
SINT i, j;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
j = i*3;
|
|
Output[i] = e[j ] * Input[0] +
|
|
e[j + 1] * Input[1] +
|
|
e[j + 2] * Input[2];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DoHostConversionCRD
|
|
* function:
|
|
* This function converts XYZ/Lab to RGB/CMYK by using HostCRD
|
|
* parameters:
|
|
* LPHOSTCLUT lpHostCRD -- pointer to a HostCRD
|
|
* LPHOSTCLUT lpHostCSA -- pointer to a HostCSA
|
|
* float far *Input -- Input XYZ/Lab
|
|
* float far *Output -- Output RGB/CMYK
|
|
* returns:
|
|
* BOOL -- TRUE
|
|
*/
|
|
static BOOL
|
|
DoHostConversionCRD (LPHOSTCLUT lpHostCRD, LPHOSTCLUT lpHostCSA,
|
|
float far *Input, float far *Output,
|
|
CSIG ColorSpace, BOOL bCheckOutputTable)
|
|
{
|
|
float fTemp[MAXCHANNELS];
|
|
float fTemp1[MAXCHANNELS];
|
|
int i;
|
|
|
|
/*
|
|
** Input XYZ or Lab in range [0 2]
|
|
*/
|
|
// When sampling the deviceCRD, skip the input table.
|
|
// If lpHostCSA is not NULL, the current CRD is targetCRD, we
|
|
// need to do input table conversion
|
|
if (lpHostCSA)
|
|
{
|
|
// Convert Lab to XYZ in range [ 0 whitePoint ]
|
|
if ((lpHostCRD->pcs == icSigXYZData) &&
|
|
(lpHostCSA->pcs == icSigLabData))
|
|
{
|
|
LabToXYZ(Input, fTemp1, lpHostCRD->whitePoint);
|
|
}
|
|
// Convert XYZ to Lab in range [ 0 1]
|
|
else if ((lpHostCRD->pcs == icSigLabData) &&
|
|
(lpHostCSA->pcs == icSigXYZData))
|
|
{
|
|
XYZToLab(Input, fTemp, lpHostCSA->whitePoint);
|
|
}
|
|
// Convert Lab to range [ 0 1]
|
|
else if ((lpHostCRD->pcs == icSigLabData) &&
|
|
(lpHostCSA->pcs == icSigLabData))
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
fTemp[i] = Input[i] / 2;
|
|
}
|
|
// Convert XYZ to XYZ (based on white point) to range [0 1]
|
|
else
|
|
{ // TODO: different intents using different conversion.
|
|
// icRelativeColorimetric: using Bradford transform.
|
|
// icAbsoluteColorimetric: using scaling.
|
|
for (i = 0; i < 3; i++)
|
|
fTemp1[i] = Input[i] * lpHostCRD->whitePoint[i] / lpHostCSA->whitePoint[i];
|
|
}
|
|
|
|
// Matrix, used for XYZ data only or Matrix icc profile only
|
|
if (lpHostCRD->pcs == icSigXYZData)
|
|
{
|
|
ApplyMatrix(lpHostCRD->e, fTemp1, fTemp);
|
|
}
|
|
|
|
if (lpHostCRD->dataType != DATA_matrix)
|
|
{
|
|
//Search input Table
|
|
CheckInputOutputTable(lpHostCRD, fTemp, 0, 1);
|
|
}
|
|
}
|
|
// If the current CRD is device CRD, we do not need to do input
|
|
// table conversion.
|
|
else
|
|
{
|
|
short Grids;
|
|
Grids = lpHostCRD->clutPoints;
|
|
// Sample data may be XYZ or Lab. It depends on Target icc profile.
|
|
// If the PCS of the target icc profile is XYZ, input data will be XYZ.
|
|
// If the PCS of the target icc profile is Lab, input data will be Lab.
|
|
|
|
if (lpHostCRD->dataType == DATA_matrix)
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
fTemp[i] = Input[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
fTemp[i] = Input[i]* (Grids - 1);
|
|
if (fTemp[i] > (Grids - 1))
|
|
fTemp[i] = (float)(Grids - 1);
|
|
}
|
|
}
|
|
} // bCheckInputTable
|
|
|
|
if (lpHostCRD->dataType != DATA_matrix)
|
|
{
|
|
// Rendering table
|
|
CheckColorLookupTable(lpHostCRD, fTemp);
|
|
|
|
/*
|
|
** Output RGB or CMYK in range [0 1]
|
|
*/
|
|
}
|
|
if (bCheckOutputTable)
|
|
{
|
|
//Output Table
|
|
CheckInputOutputTable(lpHostCRD, fTemp, 0, 0);
|
|
}
|
|
for (i = 0; (i <= MAXCHANNELS) && (i < lpHostCRD->outputChan); i++)
|
|
{
|
|
Output[i] = fTemp[i];
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* DoHostConversionCSA
|
|
* function:
|
|
* This function converts RGB/CMYK to XYZ/Lab by using HostCSA
|
|
* parameters:
|
|
* LPHOSTCLUT lpHostCLUT -- pointer to a HostCSA
|
|
* float far *Input -- Input XYZ/Lab
|
|
* float far *Output -- Output RGB/CMYK
|
|
* returns:
|
|
* BOOL -- TRUE
|
|
*/
|
|
|
|
static BOOL
|
|
DoHostConversionCSA (LPHOSTCLUT lpHostClut, float far *Input, float far *Output)
|
|
{
|
|
float fTemp[MAXCHANNELS];
|
|
int i;
|
|
|
|
/*
|
|
** Input RGB or CMYK in range [0 1]
|
|
*/
|
|
for (i = 0; (i <= MAXCHANNELS) && (i < lpHostClut->inputChan); i++)
|
|
{
|
|
fTemp[i] = Input[i];
|
|
}
|
|
|
|
if (lpHostClut->dataType == DATA_matrix)
|
|
{
|
|
//Search input Table
|
|
CheckInputOutputTable(lpHostClut, fTemp, 1, 1);
|
|
ApplyMatrix(lpHostClut->e, fTemp, Output);
|
|
}
|
|
else
|
|
{
|
|
//Search input Table
|
|
CheckInputOutputTable(lpHostClut, fTemp, 1, 1);
|
|
|
|
// Rendering table
|
|
CheckColorLookupTable(lpHostClut, fTemp);
|
|
|
|
//Output Table
|
|
CheckInputOutputTable(lpHostClut, fTemp, 1, 0 );
|
|
|
|
/*
|
|
** Output XYZ or Lab in range [0 2]
|
|
*/
|
|
for (i = 0; (i <= MAXCHANNELS) && (i < lpHostClut->outputChan); i++)
|
|
{
|
|
Output[i] = fTemp[i];
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
GetCRDInputOutputArraySize(CHANDLE cp, DWORD Intent,
|
|
LPSINT lpInTbSize, LPSINT lpOutTbSize,
|
|
LPCSIG lpIntentTag, LPSINT lpGrids)
|
|
{
|
|
CSIG Tag;
|
|
SINT Index;
|
|
SINT Ret = 0;
|
|
MEMPTR Buff = NULL;
|
|
SINT MemSize = 0;
|
|
HGLOBAL hMem;
|
|
SINT outputChan, outputEnt;
|
|
SINT inputChan, inputEnt;
|
|
SINT Grids;
|
|
SINT i;
|
|
|
|
switch (Intent)
|
|
{
|
|
case icPerceptual:
|
|
*lpIntentTag = icSigBToA0Tag;
|
|
break;
|
|
|
|
case icRelativeColorimetric:
|
|
case icAbsoluteColorimetric:
|
|
*lpIntentTag = icSigBToA1Tag;
|
|
break;
|
|
|
|
case icSaturation:
|
|
*lpIntentTag = icSigBToA2Tag;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
if (!DoesCPTagExist (cp, *lpIntentTag) ||
|
|
!GetCPTagIndex (cp, *lpIntentTag, (LPSINT) & Index) ||
|
|
!GetCPElementType (cp, Index, (LPCSIG) & Tag) ||
|
|
((Tag != icSigLut8Type) && (Tag != icSigLut16Type)) ||
|
|
!GetCPElementSize (cp, Index, (LPSINT) & MemSize) ||
|
|
!MemAlloc (MemSize, (HGLOBAL FAR *)&hMem, (LPMEMPTR) & Buff) ||
|
|
!GetCPElement (cp, Index, Buff, MemSize))
|
|
{
|
|
BOOL retVal = FALSE;
|
|
|
|
if (NULL != Buff)
|
|
{
|
|
MemFree (hMem);
|
|
}
|
|
|
|
// Matrix icc profile.
|
|
|
|
*lpGrids = 2;
|
|
if (lpInTbSize)
|
|
{
|
|
retVal = GetHostCSA_Intent (cp, NULL, lpInTbSize,
|
|
(CSIG) Intent, TYPE_CIEBASEDDEF);
|
|
*lpInTbSize = *lpInTbSize * 3;
|
|
}
|
|
if (lpOutTbSize)
|
|
{
|
|
retVal = GetHostCSA_Intent (cp, NULL, lpOutTbSize,
|
|
(CSIG) Intent, TYPE_CIEBASEDDEF);
|
|
*lpOutTbSize = *lpOutTbSize * 3;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
if (lpInTbSize)
|
|
{
|
|
GetCLUTinfo(Tag, Buff, &inputChan, &outputChan,
|
|
&Grids, &inputEnt, &outputEnt, &i);
|
|
|
|
if (inputChan != 3)
|
|
{
|
|
MemFree (hMem);
|
|
return FALSE;
|
|
}
|
|
|
|
*lpInTbSize = inputChan * inputEnt * 6; // Number of INT bytes
|
|
*lpGrids = Grids;
|
|
}
|
|
|
|
if (lpOutTbSize)
|
|
{
|
|
GetCLUTinfo(Tag, Buff, &inputChan, &outputChan,
|
|
&Grids, &inputEnt, &outputEnt, &i);
|
|
|
|
if ((outputChan != 3) && (outputChan != 4))
|
|
{
|
|
MemFree (hMem);
|
|
return FALSE;
|
|
}
|
|
*lpOutTbSize = outputChan * outputEnt * 6; // Number of INT bytes
|
|
*lpGrids = Grids;
|
|
}
|
|
|
|
MemFree (hMem);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* CreateOutputArray
|
|
* function:
|
|
* Create CSA/CRD output arrays from the data supplied in icc profile's
|
|
* LUT8 or LUT16 tags.
|
|
* parameters:
|
|
* MEMPTR lpMem -- a pointer to a buffer which will contain the arrays.
|
|
* SINT nOutputCh -- Number of output channel. if lpHostClut, no meaning.
|
|
* SINT nOutputTable -- saze of each array. if lpHostClut, no meaning.
|
|
* SINT Offset -- offset of Buff, point to the 1st byte of output array in CLUT.
|
|
* if lpHostClut, no meaning.
|
|
* MEMPTR Intent --
|
|
* CSIG Tag -- LUT8 or LUT16
|
|
* MEMPTR Buff -- point to a buffer which contain LUT8 or LUT16.
|
|
* if NULL, use lpHostClut.
|
|
* BOOL AllowBinary --
|
|
* MEMPTR lpHostClut -- point to host CSA/CRD. if NULL, use Buff.
|
|
* returns:
|
|
* SINT -- The size of output array created.
|
|
*/
|
|
|
|
SINT
|
|
CreateOutputArray (MEMPTR lpMem, SINT nOutputCh,
|
|
SINT nOutputTable, SINT Offset, MEMPTR Intent,
|
|
CSIG Tag, MEMPTR Buff, BOOL AllowBinary, MEMPTR lpHostClut)
|
|
{
|
|
SINT i, j;
|
|
MEMPTR lpOldMem;
|
|
MEMPTR lpTable;
|
|
MEMPTR lpLineStart;
|
|
lpOldMem = lpMem;
|
|
|
|
if (lpHostClut)
|
|
{
|
|
nOutputCh = (SINT)(((LPHOSTCLUT)lpHostClut)->outputChan);
|
|
nOutputTable = (SINT)(((LPHOSTCLUT)lpHostClut)->outputEnt);
|
|
Tag = (((LPHOSTCLUT)lpHostClut)->lutBits == 8)?
|
|
icSigLut8Type : icSigLut16Type;
|
|
}
|
|
|
|
for (i = 0; i < nOutputCh; i++)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteNewLineObject (lpMem, Slash);
|
|
if (lpHostClut)
|
|
lpMem += WriteObject (lpMem, PreViewOutArray);
|
|
else
|
|
lpMem += WriteObject (lpMem, OutputArray);
|
|
lpMem += WriteObjectN (lpMem, Intent, lstrlen (Intent));
|
|
lpMem += WriteInt (lpMem, i);
|
|
|
|
if (lpHostClut)
|
|
lpTable = ((LPHOSTCLUT)lpHostClut)->outputArray[i];
|
|
else
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
lpTable = (MEMPTR) (((lpcpLut8Type) Buff)->lut.data) +
|
|
Offset +
|
|
nOutputTable * i;
|
|
else
|
|
lpTable = (MEMPTR) (((lpcpLut16Type) Buff)->lut.data) +
|
|
2 * Offset +
|
|
2 * nOutputTable * i;
|
|
}
|
|
|
|
if (!AllowBinary) // Output ASCII CRD
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginString);
|
|
lpMem += WriteHexBuffer (lpMem, lpTable, lpLineStart, nOutputTable);
|
|
lpMem += WriteObject (lpMem, EndString);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (j = 0; j < nOutputTable; j++)
|
|
{
|
|
if (lpHostClut)
|
|
lpMem += WriteInt (lpMem, *((PUSHORT)lpTable));
|
|
else
|
|
lpMem += WriteInt (lpMem, ui16toSINT (lpTable));
|
|
lpTable += sizeof (icUInt16Number);
|
|
if (((SINT) (lpMem - lpLineStart)) > MAX_LINELENG)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteObject (lpMem, NewLine);
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
}
|
|
} else
|
|
{ // Output BINARY CRD
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteStringToken (lpMem, 143, 256);
|
|
lpMem += WriteByteString (lpMem, lpTable, 256L);
|
|
} else
|
|
{
|
|
lpMem += WriteHNAToken (lpMem, 149, nOutputTable);
|
|
if (lpHostClut)
|
|
lpMem += WriteIntStringU2S_L (lpMem, lpTable, nOutputTable);
|
|
else
|
|
lpMem += WriteIntStringU2S (lpMem, lpTable, nOutputTable);
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, DefOp);
|
|
}
|
|
|
|
return ((SINT) (lpMem - lpOldMem));
|
|
}
|
|
|
|
/*
|
|
* CreateInputArray
|
|
* function:
|
|
* Create CSA/CRD Input arrays from the data supplied in icc profile's
|
|
* LUT8 or LUT16 tags.
|
|
* parameters:
|
|
* MEMPTR lpMem -- a pointer to the buffer which will contain the arrays.
|
|
* SINT nInputCh -- Number of input channel. if lpHostClut, no meaning.
|
|
* SINT nInputTable -- saze of each array. if lpHostClut, no meaning.
|
|
* SINT Offset -- offset of Buff, point to the 1st byte of output array in CLUT.
|
|
* if lpHostClut, no meaning.
|
|
* MEMPTR Intent --
|
|
* CSIG Tag -- LUT8 or LUT16
|
|
* MEMPTR Buff -- point to a buffer which contains LUT8 or LUT16.
|
|
* if NULL, use lpHostClut.
|
|
* BOOL AllowBinary --
|
|
* MEMPTR lpHostClut -- point to host CSA/CRD. if NULL, use Buff.
|
|
* returns:
|
|
* SINT -- The size of inpput array created.
|
|
*/
|
|
|
|
SINT
|
|
CreateInputArray (MEMPTR lpMem, SINT nInputCh,
|
|
SINT nInputTable, MEMPTR Intent, CSIG Tag,
|
|
MEMPTR Buff, BOOL bAllowBinary, MEMPTR lpHostClut)
|
|
{
|
|
SINT i, j;
|
|
MEMPTR lpOldMem;
|
|
MEMPTR lpTable;
|
|
MEMPTR lpLineStart;
|
|
lpOldMem = lpMem;
|
|
|
|
if (lpHostClut)
|
|
{
|
|
nInputCh = (SINT)(((LPHOSTCLUT)lpHostClut)->inputChan);
|
|
nInputTable = (SINT)(((LPHOSTCLUT)lpHostClut)->inputEnt);
|
|
Tag = (((LPHOSTCLUT)lpHostClut)->lutBits == 8)?
|
|
icSigLut8Type : icSigLut16Type;
|
|
}
|
|
|
|
for (i = 0; i < nInputCh; i++)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteNewLineObject (lpMem, Slash);
|
|
if (lpHostClut)
|
|
lpMem += WriteObject (lpMem, PreViewInArray);
|
|
else
|
|
lpMem += WriteObject (lpMem, InputArray);
|
|
lpMem += WriteObjectN (lpMem, Intent, lstrlen (Intent));
|
|
lpMem += WriteInt (lpMem, i);
|
|
|
|
if (lpHostClut)
|
|
{
|
|
lpTable = ((LPHOSTCLUT)lpHostClut)->inputArray[i];
|
|
}
|
|
else
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
lpTable = (MEMPTR) (((lpcpLut8Type) Buff)->lut.data) + nInputTable * i;
|
|
else
|
|
lpTable = (MEMPTR) (((lpcpLut16Type) Buff)->lut.data) + 2 * nInputTable * i;
|
|
}
|
|
if (!bAllowBinary) // Output ASCII CRD
|
|
{
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginString);
|
|
lpMem += WriteHexBuffer (lpMem, lpTable,lpLineStart, nInputTable);
|
|
lpMem += WriteObject (lpMem, EndString);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (j = 0; j < nInputTable; j++)
|
|
{
|
|
if(lpHostClut)
|
|
lpMem += WriteInt (lpMem, *((PUSHORT)lpTable));
|
|
else
|
|
lpMem += WriteInt (lpMem, ui16toSINT (lpTable));
|
|
lpTable += sizeof (icUInt16Number);
|
|
if (((SINT) (lpMem - lpLineStart)) > MAX_LINELENG)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteObject (lpMem, NewLine);
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
}
|
|
} else
|
|
{ // Output BINARY CRD
|
|
if (Tag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteStringToken (lpMem, 143, 256);
|
|
lpMem += WriteByteString (lpMem, lpTable, 256L);
|
|
} else
|
|
{
|
|
lpMem += WriteHNAToken (lpMem, 149, nInputTable);
|
|
if (lpHostClut)
|
|
lpMem += WriteIntStringU2S_L (lpMem, lpTable, nInputTable);
|
|
else
|
|
lpMem += WriteIntStringU2S (lpMem, lpTable, nInputTable);
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, DefOp);
|
|
}
|
|
|
|
return ((SINT) (lpMem - lpOldMem));
|
|
}
|
|
|
|
SINT
|
|
SendCRDLMN(MEMPTR lpMem, CSIG Intent, LPSFLOAT whitePoint, LPSFLOAT mediaWP, CSIG pcs)
|
|
{
|
|
MEMPTR lpOldMem;
|
|
SINT i, j;
|
|
|
|
lpOldMem = lpMem;
|
|
|
|
//********** /MatrixLMN
|
|
if (icAbsoluteColorimetric == Intent)
|
|
{
|
|
lpMem += WriteNewLineObject (lpMem, MatrixLMNTag);
|
|
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
for (j = 0; j < 3; j++)
|
|
lpMem += WriteFloat (lpMem,
|
|
(double) (i == j) ? whitePoint[i] / mediaWP[i] : 0.0);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
}
|
|
//********** /RangeLMN
|
|
lpMem += WriteNewLineObject (lpMem, RangeLMNTag);
|
|
if (pcs == icSigXYZData)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lpMem += WriteFloat (lpMem, (double) 0);
|
|
lpMem += WriteFloat (lpMem, (double) whitePoint[i]);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, RangeLMNLab);
|
|
}
|
|
|
|
//********** /EncodeLMN
|
|
lpMem += WriteNewLineObject (lpMem, EncodeLMNTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginFunction);
|
|
if (pcs != icSigXYZData)
|
|
{
|
|
lpMem += WriteFloat (lpMem, (double)whitePoint[i]);
|
|
lpMem += WriteObject (lpMem, DivOp);
|
|
lpMem += WriteObject (lpMem, EncodeLMNLab);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndFunction);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
|
|
return (SINT)(lpMem - lpOldMem);
|
|
}
|
|
|
|
|
|
SINT
|
|
SendCRDPQR(MEMPTR lpMem, CSIG Intent, LPSFLOAT whitePoint)
|
|
{
|
|
MEMPTR lpOldMem;
|
|
SINT i;
|
|
|
|
lpOldMem = lpMem;
|
|
|
|
if (icAbsoluteColorimetric != Intent)
|
|
{
|
|
//********** /RangePQR
|
|
lpMem += WriteNewLineObject (lpMem, RangePQRTag);
|
|
lpMem += WriteObject (lpMem, RangePQR);
|
|
|
|
//********** /MatrixPQR
|
|
lpMem += WriteNewLineObject (lpMem, MatrixPQRTag);
|
|
lpMem += WriteObject (lpMem, MatrixPQR);
|
|
}
|
|
else
|
|
{
|
|
//********** /RangePQR
|
|
lpMem += WriteNewLineObject (lpMem, RangePQRTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lpMem += WriteFloat (lpMem, (double) 0);
|
|
lpMem += WriteFloat (lpMem, (double)(whitePoint[i]));
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
//********** /MatrixPQR
|
|
lpMem += WriteNewLineObject (lpMem, MatrixPQRTag);
|
|
lpMem += WriteObject (lpMem, Identity);
|
|
}
|
|
//********** /TransformPQR
|
|
lpMem += WriteNewLineObject (lpMem, TransformPQRTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginFunction);
|
|
lpMem += WriteObject (lpMem,
|
|
(icAbsoluteColorimetric != Intent) ? TransformPQR[i] : NullOp);
|
|
lpMem += WriteObject (lpMem, EndFunction);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
|
|
return (SINT)(lpMem - lpOldMem);
|
|
}
|
|
|
|
SINT
|
|
SendCRDABC(MEMPTR lpMem, MEMPTR PublicArrayName, CSIG pcs, SINT nInputCh,
|
|
MEMPTR Buff, LPSFLOAT e, CSIG LutTag, BOOL bAllowBinary)
|
|
{
|
|
MEMPTR lpOldMem;
|
|
SINT i, j;
|
|
double TempMatrixABC[9];
|
|
MEMPTR lpTable;
|
|
MEMPTR lpLineStart;
|
|
lpOldMem = lpMem;
|
|
|
|
//********** /RangeABC
|
|
lpMem += WriteNewLineObject (lpMem, RangeABCTag);
|
|
lpMem += WriteObject (lpMem, RangeABC);
|
|
//********** /MatrixABC
|
|
lpMem += WriteNewLineObject (lpMem, MatrixABCTag);
|
|
if (pcs == icSigXYZData)
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
if (e)
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
lpMem += WriteFloat (lpMem, e[i + j * 3]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
lpTable = (MEMPTR) & ((lpcpLut8Type) Buff)->lut.e00;
|
|
} else
|
|
{
|
|
lpTable = (MEMPTR) & ((lpcpLut16Type) Buff)->lut.e00;
|
|
}
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
TempMatrixABC[i] = ((double) si16f16toSFLOAT (lpTable)) / CIEXYZRange;
|
|
lpTable += sizeof (icS15Fixed16Number);
|
|
}
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
lpMem += WriteFloat (lpMem, TempMatrixABC[i + j * 3]);
|
|
}
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, MatrixABCLabCRD);
|
|
}
|
|
//********** /EncodeABC
|
|
if (nInputCh == 0)
|
|
return (SINT)(lpMem - lpOldMem);
|
|
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteNewLineObject (lpMem, EncodeABCTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < nInputCh; i++)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteNewLineObject (lpMem, BeginFunction);
|
|
if (pcs == icSigLabData)
|
|
{
|
|
lpMem += WriteObject (lpMem,
|
|
(0 == i) ? EncodeABCLab1 : EncodeABCLab2);
|
|
}
|
|
lpMem += WriteObject (lpMem, StartClip);
|
|
if (e)
|
|
lpMem += WriteObject (lpMem, PreViewInArray);
|
|
else
|
|
lpMem += WriteObject (lpMem, InputArray);
|
|
lpMem += WriteObjectN (lpMem, (MEMPTR) PublicArrayName, lstrlen (PublicArrayName));
|
|
lpMem += WriteInt (lpMem, i);
|
|
|
|
if (!bAllowBinary) // Output ASCII CRD
|
|
{
|
|
lpMem += WriteNewLineObject (lpMem, IndexArray);
|
|
} else
|
|
{ // Output BINARY CRD
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteObject (lpMem, IndexArray);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, IndexArray16b);
|
|
}
|
|
}
|
|
lpMem += WriteObject (lpMem, (LutTag == icSigLut8Type) ?
|
|
Scale8 : Scale16);
|
|
lpMem += WriteObject (lpMem, EndClip);
|
|
lpMem += WriteObject (lpMem, EndFunction);
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
return (SINT)(lpMem - lpOldMem);
|
|
}
|
|
|
|
SINT
|
|
SendCRDBWPoint(MEMPTR lpMem, LPSFLOAT whitePoint)
|
|
{
|
|
MEMPTR lpOldMem;
|
|
SINT i;
|
|
|
|
lpOldMem = lpMem;
|
|
|
|
//********** /BlackPoint
|
|
lpMem += WriteNewLineObject (lpMem, BlackPointTag);
|
|
lpMem += WriteObject (lpMem, BlackPoint);
|
|
|
|
//********** /WhitePoint
|
|
lpMem += WriteNewLineObject (lpMem, WhitePointTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
lpMem += WriteFloat (lpMem, (double)(whitePoint[i]));
|
|
}
|
|
lpMem += WriteObject (lpMem, EndArray);
|
|
return (SINT)(lpMem - lpOldMem);
|
|
}
|
|
|
|
SINT SendCRDOutputTable(MEMPTR lpMem, MEMPTR PublicArrayName,
|
|
SINT nOutputCh, CSIG LutTag, BOOL bHost, BOOL bAllowBinary)
|
|
{
|
|
MEMPTR lpOldMem;
|
|
SINT i;
|
|
|
|
lpOldMem = lpMem;
|
|
|
|
for (i = 0; i < nOutputCh; i++)
|
|
{
|
|
lpMem += WriteNewLineObject (lpMem, BeginFunction);
|
|
lpMem += WriteObject (lpMem, Clip01);
|
|
if (bHost)
|
|
lpMem += WriteObject (lpMem, PreViewOutArray);
|
|
else
|
|
lpMem += WriteObject (lpMem, OutputArray);
|
|
lpMem += WriteObjectN (lpMem, (MEMPTR) PublicArrayName, lstrlen (PublicArrayName));
|
|
lpMem += WriteInt (lpMem, i);
|
|
|
|
if (!bAllowBinary) // Output ASCII CRD
|
|
{
|
|
lpMem += WriteObject (lpMem, NewLine);
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteObject (lpMem, TFunction8);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, IndexArray);
|
|
lpMem += WriteObject (lpMem, Scale16);
|
|
}
|
|
} else
|
|
{ // Output BINARY CRD
|
|
if (LutTag == icSigLut8Type)
|
|
{
|
|
lpMem += WriteObject (lpMem, TFunction8);
|
|
} else
|
|
{
|
|
lpMem += WriteObject (lpMem, IndexArray16b);
|
|
lpMem += WriteObject (lpMem, Scale16);
|
|
}
|
|
}
|
|
|
|
lpMem += WriteObject (lpMem, EndFunction);
|
|
}
|
|
return (SINT)(lpMem - lpOldMem);
|
|
}
|
|
|
|
|
|
/*
|
|
* GetPS2PreviewColorRenderingDictionary
|
|
* function:
|
|
* This is the main function that creates proofing CRD.
|
|
* It does the following:
|
|
* 1) Creates host TargetCRD, TargetCSA and DevCRD.
|
|
* 2) Create proofing CRD by sampling TargetCRD TargetCSA and DevCRD.
|
|
* 3) Uses TargetCRD's input table as proofingCRD's input table.
|
|
* 4) Uses DevCRD's output table as proofingCRD's output table.
|
|
* 5) Sample data is XYZ or Lab, depends on PCS of TargetCRD.
|
|
|
|
* parameters:
|
|
* CHANDLE cpDev -- handle to Target icc profile.
|
|
* CHANDLE cpTarget -- handle to Dev icc profile.
|
|
* DWORD Intent -- intent
|
|
* MEMPTR lpMem -- pointer to buffer for proofCRD,
|
|
* NULL means query buffer size.
|
|
* LPDWORD lpcbSize -- as input: current buffer size
|
|
* -- as output: real proofCRD size.
|
|
* BOOL bAllowBinary -- create a ascii or binary proofCRD.
|
|
|
|
* returns:
|
|
* BOOL -- TRUE/FALSE
|
|
*/
|
|
|
|
BOOL EXTERN
|
|
GetPS2PreviewColorRenderingDictionary (CHANDLE cpDev,
|
|
CHANDLE cpTarget,
|
|
DWORD Intent,
|
|
MEMPTR lpMem,
|
|
LPDWORD lpcbSize,
|
|
BOOL bAllowBinary)
|
|
{
|
|
MEMPTR lpTargetCRD, lpTargetCSA, lpDevCRD;
|
|
DWORD cbTargetCRD, cbTargetCSA, cbDevCRD;
|
|
HGLOBAL hTargetCRD, hTargetCSA, hDevCRD;
|
|
BOOL Success = FALSE;
|
|
float Input[MAXCHANNELS];
|
|
float Output[MAXCHANNELS];
|
|
float Temp[MAXCHANNELS];
|
|
int i, j, k, l;
|
|
MEMPTR lpLineStart;
|
|
MEMPTR lpOldMem;
|
|
CSIG ColorSpace;
|
|
CSIG DevColorSpace;
|
|
static CSIG IntentTag;
|
|
static SINT PreviewCRDGrid;
|
|
SINT OutArraySize, InArraySize;
|
|
char PublicArrayName[TempBfSize];
|
|
SINT TargetGrids, DevGrids;
|
|
|
|
// First pass, return the size of Previewind CRD.
|
|
if (lpMem == NULL)
|
|
{
|
|
SINT dwOutArraySizr = 0;
|
|
|
|
i = 3; // Default output channal;
|
|
if ((GetCPDevSpace (cpDev, (LPCSIG) & DevColorSpace)) &&
|
|
(DevColorSpace == icSigCmykData))
|
|
{
|
|
i = 4;
|
|
}
|
|
|
|
// Get the input array size IntentTag and Grid of the Target icc profile.
|
|
if (!GetCRDInputOutputArraySize(cpTarget, Intent,
|
|
&InArraySize, NULL, &IntentTag, &TargetGrids ))
|
|
return FALSE;
|
|
|
|
// Get the output array size IntentTag and Grid of the Dev icc profile.
|
|
if (!GetCRDInputOutputArraySize(cpDev, Intent,
|
|
NULL, &OutArraySize, &IntentTag, &DevGrids ))
|
|
return FALSE;
|
|
|
|
PreviewCRDGrid = (TargetGrids > DevGrids)? TargetGrids: DevGrids;
|
|
|
|
// Min proofing CRD grid will be PREVIEWCRDGRID
|
|
if (PreviewCRDGrid < PREVIEWCRDGRID)
|
|
PreviewCRDGrid = PREVIEWCRDGRID;
|
|
*lpcbSize = PreviewCRDGrid * PreviewCRDGrid * PreviewCRDGrid *
|
|
i * 2 + // CLUT size (Hex output)
|
|
OutArraySize + // Output Array size
|
|
InArraySize + // Input Array size
|
|
4096; // Extra PostScript staff.
|
|
return (TRUE);
|
|
}
|
|
|
|
// Second pass, return the Previewind CRD.
|
|
lpOldMem = lpMem;
|
|
|
|
//Query the sizes of Host TargetCRD, TargetCSA and DevCRD.
|
|
if (!(GetHostColorRenderingDictionary (cpTarget, Intent, NULL, &cbTargetCRD)) ||
|
|
!(GetHostColorSpaceArray (cpTarget, Intent, NULL, &cbTargetCSA)) ||
|
|
!(GetHostColorRenderingDictionary (cpDev, Intent, NULL, &cbDevCRD)))
|
|
{
|
|
return (Success);
|
|
}
|
|
|
|
//Alloc the buffers for Host TargetCRD, TargetCSA and DevCRD.
|
|
hTargetCRD = hTargetCSA = hDevCRD = 0;
|
|
if (!MemAlloc (cbTargetCRD, (HGLOBAL FAR *)&hTargetCRD, (LPMEMPTR)&lpTargetCRD) ||
|
|
!MemAlloc (cbTargetCSA, (HGLOBAL FAR *)&hTargetCSA, (LPMEMPTR)&lpTargetCSA) ||
|
|
!MemAlloc (cbDevCRD, (HGLOBAL FAR *)&hDevCRD, (LPMEMPTR)&lpDevCRD))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//Build Host TargetCRD, TargetCSA and DevCRD.
|
|
if (!(GetHostColorRenderingDictionary (cpTarget, Intent, lpTargetCRD, &cbTargetCRD)) ||
|
|
!(GetHostColorSpaceArray (cpTarget, Intent, lpTargetCSA, &cbTargetCSA)) ||
|
|
!(GetHostColorRenderingDictionary (cpDev, Intent, lpDevCRD, &cbDevCRD)))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
// Build Proofing CRD based on Host TargetCRD TargetCSA and DevCRD.
|
|
// We use TargetCRD input tables and matrix as the
|
|
// input tables and matrix of the ProofCRD.
|
|
// We use DevCRD output tables as the output tables of the ProofCRD.
|
|
|
|
//******** Define golbal array used in EncodeABC and RenderTaber
|
|
GetPublicArrayName (cpDev, IntentTag, PublicArrayName);
|
|
lpMem += WriteNewLineObject (lpMem, CRDBegin);
|
|
|
|
lpMem += EnableGlobalDict(lpMem);
|
|
lpMem += BeginGlobalDict(lpMem);
|
|
|
|
lpMem += CreateInputArray (lpMem, (SINT)0, (SINT)0, (MEMPTR)PublicArrayName,
|
|
(CSIG)0, NULL, bAllowBinary, lpTargetCRD);
|
|
|
|
lpMem += CreateOutputArray (lpMem, (SINT)0, (SINT)0, (SINT)0,
|
|
(MEMPTR)PublicArrayName, (CSIG)0, NULL, bAllowBinary, lpDevCRD);
|
|
|
|
lpMem += EndGlobalDict(lpMem);
|
|
|
|
//************* Start writing CRD ***
|
|
lpMem += WriteNewLineObject (lpMem, BeginDict); // Begin dictionary
|
|
lpMem += WriteObject (lpMem, DictType); // Dictionary type
|
|
|
|
lpMem += WriteNewLineObject (lpMem, IntentType); // RenderingIntent
|
|
switch (Intent)
|
|
{
|
|
case icPerceptual:
|
|
lpMem += WriteObject (lpMem, IntentPer);
|
|
break;
|
|
|
|
case icSaturation:
|
|
lpMem += WriteObject (lpMem, IntentSat);
|
|
break;
|
|
|
|
case icRelativeColorimetric:
|
|
lpMem += WriteObject (lpMem, IntentRCol);
|
|
break;
|
|
|
|
case icAbsoluteColorimetric:
|
|
lpMem += WriteObject (lpMem, IntentACol);
|
|
break;
|
|
}
|
|
|
|
//********** Send Black/White Point.
|
|
lpMem += SendCRDBWPoint(lpMem,
|
|
((LPHOSTCLUT)lpTargetCRD)->whitePoint);
|
|
|
|
//********** Send PQR - For White Point correction
|
|
lpMem += SendCRDPQR(lpMem, Intent,
|
|
((LPHOSTCLUT)lpTargetCRD)->whitePoint);
|
|
|
|
//********** Send LMN - For Absolute Colorimetric use WhitePoint's XYZs
|
|
lpMem += SendCRDLMN(lpMem, Intent,
|
|
((LPHOSTCLUT)lpTargetCRD)->whitePoint,
|
|
((LPHOSTCLUT)lpTargetCRD)->mediaWP,
|
|
((LPHOSTCLUT)lpTargetCRD)->pcs);
|
|
|
|
//********** Create MatrixABC and EncodeABC stuff
|
|
lpMem += SendCRDABC(lpMem, PublicArrayName,
|
|
((LPHOSTCLUT)lpTargetCRD)->pcs,
|
|
((LPHOSTCLUT)lpTargetCRD)->inputChan,
|
|
NULL,
|
|
((LPHOSTCLUT)lpTargetCRD)->e,
|
|
(((LPHOSTCLUT)lpTargetCRD)->lutBits == 8)? icSigLut8Type:icSigLut16Type,
|
|
bAllowBinary);
|
|
|
|
//********** /RenderTable
|
|
lpMem += WriteNewLineObject (lpMem, RenderTableTag);
|
|
lpMem += WriteObject (lpMem, BeginArray);
|
|
|
|
lpMem += WriteInt (lpMem, PreviewCRDGrid); // Send down Na
|
|
lpMem += WriteInt (lpMem, PreviewCRDGrid); // Send down Nb
|
|
lpMem += WriteInt (lpMem, PreviewCRDGrid); // Send down Nc
|
|
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteNewLineObject (lpMem, BeginArray);
|
|
ColorSpace = ((LPHOSTCLUT)lpDevCRD)->pcs;
|
|
for (i = 0; i < PreviewCRDGrid; i++) // Na strings should be sent
|
|
{
|
|
lpMem += WriteObject (lpMem, NewLine);
|
|
lpLineStart = lpMem;
|
|
if (bAllowBinary)
|
|
{
|
|
lpMem += WriteStringToken (lpMem, 143,
|
|
PreviewCRDGrid * PreviewCRDGrid * ((LPHOSTCLUT)lpDevCRD)->outputChan);
|
|
}
|
|
else
|
|
{
|
|
lpMem += WriteObject (lpMem, BeginString);
|
|
}
|
|
Input[0] = ((float)i) / (PreviewCRDGrid - 1);
|
|
for (j = 0; j < PreviewCRDGrid; j++)
|
|
{
|
|
Input[1] = ((float)j) / (PreviewCRDGrid - 1);
|
|
for (k = 0; k < PreviewCRDGrid; k++)
|
|
{
|
|
Input[2] = ((float)k) / (PreviewCRDGrid - 1);
|
|
|
|
DoHostConversionCRD ((LPHOSTCLUT)lpTargetCRD, NULL, Input, Output, ColorSpace, 1);
|
|
DoHostConversionCSA ((LPHOSTCLUT)lpTargetCSA, Output, Temp);
|
|
DoHostConversionCRD ((LPHOSTCLUT)lpDevCRD, (LPHOSTCLUT)lpTargetCSA,
|
|
Temp, Output, 0, 0);
|
|
for (l = 0; l < ((LPHOSTCLUT)lpDevCRD)->outputChan; l++)
|
|
{
|
|
if (bAllowBinary)
|
|
{
|
|
*lpMem++ = (BYTES)(Output[l]*255);
|
|
}
|
|
else
|
|
{
|
|
lpMem += WriteHex (lpMem, (USHORT)(Output[l]*255));
|
|
if (((SINT) (lpMem - lpLineStart)) > MAX_LINELENG)
|
|
{
|
|
lpLineStart = lpMem;
|
|
lpMem += WriteObject (lpMem, NewLine);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!bAllowBinary)
|
|
lpMem += WriteObject (lpMem, EndString);
|
|
}
|
|
lpMem += WriteNewLineObject (lpMem, EndArray);
|
|
lpMem += WriteInt (lpMem, ((LPHOSTCLUT)lpDevCRD)->outputChan);
|
|
|
|
//********** Send Output Table.
|
|
lpMem += SendCRDOutputTable(lpMem, PublicArrayName,
|
|
((LPHOSTCLUT)lpDevCRD)->outputChan,
|
|
(((LPHOSTCLUT)lpDevCRD)->lutBits == 8)? icSigLut8Type:icSigLut16Type,
|
|
TRUE,
|
|
bAllowBinary);
|
|
|
|
|
|
lpMem += WriteNewLineObject (lpMem, EndArray);
|
|
lpMem += WriteObject (lpMem, EndDict); // End dictionary definition
|
|
lpMem += WriteNewLineObject (lpMem, CRDEnd);
|
|
Success = TRUE;
|
|
|
|
Done:
|
|
*lpcbSize = (DWORD)(lpMem - lpOldMem);
|
|
|
|
if (hTargetCRD)
|
|
MemFree(hTargetCRD);
|
|
if (hTargetCSA)
|
|
MemFree(hTargetCSA);
|
|
if (hDevCRD)
|
|
MemFree(hDevCRD);
|
|
return (Success);
|
|
}
|