Windows2000/private/ntos/w32/ntgdi/icm/mscms/ps2.c
2020-09-30 17:12:32 +02:00

6915 lines
179 KiB
C

/**Module*Header****\
* Module Name: PS2.C
* Module Descripton: Functions for retrieving or creating PostScript
* Level 2 operators from a profile. It is shared by mscms & pscript5
* Warnings:
* Issues:
* Public Routines:
* Created: 13 May 1996
* Author: Srinivasan Chandrasekar [srinivac]
* Copyright (c) 1996, 1997 Microsoft Corporation
*/
#include <math.h>
#define MAX_LINELEN 240
#define REVCURVE_RATIO 1
#define CIEXYZRange 0x1FFEC // 1.9997 in 16.16 notation
#define ALIGN_DWORD(nBytes) (((nBytes) + 3) & ~3)
#define FIX_16_16_SHIFT 16
#define FIX_16_16_SCALE (1 << (FIX_16_16_SHIFT))
#define TO_FIX(x) ((x) << FIX_16_16_SHIFT)
#define TO_INT(x) ((x) >> FIX_16_16_SHIFT)
#define FIX_MUL(x, y) MulDiv((x), (y), FIX_16_16_SCALE)
#define FIX_DIV(x, y) MulDiv((x), FIX_16_16_SCALE, (y))
#define FLOOR(x) ((x) >> FIX_16_16_SHIFT << FIX_16_16_SHIFT)
#define TYPE_CIEBASEDDEF 1
#define TYPE_CIEBASEDDEFG 2
#define TAG_PS2CSA 'ps2s'
#define TAG_REDCOLORANT 'rXYZ'
#define TAG_GREENCOLORANT 'gXYZ'
#define TAG_BLUECOLORANT 'bXYZ'
#define TAG_REDTRC 'rTRC'
#define TAG_GREENTRC 'gTRC'
#define TAG_BLUETRC 'bTRC'
#define TAG_GRAYTRC 'kTRC'
#define TAG_MEDIAWHITEPOINT 'wtpt'
#define TAG_AToB0 'A2B0'
#define TAG_AToB1 'A2B1'
#define TAG_AToB2 'A2B2'
#define TAG_PS2INTENT0 'psi0'
#define TAG_PS2INTENT1 'psi1'
#define TAG_PS2INTENT2 'psi2'
#define TAG_PS2INTENT3 'psi3'
#define TAG_CRDINTENT0 'psd0'
#define TAG_CRDINTENT1 'psd1'
#define TAG_CRDINTENT2 'psd2'
#define TAG_CRDINTENT3 'psd3'
#define TAG_BToA0 'B2A0'
#define TAG_BToA1 'B2A1'
#define TAG_BToA2 'B2A2'
#define TAG_BToA3 'B2A3'
#define LUT8_TYPE 'mft1'
#define LUT16_TYPE 'mft2'
#define SIG_CURVE_TYPE 'curv'
#define GetCPConnSpace(pProfile) (FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phConnectionSpace))
#define GetCPDevSpace(pProfile) (FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phDataColorSpace))
#define GetCPRenderIntent(pProfile) (FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phRenderingIntent))
#define WriteObject(pBuf, pStr) (STRCPY(pBuf, pStr), STRLEN(pStr))
#ifdef KERNEL_MODE
#define WriteInt(pBuf, i) OPSprintf(pBuf, "%l ", (i))
#define WriteHex(pBuf, x) OPSprintf(pBuf, "%x", ((x) & 0x00FF))
#define STRLEN strlen
#define STRCPY strcpy
#else
#define WriteInt(pBuf, i) wsprintfA(pBuf, "%lu ", (i))
#define WriteHex(pBuf, x) wsprintfA(pBuf, "%2.2x", ((x) & 0x00FF))
#define STRLEN lstrlenA
#define STRCPY lstrcpyA
#endif
#define MAXCHANNELS 4
#define PREVIEWCRDGRID 16
#define MAXCOLOR8 255
#define DATATYPE_LUT 0
#define DATATYPE_MATRIX 1
#define sRGB_CRC 0xa3d777b4L
#define sRGB_TAGSIZE 6168
// Local typedefs
typedef DWORD FIX_16_16, *PFIX_16_16;
typedef struct tagCURVETYPE {
DWORD dwSignature;
DWORD dwReserved;
DWORD nCount;
WORD data[0];
} CURVETYPE, *PCURVETYPE;
typedef struct tagXYZTYPE {
DWORD dwSignature;
DWORD dwReserved;
FIX_16_16 afxData[0];
} XYZTYPE, *PXYZTYPE;
typedef struct tagLUT8TYPE {
DWORD dwSignature;
DWORD dwReserved;
BYTE nInputChannels;
BYTE nOutputChannels;
BYTE nClutPoints;
BYTE padding;
FIX_16_16 e00;
FIX_16_16 e01;
FIX_16_16 e02;
FIX_16_16 e10;
FIX_16_16 e11;
FIX_16_16 e12;
FIX_16_16 e20;
FIX_16_16 e21;
FIX_16_16 e22;
BYTE data[0];
} LUT8TYPE, *PLUT8TYPE;
typedef struct tagLUT16TYPE {
DWORD dwSignature;
DWORD dwReserved;
BYTE nInputChannels;
BYTE nOutputChannels;
BYTE nClutPoints;
BYTE padding;
FIX_16_16 e00;
FIX_16_16 e01;
FIX_16_16 e02;
FIX_16_16 e10;
FIX_16_16 e11;
FIX_16_16 e12;
FIX_16_16 e20;
FIX_16_16 e21;
FIX_16_16 e22;
WORD wInputEntries;
WORD wOutputEntries;
WORD data[0];
} LUT16TYPE, *PLUT16TYPE;
typedef struct tagHOSTCLUT {
WORD wSize;
WORD wDataType;
DWORD dwDev;
DWORD dwPCS;
DWORD dwIntent;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
BYTE nInputCh;
BYTE nOutputCh;
BYTE nClutPoints;
BYTE nLutBits;
FIX_16_16 e[9];
WORD nInputEntries;
WORD nOutputEntries;
PBYTE inputArray[MAXCHANNELS];
PBYTE outputArray[MAXCHANNELS];
PBYTE clut;
} HOSTCLUT, *PHOSTCLUT;
// Internal functions
BOOL IsSRGBColorProfile(PBYTE);
BOOL GetCSAFromProfile (PBYTE, DWORD, DWORD, PBYTE, PDWORD, PBOOL);
BOOL GetPS2CSA_MONO_A(PBYTE, PBYTE, PDWORD, DWORD, PBOOL);
BOOL GetPS2CSA_ABC(PBYTE, PBYTE, PDWORD, DWORD, PBOOL, BOOL);
BOOL GetPS2CSA_ABC_Lab(PBYTE, PBYTE, PDWORD, DWORD, PBOOL);
BOOL GetPS2CSA_DEFG(PBYTE, PBYTE, PDWORD, DWORD, DWORD, PBOOL);
BOOL CreateMonoCRD(PBYTE, DWORD, PBYTE, PDWORD, DWORD);
BOOL CreateLutCRD(PBYTE, DWORD, PBYTE, PDWORD, DWORD, BOOL);
BOOL DoesCPTagExist(PBYTE, DWORD, PDWORD);
BOOL DoesTRCAndColorantTagExist(PBYTE);
BOOL GetCPWhitePoint(PBYTE, PFIX_16_16);
BOOL GetCPMediaWhitePoint(PBYTE, PFIX_16_16);
BOOL GetCPElementDataSize(PBYTE, DWORD, PDWORD);
BOOL GetCPElementSize(PBYTE, DWORD, PDWORD);
BOOL GetCPElementDataType(PBYTE, DWORD, PDWORD);
BOOL GetCPElementData(PBYTE, DWORD, PBYTE, PDWORD);
BOOL GetTRCElementSize(PBYTE, DWORD, PDWORD, PDWORD);
DWORD Ascii85Encode(PBYTE, DWORD, DWORD);
BOOL GetCRDInputOutputArraySize(PBYTE, DWORD, PDWORD, PDWORD, PDWORD, PDWORD);
BOOL GetHostCSA(PBYTE, PBYTE, PDWORD, DWORD, DWORD);
BOOL GetHostColorRenderingDictionary(PBYTE, DWORD, PBYTE, PDWORD);
BOOL GetHostColorSpaceArray(PBYTE, DWORD, PBYTE, PDWORD);
DWORD SendCRDBWPoint(PBYTE, PFIX_16_16);
DWORD SendCRDPQR(PBYTE, DWORD, PFIX_16_16);
DWORD SendCRDLMN(PBYTE, DWORD, PFIX_16_16, PFIX_16_16, DWORD);
DWORD SendCRDABC(PBYTE, PBYTE, DWORD, DWORD, PBYTE, PFIX_16_16, DWORD, BOOL);
DWORD SendCRDOutputTable(PBYTE, PBYTE, DWORD, DWORD, BOOL, BOOL);
DWORD SendCSABWPoint(PBYTE, DWORD, PFIX_16_16, PFIX_16_16);
VOID GetMediaWP(PBYTE, DWORD, PFIX_16_16, PFIX_16_16);
DWORD CreateCRDRevArray(PBYTE, PBYTE, PCURVETYPE, PWORD, DWORD, BOOL);
DWORD SendCRDRevArray(PBYTE, PBYTE, PCURVETYPE, DWORD, BOOL);
DWORD CreateColSpArray(PBYTE, PBYTE, DWORD, BOOL);
DWORD CreateColSpProc(PBYTE, PBYTE, DWORD, BOOL);
DWORD CreateFloatString(PBYTE, PBYTE, DWORD);
DWORD CreateInputArray(PBYTE, DWORD, DWORD, PBYTE, DWORD, PBYTE, BOOL, PBYTE);
DWORD CreateOutputArray(PBYTE, DWORD, DWORD, DWORD, PBYTE, DWORD, PBYTE, BOOL, PBYTE);
DWORD GetPublicArrayName(DWORD, PBYTE);
BOOL GetRevCurve(PCURVETYPE, PWORD, PWORD);
VOID GetCLUTInfo(DWORD, PBYTE, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD, PDWORD);
DWORD EnableGlobalDict(PBYTE);
DWORD BeginGlobalDict(PBYTE);
DWORD EndGlobalDict(PBYTE);
DWORD WriteNewLineObject(PBYTE, const char *);
DWORD WriteHNAToken(PBYTE, BYTE, DWORD);
DWORD WriteIntStringU2S(PBYTE, PBYTE, DWORD);
DWORD WriteIntStringU2S_L(PBYTE, PBYTE, DWORD);
DWORD WriteHexBuffer(PBYTE, PBYTE, PBYTE, DWORD);
DWORD WriteStringToken(PBYTE, BYTE, DWORD);
DWORD WriteByteString(PBYTE, PBYTE, DWORD);
DWORD WriteInt2ByteString(PBYTE, PBYTE, DWORD);
DWORD WriteFixed(PBYTE, FIX_16_16);
DWORD WriteFixed2dot30(PBYTE, DWORD);
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
DWORD WriteDouble(PBYTE, double);
BOOL CreateMatrixCRD(PBYTE, PBYTE, PDWORD, DWORD, BOOL);
DWORD CreateHostLutCRD(PBYTE, DWORD, PBYTE, DWORD);
DWORD CreateHostMatrixCSAorCRD(PBYTE, PBYTE, PDWORD, DWORD, BOOL);
DWORD CreateHostInputOutputArray(PBYTE, PBYTE*, DWORD, DWORD, DWORD, DWORD, PBYTE);
DWORD CreateHostTRCInputTable(PBYTE, PHOSTCLUT, PCURVETYPE, PCURVETYPE, PCURVETYPE);
DWORD CreateHostRevTRCInputTable(PBYTE, PHOSTCLUT, PCURVETYPE, PCURVETYPE, PCURVETYPE);
BOOL CheckInputOutputTable(PHOSTCLUT, float*, BOOL, BOOL);
BOOL CheckColorLookupTable(PHOSTCLUT, float*);
BOOL DoHostConversionCSA(PHOSTCLUT, float*, float*);
BOOL DoHostConversionCRD(PHOSTCLUT, PHOSTCLUT, float*, float*, BOOL);
float g(float);
float inverse_g(float);
BOOL TableInterp3(PHOSTCLUT, float*);
BOOL TableInterp4(PHOSTCLUT, float*);
void LabToXYZ(float*, float*, PFIX_16_16);
void XYZToLab(float*, float*, PFIX_16_16);
VOID ApplyMatrix(FIX_16_16 *e, float *Input, float *Output);
BOOL CreateColorantArray(PBYTE, double *, DWORD);
BOOL InvertColorantArray(double *, double *);
#endif
DWORD crc32(PBYTE buff, DWORD length);
// Global variables
const char ASCII85DecodeBegin[] = "<~";
const char ASCII85DecodeEnd[] = "~> cvx exec ";
const char TestingDEFG[] = "/SupportDEFG? {/CIEBasedDEFG \
/ColorSpaceFamily resourcestatus { pop pop languagelevel 3 ge}{false} ifelse} def";
const char SupportDEFG_S[] = "SupportDEFG? { ";
const char NotSupportDEFG_S[] = "SupportDEFG? not { ";
const char SupportDEFG_E[] = "}if ";
const char IndexArray16b[] = " dup length 1 sub 3 -1 roll mul dup dup floor cvi\
exch ceiling cvi 3 index exch get 32768 add 4 -1 roll 3 -1 roll get 32768 add\
dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add ";
const char IndexArray[] = " dup length 1 sub 3 -1 roll mul dup dup floor cvi\
exch ceiling cvi 3 index exch get 4 -1 roll 3 -1 roll get\
dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add ";
const char StartClip[] = "dup 1.0 le{dup 0.0 ge{" ;
const char EndClip[] = "}if}if " ;
const char BeginString[] = "<";
const char EndString[] = ">";
const char BeginArray[] = "[";
const char EndArray[] = "]";
const char BeginFunction[] = "{";
const char EndFunction[] = "}bind ";
const char BeginDict[] = "<<" ;
const char EndDict[] = ">>" ;
const char BlackPoint[] = "[0 0 0]" ;
const char DictType[] = "/ColorRenderingType 1 ";
const char IntentType[] = "/RenderingIntent ";
const char IntentPer[] = "/Perceptual";
const char IntentSat[] = "/Saturation";
const char IntentACol[] = "/AbsoluteColorimetric";
const char IntentRCol[] = "/RelativeColorimetric";
const char WhitePointTag[] = "/WhitePoint " ;
const char BlackPointTag[] = "/BlackPoint " ;
const char RangePQRTag[] = "/RangePQR " ;
const char TransformPQRTag[] = "/TransformPQR " ;
const char MatrixPQRTag[] = "/MatrixPQR " ;
const char RangePQR[] = "[ -0.07 2.2 -0.02 1.4 -0.2 4.8 ]";
const char MatrixPQR[] = "[0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296]";
#ifdef BARDFORD_TRANSFORM
const char *TransformPQR[3] = {"exch pop exch 3 get mul exch pop exch 3 get div ",
"exch pop exch 4 get mul exch pop exch 4 get div ",
"exch pop exch 5 get mul exch pop exch 5 get div " };
#else
const char *TransformPQR[3] = {"4 index 0 get div 2 index 0 get mul 4 {exch pop} repeat ",
"4 index 1 get div 2 index 1 get mul 4 {exch pop} repeat ",
"4 index 2 get div 2 index 2 get mul 4 {exch pop} repeat " };
#endif
const char RangeABCTag[] = "/RangeABC " ;
const char MatrixATag[] = "/MatrixA ";
const char MatrixABCTag[] = "/MatrixABC ";
const char EncodeABCTag[] = "/EncodeABC " ;
const char RangeLMNTag[] = "/RangeLMN " ;
const char MatrixLMNTag[] = "/MatrixLMN " ;
const char EncodeLMNTag[] = "/EncodeLMN " ;
const char RenderTableTag[] = "/RenderTable " ;
const char CIEBasedATag[] = "/CIEBasedA " ;
const char CIEBasedABCTag[] = "/CIEBasedABC " ;
const char CIEBasedDEFGTag[] = "/CIEBasedDEFG " ;
const char CIEBasedDEFTag[] = "/CIEBasedDEF " ;
const char DecodeATag[] = "/DecodeA " ;
const char DecodeABCTag[] = "/DecodeABC " ;
const char DecodeLMNTag[] = "/DecodeLMN " ;
const char DeviceRGBTag[] = "/DeviceRGB " ;
const char DeviceCMYKTag[] = "/DeviceCMYK " ;
const char DeviceGrayTag[] = "/DeviceGray " ;
const char TableTag[] = "/Table " ;
const char DecodeDEFGTag[] = "/DecodeDEFG " ;
const char DecodeDEFTag[] = "/DecodeDEF " ;
const char NullOp[] = "";
const char DupOp[] = "dup ";
const char UserDictOp[] = "userdict ";
const char GlobalDictOp[] = "globaldict ";
const char CurrentGlobalOp[] = "currentglobal ";
const char SetGlobalOp[] = "setglobal ";
const char DefOp[] = "def ";
const char BeginOp[] = "begin ";
const char EndOp[] = "end ";
const char TrueOp[] = "true ";
const char FalseOp[] = "false ";
const char MulOp[] = "mul ";
const char DivOp[] = "div ";
const char NewLine[] = "\r\n" ;
const char Slash[] = "/" ;
const char Space[] = " " ;
const char CRDBegin[] = "%** CRD Begin ";
const char CRDEnd[] = "%** CRD End ";
const char CieBasedDEFGBegin[] = "%** CieBasedDEFG CSA Begin ";
const char CieBasedDEFBegin[] = "%** CieBasedDEF CSA Begin ";
const char CieBasedABCBegin[] = "%** CieBasedABC CSA Begin ";
const char CieBasedABegin[] = "%** CieBasedA CSA Begin ";
const char CieBasedDEFGEnd[] = "%** CieBasedDEFG CSA End ";
const char CieBasedDEFEnd[] = "%** CieBasedDEF CSA End ";
const char CieBasedABCEnd[] = "%** CieBasedABC CSA End ";
const char CieBasedAEnd[] = "%** CieBasedA CSA End ";
const char RangeABC[] = "[ 0 1 0 1 0 1 ] ";
const char RangeLMN[] = "[ 0 2 0 2 0 2 ] ";
const char Identity[] = "[1 0 0 0 1 0 0 0 1]";
const char RangeABC_Lab[] = "[0 100 -128 127 -128 127]";
const char Clip01[] = "dup 1.0 ge{pop 1.0}{dup 0.0 lt{pop 0.0}if}ifelse " ;
const char DecodeA3[] = "256 div exp ";
const char DecodeA3Rev[] = "256 div 1.0 exch div exp ";
const char DecodeABCArray[] = "DecodeABC_";
const char InputArray[] = "Inp_";
const char OutputArray[] = "Out_";
const char Scale8[] = "255 div " ;
const char Scale16[] = "65535 div " ;
const char Scale16XYZ[] = "32768 div " ;
const char TFunction8[] = "exch 255 mul round cvi get 255 div " ;
const char TFunction8XYZ[] = "exch 255 mul round cvi get 128 div " ;
const char MatrixABCLab[] = "[1 1 1 1 0 0 0 0 -1]" ;
const char DecodeABCLab1[] = "[{16 add 116 div} bind {500 div} bind {200 div} bind]";
const char DecodeALab[] = " 50 mul 16 add 116 div ";
const char DecodeLMNLab[] = "dup 0.206897 ge{dup dup mul mul}{0.137931 sub 0.128419 mul} ifelse ";
const char RangeLMNLab[] = "[0 1 0 1 0 1]" ;
const char EncodeLMNLab[] = "dup 0.008856 le{7.787 mul 0.13793 add}{0.3333 exp}ifelse " ;
const char MatrixABCLabCRD[] = "[0 500 0 116 -500 200 0 0 -200]" ;
const char MatrixABCXYZCRD[] = "[0 1 0 1 0 0 0 0 1]" ;
const char EncodeABCLab1[] = "16 sub 100 div " ;
const char EncodeABCLab2[] = "128 add 255 div " ;
const char *DecodeABCLab[] = {"50 mul 16 add 116 div ",
"128 mul 128 sub 500 div",
"128 mul 128 sub 200 div"};
const char ColorSpace1[] = "/CIEBasedABC << /DecodeLMN ";
const char ColorSpace3[] = " exp} bind ";
const char ColorSpace5[] = "/WhitePoint [0.9642 1 0.8249] ";
const char PreViewInArray[] = "IPV_";
const char PreViewOutArray[] = "OPV_";
const char sRGBColorSpaceArray[] = "[/CIEBasedABC << \r\n\
/DecodeLMN [{dup 0.03928 le {12.92321 div}{0.055 add 1.055 div 2.4 exp}ifelse} bind dup dup ] \r\n\
/MatrixLMN [0.412457 0.212673 0.019334 0.357576 0.715152 0.119192 0.180437 0.072175 0.950301] \r\n\
/WhitePoint [ 0.9505 1 1.0890 ] >> ]";
#ifdef BRADFORD_TRANSFORM
const char sRGBColorRenderingDictionary[] = "\
/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ] \r\n\
/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296] \r\n\
/TransformPQR [\
{exch pop exch 3 get mul exch pop exch 3 get div} bind \
{exch pop exch 4 get mul exch pop exch 4 get div} bind \
{exch pop exch 5 get mul exch pop exch 5 get div} bind] \r\n\
/MatrixLMN [3.240449 -0.969265 0.055643 -1.537136 1.876011 -0.204026 -0.498531 0.041556 1.057229] \r\n\
/EncodeABC [{dup 0.00304 le {12.92321 mul}{1 2.4 div exp 1.055 mul 0.055 sub}ifelse} bind dup dup] \r\n\
/WhitePoint[0.9505 1 1.0890] >>";
#else
const char sRGBColorRenderingDictionary[] = "\
/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ] \r\n\
/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296] \r\n\
/TransformPQR [\
{4 index 0 get div 2 index 0 get mul 4 {exch pop} repeat} \
{4 index 1 get div 2 index 1 get mul 4 {exch pop} repeat} \
{4 index 2 get div 2 index 2 get mul 4 {exch pop} repeat}] \r\n\
/MatrixLMN [3.240449 -0.969265 0.055643 -1.537136 1.876011 -0.204026 -0.498531 0.041556 1.057229] \r\n\
/EncodeABC [{dup 0.00304 le {12.92321 mul}{1 2.4 div exp 1.055 mul 0.055 sub}ifelse} bind dup dup] \r\n\
/WhitePoint[0.9505 1 1.0890] >>";
#endif
/*
* InternalGetPS2ColorSpaceArray
* Function:
* This functions retrieves the PostScript Level 2 CSA from the profile,
* or creates it if the profile tag is not present
* Arguments:
* hProfile - handle identifing the profile object
* dwIntent - rendering intent of CSA
* dwCSAType - type of CSA
* pbuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
InternalGetPS2ColorSpaceArray (
PBYTE pProfile,
DWORD dwIntent,
DWORD dwCSAType,
PBYTE pBuffer,
PDWORD pcbSize,
LPBOOL pbBinary
)
{
DWORD dwInpBufSize;
BOOL bRc;
// If profile has a CSA tag, get it directly
bRc = GetCSAFromProfile(pProfile, dwIntent, dwCSAType, pBuffer, pcbSize, pbBinary);
if (! bRc && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
{
// Create a CSA from the profile data
switch (dwCSAType)
{
case CSA_ABC:
bRc = GetPS2CSA_ABC(pProfile, pBuffer, pcbSize, dwIntent, pbBinary, FALSE);
break;
case CSA_DEF:
bRc = GetPS2CSA_DEFG(pProfile, pBuffer, pcbSize, dwIntent, TYPE_CIEBASEDDEF, pbBinary);
break;
case CSA_RGB:
case CSA_Lab:
dwInpBufSize = *pcbSize;
// We get a DEF CSA followed by an ABC CSA and set it up so that
// on PS interpreters that do not support the DEF CSA, the ABC one
// is active
bRc = GetPS2CSA_DEFG(pProfile, pBuffer, pcbSize, dwIntent, TYPE_CIEBASEDDEF, pbBinary);
if (bRc)
{
// Create CieBasedABC for printers that do not support CieBasedDEF
DWORD cbNewSize = 0;
PBYTE pNewBuffer;
PBYTE pOldBuffer;
if (pBuffer)
{
pNewBuffer = pBuffer + *pcbSize;
pOldBuffer = pNewBuffer;
pNewBuffer += WriteObject(pNewBuffer, NewLine);
if (dwCSAType == CSA_Lab)
{
pNewBuffer += WriteNewLineObject(pNewBuffer, NotSupportDEFG_S);
}
cbNewSize = dwInpBufSize - (DWORD)(pNewBuffer - pBuffer);
}
else
{
pNewBuffer = NULL;
}
bRc = GetPS2CSA_ABC(pProfile, pNewBuffer, &cbNewSize, dwIntent, pbBinary, TRUE);
if (pBuffer)
{
pNewBuffer += cbNewSize;
if (dwCSAType == CSA_Lab)
{
pNewBuffer += WriteNewLineObject(pNewBuffer, SupportDEFG_E);
}
*pcbSize += (DWORD) (pNewBuffer - pOldBuffer);
}
else
{
*pcbSize += cbNewSize;
}
}
else
{
*pcbSize = dwInpBufSize;
bRc = GetPS2CSA_ABC(pProfile, pBuffer, pcbSize, dwIntent, pbBinary, FALSE);
}
break;
case CSA_CMYK:
case CSA_DEFG:
bRc = GetPS2CSA_DEFG(pProfile, pBuffer, pcbSize, dwIntent, TYPE_CIEBASEDDEFG, pbBinary);
break;
case CSA_GRAY:
case CSA_A:
bRc = GetPS2CSA_MONO_A(pProfile, pBuffer, pcbSize, dwIntent, pbBinary);
break;
default:
WARNING((__TEXT("Invalid CSA type passed to GetPS2ColorSpaceArray: %d\n"), dwCSAType));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
return bRc;
}
/*
* InternalGetPS2ColorRenderingIntent
* Function:
* This functions retrieves the PostScript Level 2 color rendering intent
* from the profile, or creates it if the profile tag is not present
* Arguments:
* hProfile - handle identifing the profile object
* pbuffer - pointer to receive the color rendering intent
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
InternalGetPS2ColorRenderingIntent(
PBYTE pProfile,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pcbSize
)
{
DWORD dwIndex, dwTag, dwSize;
BOOL bRc = FALSE;
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
dwTag = TAG_PS2INTENT0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
dwTag = TAG_PS2INTENT1;
break;
case INTENT_SATURATION:
dwTag = TAG_PS2INTENT2;
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
dwTag = TAG_PS2INTENT3;
break;
default:
WARNING((__TEXT("Invalid intent passed to GetPS2ColorRenderingIntent: %d\n"), dwIntent));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DoesCPTagExist(pProfile, dwTag, &dwIndex))
{
(void)GetCPElementDataSize(pProfile, dwIndex, &dwSize);
if (pBuffer)
{
if (*pcbSize >= dwSize + 1) // for NULL terminating
{
bRc = GetCPElementData(pProfile, dwIndex, pBuffer, &dwSize);
}
else
{
WARNING((__TEXT("Buffer too small to get CRI\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
}
else
bRc = TRUE;
*pcbSize = dwSize;
}
else
{
WARNING((__TEXT("psi tag not present for intent %d in profile\n"), dwIntent));
SetLastError(ERROR_TAG_NOT_PRESENT);
}
// NULL terminate
if (bRc)
{
if (pBuffer)
{
pBuffer[*pcbSize] = '\0';
}
(*pcbSize)++;
}
return bRc;
}
/*
* InternalGetPS2ColorRenderingDictionary
* Function:
* This functions retrieves the PostScript Level 2 CRD from the profile,
* or creates it if the profile tag is not preesnt
* Arguments:
* hProfile - handle identifing the profile object
* dwIntent - intent whose CRD is required
* pbuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
InternalGetPS2ColorRenderingDictionary(
PBYTE pProfile,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pcbSize,
PBOOL pbBinary
)
{
DWORD dwIndex, dwSize, dwDataType;
DWORD dwCRDTag, dwBToATag;
BOOL bRc = FALSE;
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
dwCRDTag = TAG_CRDINTENT0;
dwBToATag = TAG_BToA0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
dwCRDTag = TAG_CRDINTENT1;
dwBToATag = TAG_BToA1;
break;
case INTENT_SATURATION:
dwCRDTag = TAG_CRDINTENT2;
dwBToATag = TAG_BToA2;
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
dwCRDTag = TAG_CRDINTENT3;
dwBToATag = TAG_BToA1;
break;
default:
WARNING((__TEXT("Invalid intent passed to GetPS2ColorRenderingDictionary: %d\n"), dwIntent));
SetLastError(ERROR_INVALID_PARAMETER);
return bRc;
}
if (DoesCPTagExist(pProfile, dwCRDTag, &dwIndex))
{
(void)GetCPElementDataSize(pProfile, dwIndex, &dwSize);
(void)GetCPElementDataType(pProfile, dwIndex, &dwDataType);
if (! *pbBinary && dwDataType == 1)
{
// Profile has binary data, user asked for ASCII, so we have to
// ASCII 85 encode it
dwSize = dwSize * 5 / 4 + sizeof(ASCII85DecodeBegin) + sizeof(ASCII85DecodeEnd) + 2048;
}
if (pBuffer)
{
if (*pcbSize >= dwSize)
{
(void)GetCPElementData(pProfile, dwIndex, pBuffer, &dwSize);
if (! *pbBinary && dwDataType == 1)
{
dwSize = Ascii85Encode(pBuffer, dwSize, *pcbSize);
}
bRc = TRUE;
}
else
{
WARNING((__TEXT("Buffer too small to get CRD\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
}
else
bRc = TRUE;
*pcbSize = dwSize;
}
else if (DoesCPTagExist(pProfile, dwBToATag, &dwIndex))
{
bRc = CreateLutCRD(pProfile, dwIndex, pBuffer, pcbSize, dwIntent, *pbBinary);
}
else if (DoesCPTagExist(pProfile, TAG_GRAYTRC, &dwIndex))
{
bRc = CreateMonoCRD(pProfile, dwIndex, pBuffer, pcbSize, dwIntent);
}
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
else if (DoesTRCAndColorantTagExist(pProfile))
{
bRc = CreateMatrixCRD(pProfile, pBuffer, pcbSize, dwIntent, *pbBinary);
}
#endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
else
{
WARNING((__TEXT("Profile doesn't have tags to create CRD\n")));
SetLastError(ERROR_INVALID_PROFILE);
}
return bRc;
}
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* InternalGetPS2PreviewCRD
* Function:
* This functions creates a preview PostScript Level 2 CRD from the
* specified destination and target profiles
* To do this, it does the following:
* 1) Creates host deviceCRD deviceCSA targetCRD.
* 2) Creates proofing CRD by sampling deviceCRD deviceCSA and targetCRD.
* 3) Uses deviceCRD's input table as proofingCRD's input table.
* 4) Uses targetCRD's output table as proofingCRD's output table.
* 5) Sample data is XYZ or Lab, depends on PCS of targetCRD.
* Arguments:
* pDestProf - memory mapped pointer to destination profile
* pTargetProf - memory mapped pointer to target profile
* dwIntent - intent whose CRD is required
* pbuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
InternalGetPS2PreviewCRD(
PBYTE pDestProf,
PBYTE pTargetProf,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pcbSize,
PBOOL pbBinary
)
{
DWORD i, j, k, l, dwDev, dwTag, dwPCS;
DWORD dwInArraySize, dwOutArraySize;
DWORD nDevGrids, nTargetGrids, nPreviewCRDGrids;
DWORD cbDevCRD, cbTargetCSA, cbTargetCRD;
float fInput[MAXCHANNELS];
float fOutput[MAXCHANNELS];
float fTemp[MAXCHANNELS];
PBYTE pLineStart, pStart = pBuffer;
PBYTE lpDevCRD = NULL, lpTargetCSA = NULL, lpTargetCRD = NULL;
char pPublicArrayName[5];
BOOL bRc = FALSE;
dwDev = GetCPDevSpace(pTargetProf);
i = (dwDev == SPACE_CMYK) ? 4 : 3;
// Get the input array size IntentTag and Grid of the destination profile
if (!GetCRDInputOutputArraySize(
pTargetProf,
dwIntent,
&dwInArraySize,
NULL,
&dwTag,
&nTargetGrids))
return FALSE;
// Get the output array size IntentTag and Grid of the target profile
if (!GetCRDInputOutputArraySize(
pDestProf,
dwIntent,
NULL,
&dwOutArraySize,
&dwTag,
&nDevGrids))
return FALSE;
nPreviewCRDGrids = (nTargetGrids > nDevGrids) ? nTargetGrids : nDevGrids;
// Min proofing CRD grid will be PREVIEWCRDGRID
if (nPreviewCRDGrids < PREVIEWCRDGRID)
nPreviewCRDGrids = PREVIEWCRDGRID;
if (pBuffer == NULL)
{
// Return size of buffer needed
*pcbSize = nPreviewCRDGrids * nPreviewCRDGrids * nPreviewCRDGrids *
i * 2 + // CLUT size (Hex output)
dwOutArraySize + // Output Array size
dwInArraySize + // Input Array size
4096; // Extra PostScript stuff
// Add space for new line.
*pcbSize += (((*pcbSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
return TRUE;
}
// Query the sizes of host target CRD, target CSA and device CRD
if (!GetHostColorRenderingDictionary(pTargetProf, dwIntent, NULL, &cbTargetCRD) ||
!GetHostColorSpaceArray(pTargetProf, dwIntent, NULL, &cbTargetCSA) ||
!GetHostColorRenderingDictionary(pDestProf, dwIntent, NULL, &cbDevCRD))
{
return FALSE;
}
// Allocate buffers for host target CRD, target CSA and device CRD
if (((lpTargetCRD = MemAlloc(cbTargetCRD)) == NULL) ||
((lpTargetCSA = MemAlloc(cbTargetCSA)) == NULL) ||
((lpDevCRD = MemAlloc(cbDevCRD)) == NULL))
{
goto Done;
}
// Build host target CRD, target CSA and device CRD
if (!GetHostColorRenderingDictionary(pTargetProf, dwIntent, lpTargetCRD, &cbTargetCRD) ||
!GetHostColorSpaceArray(pTargetProf, dwIntent, lpTargetCSA, &cbTargetCSA) ||
!GetHostColorRenderingDictionary(pDestProf, dwIntent, lpDevCRD, &cbDevCRD))
{
goto Done;
}
// Create global data
GetPublicArrayName(dwTag, pPublicArrayName);
// Build Proofing CRD based on Host target CRD, target CSA and dest CRD.
// We use target CRD input tables and matrix as the input tables and
// matrix of the ProofCRD. We use dest CRD output tables as the
// output tables of the ProofCRD.
pBuffer += WriteNewLineObject(pBuffer, CRDBegin);
pBuffer += EnableGlobalDict(pBuffer);
pBuffer += BeginGlobalDict(pBuffer);
pBuffer += CreateInputArray(pBuffer, 0, 0, pPublicArrayName,
0, NULL, *pbBinary, lpTargetCRD);
pBuffer += CreateOutputArray(pBuffer, 0, 0, 0,
pPublicArrayName, 0, NULL, *pbBinary, lpDevCRD);
pBuffer += EndGlobalDict(pBuffer);
// Start writing the CRD
pBuffer += WriteNewLineObject(pBuffer, BeginDict); // Begin dictionary
pBuffer += WriteObject(pBuffer, DictType); // Dictionary type
// Send /RenderingIntent
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentPer);
break;
case INTENT_SATURATION:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentSat);
break;
case INTENT_RELATIVE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentRCol);
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentACol);
break;
}
// /BlackPoint & /WhitePoint
pBuffer += SendCRDBWPoint(pBuffer, ((PHOSTCLUT)lpTargetCRD)->afxIlluminantWP);
// Send PQR - used for Absolute Colorimetric
pBuffer += SendCRDPQR(pBuffer, dwIntent, ((PHOSTCLUT)lpTargetCRD)->afxIlluminantWP);
// Send LMN - For Absolute Colorimetric use WhitePoint's XYZs
pBuffer += SendCRDLMN(pBuffer, dwIntent,
((PHOSTCLUT)lpTargetCRD)->afxIlluminantWP,
((PHOSTCLUT)lpTargetCRD)->afxMediaWP,
((PHOSTCLUT)lpTargetCRD)->dwPCS);
// Send ABC
pBuffer += SendCRDABC(pBuffer, pPublicArrayName,
((PHOSTCLUT)lpTargetCRD)->dwPCS,
((PHOSTCLUT)lpTargetCRD)->nInputCh,
NULL,
((PHOSTCLUT)lpTargetCRD)->e,
(((PHOSTCLUT)lpTargetCRD)->nLutBits == 8)? LUT8_TYPE : LUT16_TYPE,
*pbBinary);
// /RenderTable
pBuffer += WriteNewLineObject(pBuffer, RenderTableTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteInt(pBuffer, nPreviewCRDGrids); // Send down Na
pBuffer += WriteInt(pBuffer, nPreviewCRDGrids); // Send down Nb
pBuffer += WriteInt(pBuffer, nPreviewCRDGrids); // Send down Nc
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginArray);
dwPCS = ((PHOSTCLUT)lpDevCRD)->dwPCS;
for (i=0; i<nPreviewCRDGrids; i++) // Na strings should be sent
{
pBuffer += WriteObject(pBuffer, NewLine);
pLineStart = pBuffer;
if (*pbBinary)
{
pBuffer += WriteStringToken(pBuffer, 143,
nPreviewCRDGrids * nPreviewCRDGrids * ((PHOSTCLUT)lpDevCRD)->nOutputCh);
}
else
{
pBuffer += WriteObject(pBuffer, BeginString);
}
fInput[0] = ((float)i) / (nPreviewCRDGrids - 1);
for (j=0; j<nPreviewCRDGrids; j++)
{
fInput[1] = ((float)j) / (nPreviewCRDGrids - 1);
for (k=0; k<nPreviewCRDGrids; k++)
{
fInput[2] = ((float)k) / (nPreviewCRDGrids - 1);
DoHostConversionCRD((PHOSTCLUT)lpTargetCRD, NULL, fInput, fOutput, 1);
DoHostConversionCSA((PHOSTCLUT)lpTargetCSA, fOutput, fTemp);
DoHostConversionCRD((PHOSTCLUT)lpDevCRD, (PHOSTCLUT)lpTargetCSA,
fTemp, fOutput, 0);
for (l=0; l<((PHOSTCLUT)lpDevCRD)->nOutputCh; l++)
{
if (*pbBinary)
{
*pBuffer++ = (BYTE)(fOutput[l] * 255);
}
else
{
pBuffer += WriteHex(pBuffer, (USHORT)(fOutput[l] * 255));
if ((pBuffer - pLineStart) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
}
}
}
if (!*pbBinary)
pBuffer += WriteObject(pBuffer, EndString);
}
pBuffer += WriteNewLineObject(pBuffer, EndArray);
pBuffer += WriteInt(pBuffer, ((PHOSTCLUT)lpDevCRD)->nOutputCh);
// Send output table
pBuffer += SendCRDOutputTable(pBuffer, pPublicArrayName,
((PHOSTCLUT)lpDevCRD)->nOutputCh,
(((PHOSTCLUT)lpDevCRD)->nLutBits == 8)? LUT8_TYPE : LUT16_TYPE,
TRUE,
*pbBinary);
pBuffer += WriteNewLineObject(pBuffer, EndArray);
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, CRDEnd);
bRc = TRUE;
Done:
*pcbSize = (DWORD)(pBuffer - pStart);
if (lpTargetCRD)
MemFree(lpTargetCRD);
if (lpTargetCSA)
MemFree(lpTargetCSA);
if (lpDevCRD)
MemFree(lpDevCRD);
return bRc;
}
#endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* GetCSAFromProfile
* Function:
* This function gets the Color Space Array from the profile if the
* tag is present
* Arguments:
* pProfile - pointer to the memory mapped profile
* dwIntent - rendering intent of CSA requested
* dwCSAType - type of CSA requested
* pBuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
GetCSAFromProfile (
PBYTE pProfile,
DWORD dwIntent,
DWORD dwCSAType,
PBYTE pBuffer,
PDWORD pcbSize,
PBOOL pbBinary
)
{
DWORD dwDev, dwProfileIntent;
DWORD dwIndex, dwSize, dwDataType;
BOOL bRc = FALSE;
// This function can fail without setting an error, so reset error
// here to prevent confusion later
SetLastError(0);
// Get the profile's color space and rendering intent
dwDev = GetCPDevSpace(pProfile);
dwProfileIntent = GetCPRenderIntent(pProfile);
// If the rendering intents don't match, or the profile's color space
// is incompatible with requested CSA type, fail
if ((dwIntent != dwProfileIntent) ||
((dwDev == SPACE_GRAY) &&
((dwCSAType != CSA_GRAY) && (dwCSAType != CSA_A))))
{
WARNING((__TEXT("Can't use profile's CSA tag due to different rendering intents\n")));
return FALSE;
}
if (DoesCPTagExist(pProfile, TAG_PS2CSA, &dwIndex))
{
(void)GetCPElementDataSize(pProfile, dwIndex, &dwSize);
(void)GetCPElementDataType(pProfile, dwIndex, &dwDataType);
if (! *pbBinary && dwDataType == 1)
{
// Profile has binary data, user asked for ASCII, so we have to
// ASCII 85 encode it
dwSize = dwSize * 5 / 4 + sizeof(ASCII85DecodeBegin) + sizeof(ASCII85DecodeEnd) + 2048;
}
if (pBuffer)
{
if (*pcbSize >= dwSize)
{
(void)GetCPElementData(pProfile, dwIndex, pBuffer, &dwSize);
if (! *pbBinary && dwDataType == 1)
{
dwSize = Ascii85Encode(pBuffer, dwSize, *pcbSize);
}
bRc = TRUE;
}
else
{
WARNING((__TEXT("Buffer too small to get CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
}
else
bRc = TRUE;
*pcbSize = dwSize;
}
return bRc;
}
/*
* GetPS2CSA_MONO_A
* Function:
* This function creates a CIEBasedA colorspace array from an input
* GRAY profile
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* dwIntent - rendering intent of CSA requested
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
GetPS2CSA_MONO_A(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
PBOOL pbBinary
)
{
PCURVETYPE pData;
PTAGDATA pTagData;
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
DWORD i, dwPCS, nCount;
DWORD dwIndex, dwSize;
DWORD afxIlluminantWP[3];
DWORD afxMediaWP[3];
// Check if we can generate the CSA
// Required tag is gray TRC
if (! DoesCPTagExist(pProfile, TAG_GRAYTRC, &dwIndex))
{
WARNING((__TEXT("Gray TRC tag not present to create MONO_A CSA\n")));
SetLastError(ERROR_TAG_NOT_PRESENT);
return FALSE;
}
dwPCS = GetCPConnSpace(pProfile);
(void)GetCPElementSize(pProfile, dwIndex, &dwSize);
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
nCount = FIX_ENDIAN(pData->nCount);
// Estimate size required to hold the CSA
dwSize = nCount * 6 + // Number of INT elements
3 * (STRLEN(IndexArray) +
STRLEN(StartClip) +
STRLEN(EndClip)) +
2048; // + other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get MONO_A CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
(void)GetMediaWP(pProfile, dwIntent, afxIlluminantWP, afxMediaWP);
// Start creating the ColorSpace
pBuffer += WriteNewLineObject(pBuffer, CieBasedABegin);
pBuffer += WriteNewLineObject(pBuffer, BeginArray); // Begin array
// /CIEBasedA
pBuffer += WriteObject(pBuffer, CIEBasedATag); // Create entry
pBuffer += WriteObject(pBuffer, BeginDict); // Begin dictionary
// Send /BlackPoint & /WhitePoint
pBuffer += SendCSABWPoint(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP);
// /DecodeA
pBuffer += WriteObject(pBuffer, NewLine);
pLineStart = pBuffer;
if (nCount != 0)
{
pBuffer += WriteObject(pBuffer, DecodeATag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteObject(pBuffer, BeginFunction);
pTable = (PBYTE)(pData->data);
if (nCount == 1) // Gamma supplied in ui16 format
{
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pBuffer += WriteObject(pBuffer, DecodeA3);
// If the PCS is Lab, we need to convert Lab to XYZ
// Now, the range is from 0 --> 0.99997.
// Actually, the conversion from Lab to XYZ is not needed
if (dwPCS == SPACE_Lab)
{
pBuffer += WriteObject(pBuffer, DecodeALab);
pBuffer += WriteObject(pBuffer, DecodeLMNLab);
}
}
else
{
pBuffer += WriteObject(pBuffer, StartClip);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nCount; i++)
{
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject (pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, IndexArray);
pBuffer += WriteObject(pBuffer, Scale16);
// If the PCS is Lab, we need to convert Lab to XYZ
// Now, the range is from 0 --> .99997.
// Actually, the conversion from Lab to XYZ is not needed.
if (dwPCS == SPACE_Lab)
{
pBuffer += WriteObject(pBuffer, DecodeALab);
pBuffer += WriteObject(pBuffer, DecodeLMNLab);
}
pBuffer += WriteObject(pBuffer, EndClip);
}
pBuffer += WriteObject(pBuffer, EndFunction);
pBuffer += WriteObject(pBuffer, EndArray);
}
// /MatrixA
pBuffer += WriteNewLineObject(pBuffer, MatrixATag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
pBuffer += WriteFixed(pBuffer, afxMediaWP[i]);
}
else
{
pBuffer += WriteFixed(pBuffer, afxIlluminantWP[i]);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
// /RangeLMN
pBuffer += WriteNewLineObject(pBuffer, RangeLMNTag);
pBuffer += WriteObject(pBuffer, RangeLMN);
// /End dictionary
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary definition
pBuffer += WriteObject(pBuffer, EndArray);
pBuffer += WriteNewLineObject(pBuffer, CieBasedAEnd);
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* GetPS2CSA_ABC
* Function:
* This function creates a CIEBasedABC colorspace array from an input
* RGB profile
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* dwIntent - rendering intent of CSA requested
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* bBackup - TRUE: A CIEBasedDEF has been created, this CSA is a backup
* in case some old printer can not support CIEBasedDEF.
* FALSE: No CIEBasedDEF. This is the only CSA.
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
GetPS2CSA_ABC(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
PBOOL pbBinary,
BOOL bBackup
)
{
PBYTE pStart = pBuffer;
DWORD i, dwPCS, dwDev, dwSize;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
// Check if we can generate the CSA:
// Required tags are red, green and blue Colorants & TRCs
dwPCS = GetCPConnSpace(pProfile);
dwDev = GetCPDevSpace(pProfile);
// Call another function to handle Lab profiles
if (dwDev == SPACE_Lab)
{
return GetPS2CSA_ABC_Lab(pProfile, pBuffer, pcbSize, dwIntent, pbBinary);
}
// We only handle RGB profiles in this function
if ((dwDev != SPACE_RGB) ||
!DoesTRCAndColorantTagExist(pProfile))
{
WARNING((__TEXT("Colorant or TRC tag not present to create ABC CSA\n")));
SetLastError(ERROR_TAG_NOT_PRESENT);
return FALSE;
}
// Estimate size required to hold the CSA
dwSize = 65530;
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get ABC CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
(void)GetMediaWP(pProfile, dwIntent, afxIlluminantWP, afxMediaWP);
// Create global data
pBuffer += WriteNewLineObject(pBuffer, CieBasedABCBegin);
if (IsSRGBColorProfile(pProfile))
{
pBuffer += WriteNewLineObject(pBuffer, sRGBColorSpaceArray);
}
else
{
pBuffer += EnableGlobalDict(pBuffer);
if (bBackup)
{
pBuffer += WriteNewLineObject(pBuffer, NotSupportDEFG_S);
}
pBuffer += BeginGlobalDict(pBuffer);
pBuffer += CreateColSpArray(pProfile, pBuffer, TAG_REDTRC, *pbBinary);
pBuffer += CreateColSpArray(pProfile, pBuffer, TAG_GREENTRC, *pbBinary);
pBuffer += CreateColSpArray(pProfile, pBuffer, TAG_BLUETRC, *pbBinary);
pBuffer += WriteNewLineObject(pBuffer, EndOp);
if (bBackup)
{
pBuffer += WriteNewLineObject(pBuffer, SupportDEFG_E);
}
pBuffer += WriteNewLineObject(pBuffer, SetGlobalOp);
if (bBackup)
{
pBuffer += WriteNewLineObject(pBuffer, NotSupportDEFG_S);
}
// Start creating the ColorSpace
pBuffer += WriteNewLineObject(pBuffer, BeginArray); // Begin array
// /CIEBasedABC
pBuffer += WriteObject(pBuffer, CIEBasedABCTag); // Create entry
pBuffer += WriteObject(pBuffer, BeginDict); // Begin dictionary
// /BlackPoint & /WhitePoint
pBuffer += SendCSABWPoint(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP);
// /DecodeABC
pBuffer += WriteNewLineObject(pBuffer, DecodeABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += CreateColSpProc(pProfile, pBuffer, TAG_REDTRC, *pbBinary);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += CreateColSpProc(pProfile, pBuffer, TAG_GREENTRC, *pbBinary);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += CreateColSpProc(pProfile, pBuffer, TAG_BLUETRC, *pbBinary);
pBuffer += WriteObject(pBuffer, EndArray);
// /MatrixABC
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += CreateFloatString(pProfile, pBuffer, TAG_REDCOLORANT);
pBuffer += CreateFloatString(pProfile, pBuffer, TAG_GREENCOLORANT);
pBuffer += CreateFloatString(pProfile, pBuffer, TAG_BLUECOLORANT);
pBuffer += WriteObject(pBuffer, EndArray);
// /RangeLMN
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, RangeLMNTag);
pBuffer += WriteObject(pBuffer, RangeLMN);
// /DecodeLMN
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
// Support absolute whitePoint
pBuffer += WriteNewLineObject(pBuffer, DecodeLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteFixed(pBuffer, FIX_DIV(afxMediaWP[i], afxIlluminantWP[i]));
pBuffer += WriteObject(pBuffer, MulOp);
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject (pBuffer, EndArray);
}
// End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, EndDict);
pBuffer += WriteObject(pBuffer, EndArray);
pBuffer += WriteNewLineObject(pBuffer, CieBasedABCEnd);
}
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* GetPS2CSA_ABC_Lab
* Function:
* This function creates a CIEBasedABC colorspace array from an input
* Lab profile
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* dwIntent - rendering intent of CSA requested
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
GetPS2CSA_ABC_Lab(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
PBOOL pbBinary
)
{
PBYTE pStart = pBuffer;
DWORD i, dwSize;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
// Estimate size required to hold the CSA
dwSize = 65530;
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get ABC_Lab CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
GetMediaWP(pProfile, dwIntent, afxIlluminantWP, afxMediaWP);
// Start creating the ColorSpace
pBuffer += WriteNewLineObject(pBuffer, BeginArray); // Begin array
// /CIEBasedABC
pBuffer += WriteObject(pBuffer, CIEBasedABCTag); // Create entry
pBuffer += WriteObject(pBuffer, BeginDict); // Begin dictionary
// /BlackPoint & /WhitePoint
pBuffer += SendCSABWPoint(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP);
// /RangeABC
pBuffer += WriteNewLineObject(pBuffer, RangeABCTag);
pBuffer += WriteObject(pBuffer, RangeABC_Lab);
// /DecodeABC
pBuffer += WriteNewLineObject(pBuffer, DecodeABCTag);
pBuffer += WriteObject(pBuffer, DecodeABCLab1);
// /MatrixABC
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
pBuffer += WriteObject(pBuffer, MatrixABCLab);
// /DecodeLMN
pBuffer += WriteNewLineObject(pBuffer, DecodeLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer, DecodeLMNLab);
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
pBuffer += WriteFixed(pBuffer, afxMediaWP[i]);
}
else
{
pBuffer += WriteFixed(pBuffer, afxIlluminantWP[i]);
}
pBuffer += WriteObject(pBuffer, MulOp);
pBuffer += WriteObject(pBuffer, EndFunction);
pBuffer += WriteObject(pBuffer, NewLine);
}
pBuffer += WriteObject(pBuffer, EndArray);
// End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, EndDict);
pBuffer += WriteObject(pBuffer, EndArray);
pBuffer += WriteNewLineObject(pBuffer, CieBasedABCEnd);
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* GetPS2CSA_DEFG
* Function:
* This function creates DEF and DEFG based CSAs from the data supplied
* in the RGB or CMYK profiles respectively
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the CSA
* pcbSize - pointer to size of buffer. If function fails because
* buffer is not big enough, it is filled with required size.
* dwIntent - rendering intent of CSA requested
* dwType - whether DEF CSA or DEFG CSA is required
* pcbBinary - TRUE if binary data is requested. On return it is set to
* reflect the data returned
* Returns:
* TRUE if successful, FALSE otherwise
*/
BOOL
GetPS2CSA_DEFG(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
DWORD dwType,
PBOOL pbBinary
)
{
PLUT16TYPE pLut;
PTAGDATA pTagData;
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
DWORD i, j, k, dwPCS, dwDev, dwIndex, dwTag, dwLutSig, SecondGrids, dwSize;
DWORD nInputCh, nOutputCh, nGrids, nInputTable, nOutputTable, nNumbers;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
char pPublicArrayName[5];
// Make sure required tags exist
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
dwTag = TAG_AToB0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
dwTag = TAG_AToB1;
break;
case INTENT_SATURATION:
dwTag = TAG_AToB2;
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
dwTag = TAG_AToB1;
break;
default:
WARNING((__TEXT("Invalid intent passed to GetPS2CSA_DEFG: %d\n"), dwIntent));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (! DoesCPTagExist(pProfile, dwTag, &dwIndex))
{
WARNING((__TEXT("AToB%d tag not present to create DEF(G) CSA\n"), dwIntent));
SetLastError(ERROR_TAG_NOT_PRESENT);
return FALSE;
}
// Check if we can generate the CSA
// Required tags is AToBi, where i is the rendering intent
dwPCS = GetCPConnSpace(pProfile);
dwDev = GetCPDevSpace(pProfile);
if ((dwType == TYPE_CIEBASEDDEF && dwDev != SPACE_RGB) ||
(dwType == TYPE_CIEBASEDDEFG && dwDev != SPACE_CMYK))
{
WARNING((__TEXT("RGB profile & requesting CMYK CSA or vice versa\n")));
SetLastError(ERROR_TAG_NOT_PRESENT);
return FALSE;
}
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pLut = (PLUT16TYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
dwLutSig = FIX_ENDIAN(pLut->dwSignature);
if (((dwPCS != SPACE_Lab) && (dwPCS != SPACE_XYZ)) ||
((dwLutSig != LUT8_TYPE) && (dwLutSig != LUT16_TYPE)))
{
WARNING((__TEXT("Invalid color space - unable to create DEF(G) CSA\n")));
SetLastError(ERROR_INVALID_PROFILE);
return FALSE;
}
// Estimate size required to hold the CSA
(void)GetCLUTInfo(dwLutSig, (PBYTE)pLut, &nInputCh, &nOutputCh, &nGrids,
&nInputTable, &nOutputTable, NULL);
// Calculate size of buffer needed
if (dwType == TYPE_CIEBASEDDEFG)
{
dwSize = nOutputCh * nGrids * nGrids * nGrids * nGrids * 2;
}
else
{
dwSize = nOutputCh * nGrids * nGrids * nGrids * 2;
}
dwSize = dwSize +
nInputCh * nInputTable * 6 +
nOutputCh * nOutputTable * 6 + // Number of INT bytes
nInputCh * (STRLEN(IndexArray) +
STRLEN(StartClip) +
STRLEN(EndClip)) +
nOutputCh * (STRLEN(IndexArray) +
STRLEN(StartClip) +
STRLEN(EndClip)) +
4096; // + other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get DEFG CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
(void)GetMediaWP(pProfile, dwIntent, afxIlluminantWP, afxMediaWP);
// Testing CieBasedDEFG support
pBuffer += WriteNewLineObject(pBuffer, TestingDEFG);
// Create global data
GetPublicArrayName(dwTag, pPublicArrayName);
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteNewLineObject(pBuffer, CieBasedDEFGBegin);
}
else
{
pBuffer += WriteNewLineObject(pBuffer, CieBasedDEFBegin);
}
pBuffer += EnableGlobalDict(pBuffer);
pBuffer += WriteNewLineObject(pBuffer, SupportDEFG_S);
pBuffer += BeginGlobalDict(pBuffer);
pBuffer += CreateInputArray(pBuffer, nInputCh, nInputTable,
pPublicArrayName, dwLutSig, (PBYTE)pLut, *pbBinary, NULL);
if (dwType == TYPE_CIEBASEDDEFG)
{
i = nInputTable * nInputCh +
nGrids * nGrids * nGrids * nGrids * nOutputCh;
}
else
{
i = nInputTable * nInputCh +
nGrids * nGrids * nGrids * nOutputCh;
}
pBuffer += CreateOutputArray(pBuffer, nOutputCh, nOutputTable, i,
pPublicArrayName, dwLutSig, (PBYTE)pLut, *pbBinary, NULL);
pBuffer += WriteNewLineObject(pBuffer, EndOp);
pBuffer += WriteNewLineObject(pBuffer, SupportDEFG_E);
pBuffer += WriteNewLineObject(pBuffer, SetGlobalOp);
pBuffer += WriteNewLineObject(pBuffer, SupportDEFG_S);
// Start creating the ColorSpace
pBuffer += WriteNewLineObject(pBuffer, BeginArray); // Begin array
// /CIEBasedDEF(G)
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteObject(pBuffer, CIEBasedDEFGTag);
}
else
{
pBuffer += WriteObject(pBuffer, CIEBasedDEFTag);
}
pBuffer += WriteObject(pBuffer, BeginDict); // Begin dictionary
// /BlackPoint & /WhitePoint
pBuffer += SendCSABWPoint(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP);
// /DecodeDEF(G)
pLineStart = pBuffer;
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteNewLineObject(pBuffer, DecodeDEFGTag);
}
else
{
pBuffer += WriteNewLineObject(pBuffer, DecodeDEFTag);
}
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nInputCh; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer, StartClip);
pBuffer += WriteObject(pBuffer, InputArray);
pBuffer += WriteObject(pBuffer, pPublicArrayName);
pBuffer += WriteInt(pBuffer, i);
if (! *pbBinary) // Output ASCII
{
pBuffer += WriteObject(pBuffer, IndexArray);
}
else
{ // Output BINARY
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, IndexArray);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray16b);
}
}
pBuffer += WriteObject(pBuffer, (dwLutSig == LUT8_TYPE) ? Scale8 : Scale16);
pBuffer += WriteObject(pBuffer, EndClip);
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
// /Table
pBuffer += WriteNewLineObject(pBuffer, TableTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteInt(pBuffer, nGrids); // Send down Nh
pBuffer += WriteInt(pBuffer, nGrids); // Send down Ni
pBuffer += WriteInt(pBuffer, nGrids); // Send down Nj
nNumbers = nGrids * nGrids * nOutputCh;
SecondGrids = 1;
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteInt (pBuffer, nGrids); // Send down Nk
SecondGrids = nGrids;
}
pBuffer += WriteNewLineObject(pBuffer, BeginArray);
for (i=0; i<nGrids; i++) // Nh strings should be sent
{
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteNewLineObject(pBuffer, BeginArray);
}
for (k=0; k<SecondGrids; k++)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE)(((PLUT8TYPE)pLut)->data) +
nInputTable * nInputCh +
nNumbers * (i * SecondGrids + k);
}
else
{
pTable = (PBYTE)(((PLUT16TYPE)pLut)->data) +
2 * nInputTable * nInputCh +
2 * nNumbers * (i * SecondGrids + k);
}
if (! *pbBinary) // Output ASCII
{
pBuffer += WriteObject(pBuffer, BeginString);
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteHexBuffer(pBuffer, pTable, pLineStart, nNumbers);
}
else
{
for (j=0; j<nNumbers; j++)
{
pBuffer += WriteHex(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)) / 256);
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
}
pBuffer += WriteObject(pBuffer, EndString);
}
else
{ // Output BINARY
pBuffer += WriteStringToken(pBuffer, 143, nNumbers);
if (dwLutSig == LUT8_TYPE)
pBuffer += WriteByteString(pBuffer, pTable, nNumbers);
else
pBuffer += WriteInt2ByteString(pBuffer, pTable, nNumbers);
}
pBuffer += WriteObject (pBuffer, NewLine);
}
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteObject(pBuffer, EndArray);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
pBuffer += WriteObject(pBuffer, EndArray); // End array
// /DecodeABC
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, DecodeABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nOutputCh; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer, Clip01);
pBuffer += WriteObject(pBuffer, OutputArray);
pBuffer += WriteObject(pBuffer, pPublicArrayName);
pBuffer += WriteInt(pBuffer, i);
if (! *pbBinary)
{
pBuffer += WriteObject(pBuffer, NewLine);
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, TFunction8XYZ);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray);
pBuffer += WriteObject(pBuffer, Scale16XYZ);
}
}
else
{
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, TFunction8XYZ);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray16b);
pBuffer += WriteObject(pBuffer, Scale16XYZ);
}
}
// Now, We get CieBasedXYZ output. Output range 0 --> 1.99997
// If the connection space is absolute XYZ, We need to convert
// from relative XYZ to absolute XYZ.
if ((dwPCS == SPACE_XYZ) && (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC))
{
pBuffer += WriteFixed(pBuffer, FIX_DIV(afxMediaWP[i], afxIlluminantWP[i]));
pBuffer += WriteObject(pBuffer, MulOp);
}
else if (dwPCS == SPACE_Lab)
{
// If the connection space is Lab, We need to convert XYZ to Lab
pBuffer += WriteObject(pBuffer, DecodeABCLab[i]);
}
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
if (dwPCS == SPACE_Lab)
{
// /MatrixABC
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
pBuffer += WriteObject(pBuffer, MatrixABCLab);
// /DecodeLMN
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, DecodeLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer, DecodeLMNLab);
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
pBuffer += WriteFixed(pBuffer, afxMediaWP[i]);
}
else
{
pBuffer += WriteFixed(pBuffer, afxIlluminantWP[i]);
}
pBuffer += WriteObject(pBuffer, MulOp);
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
}
else
{
// /RangeLMN
pBuffer += WriteNewLineObject(pBuffer, RangeLMNTag);
pBuffer += WriteObject(pBuffer, RangeLMN);
}
// End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, EndDict);
pBuffer += WriteObject(pBuffer, EndArray);
if (dwType == TYPE_CIEBASEDDEFG)
{
pBuffer += WriteNewLineObject(pBuffer, CieBasedDEFGEnd);
}
else
{
pBuffer += WriteNewLineObject(pBuffer, CieBasedDEFEnd);
}
pBuffer += WriteNewLineObject(pBuffer, SupportDEFG_E);
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
BOOL
InternalGetPS2CSAFromLCS(
LPLOGCOLORSPACE pLogColorSpace,
PBYTE pBuffer,
PDWORD pcbSize,
PBOOL pbBinary
)
{
PBYTE pStart = pBuffer;
DWORD dwSize = 1024*2; // same value as in pscript/icm.c
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get CSA from LCS\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, BeginArray); // Begin array
pBuffer += WriteObject(pBuffer, ColorSpace1);
pBuffer += WriteObject(pBuffer, BeginArray); // [
// Red gamma
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteFixed(pBuffer, pLogColorSpace->lcsGammaRed);
pBuffer += WriteObject(pBuffer, ColorSpace3);
// Green gamma
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteFixed(pBuffer, pLogColorSpace->lcsGammaGreen);
pBuffer += WriteObject(pBuffer, ColorSpace3);
// Blue Gamma
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteFixed(pBuffer, pLogColorSpace->lcsGammaBlue);
pBuffer += WriteObject(pBuffer, ColorSpace3);
pBuffer += WriteObject(pBuffer, EndArray); // ]
pBuffer += WriteObject(pBuffer, ColorSpace5); // /WhitePoint
// Matrix LMN
pBuffer += WriteObject(pBuffer, MatrixLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
// Red Value
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzRed.ciexyzX);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzRed.ciexyzY);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzRed.ciexyzZ);
// Green Value
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzGreen.ciexyzX);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzGreen.ciexyzY);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzGreen.ciexyzZ);
// Blue Value
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzBlue.ciexyzX);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzBlue.ciexyzY);
pBuffer += WriteFixed2dot30(pBuffer, pLogColorSpace->lcsEndpoints.ciexyzBlue.ciexyzZ);
pBuffer += WriteObject(pBuffer, EndArray); // ]
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary
pBuffer += WriteObject(pBuffer, EndArray); // ]
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* CreateColorSpArray
* Function:
* This function creates an array that is used in /DecodeABC
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the array
* dwCPTag - Channel TRC tag
* bBinary - TRUE if binary data is requested
* Returns:
* Length of the data created in bytes
*/
DWORD
CreateColSpArray(
PBYTE pProfile,
PBYTE pBuffer,
DWORD dwCPTag,
BOOL bBinary
)
{
PCURVETYPE pData;
PTAGDATA pTagData;
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
DWORD i, nCount, dwIndex;
pLineStart = pBuffer;
if (DoesCPTagExist(pProfile, dwCPTag, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
nCount = FIX_ENDIAN(pData->nCount);
if (nCount > 1)
{
pBuffer += WriteNewLineObject(pBuffer, Slash);
pBuffer += WriteObject(pBuffer, DecodeABCArray);
pBuffer += WriteInt(pBuffer, dwCPTag);
pTable = (PBYTE)(pData->data);
if (! bBinary) // Output ASCII CS
{
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nCount; i++)
{
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
}
else
{ // Output BINARY CS
pBuffer += WriteHNAToken(pBuffer, 149, nCount);
pBuffer += WriteIntStringU2S(pBuffer, pTable, nCount);
}
pBuffer += WriteObject(pBuffer, DefOp);
}
}
return (DWORD) (pBuffer - pStart);
}
/*
* CreateColorSpProc
* Function:
* This function creates a PostScript procedure for the color space
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the procedure
* dwCPTag - Channel TRC tag
* bBinary - TRUE if binary data is requested
* Returns:
* Length of the data created in bytes
*/
DWORD
CreateColSpProc(
PBYTE pProfile,
PBYTE pBuffer,
DWORD dwCPTag,
BOOL bBinary
)
{
PCURVETYPE pData;
PTAGDATA pTagData;
PBYTE pStart = pBuffer;
PBYTE pTable;
DWORD nCount, dwIndex;
pBuffer += WriteObject(pBuffer, BeginFunction);
if (DoesCPTagExist(pProfile, dwCPTag, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
nCount = FIX_ENDIAN(pData->nCount);
if (nCount != 0)
{
if (nCount == 1) // Gamma supplied in ui16 format
{
pTable = (PBYTE)(pData->data);
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pBuffer += WriteObject(pBuffer, DecodeA3);
}
else
{
pBuffer += WriteObject(pBuffer, StartClip);
pBuffer += WriteObject(pBuffer, DecodeABCArray);
pBuffer += WriteInt(pBuffer, dwCPTag);
if (! bBinary) // Output ASCII CS
{
pBuffer += WriteObject(pBuffer, IndexArray);
}
else
{ // Output BINARY CS
pBuffer += WriteObject(pBuffer, IndexArray16b);
}
pBuffer += WriteObject(pBuffer, Scale16);
pBuffer += WriteObject(pBuffer, EndClip);
}
}
}
pBuffer += WriteObject(pBuffer, EndFunction);
return (DWORD) (pBuffer - pStart);
}
/*
* CreateFloatString
* Function:
* This function creates a string of floating point numbers for
* the X, Y and Z values of the specified colorant.
* Arguments:
* pProfile - pointer to the memory mapped profile
* pBuffer - pointer to receive the string
* dwCPTag - Colorant tag
* Returns:
* Length of the data created in bytes
*/
DWORD
CreateFloatString(
PBYTE pProfile,
PBYTE pBuffer,
DWORD dwCPTag
)
{
PTAGDATA pTagData;
PBYTE pStart = pBuffer;
PDWORD pTable;
DWORD i, dwIndex;
if (DoesCPTagExist(pProfile, dwCPTag, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pTable = (PDWORD)(pProfile + FIX_ENDIAN(pTagData->dwOffset)) + 2;
for (i=0; i<3; i++)
{
pBuffer += WriteFixed(pBuffer, FIX_ENDIAN(*pTable));
pTable ++;
}
}
return (DWORD) (pBuffer - pStart);
}
/*
* CreateInputArray
* Function:
* This function creates the Color Rendering Dictionary (CRD)
* from the data supplied in the ColorProfile's LUT8 or LUT16 tag.
* Arguments:
* pBuffer - pointer to receive the data
* nInputChannels - number of input channels
* nInputTable - size of input table
* pIntent - rendering intent signature (eg. A2B0)
* dwTag - signature of the look up table (8 or 16 bits)
* pLut - pointer to the look up table
* bBinary - TRUE if binary data is requested
* Returns:
* Length of the data created in bytes
*/
DWORD
CreateInputArray(
PBYTE pBuffer,
DWORD nInputChannels,
DWORD nInputTable,
PBYTE pIntent,
DWORD dwTag,
PBYTE pLut,
BOOL bBinary,
PBYTE pHostClut
)
{
DWORD i, j;
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
if (pHostClut)
{
nInputChannels = ((PHOSTCLUT)pHostClut)->nInputCh;
nInputTable = ((PHOSTCLUT)pHostClut)->nInputEntries;
dwTag = ((PHOSTCLUT)pHostClut)->nLutBits == 8 ? LUT8_TYPE : LUT16_TYPE;
}
for (i=0; i<nInputChannels; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, Slash);
if (pHostClut)
pBuffer += WriteObject(pBuffer, PreViewInArray);
else
pBuffer += WriteObject(pBuffer, InputArray);
pBuffer += WriteObject(pBuffer, pIntent);
pBuffer += WriteInt(pBuffer, i);
if (pHostClut)
{
pTable = ((PHOSTCLUT)pHostClut)->inputArray[i];
}
else
{
if (dwTag == LUT8_TYPE)
{
pTable = (PBYTE)(((PLUT8TYPE)pLut)->data) + nInputTable * i;
}
else
{
pTable = (PBYTE)(((PLUT16TYPE)pLut)->data) + 2 * nInputTable * i;
}
}
if (! bBinary)
{
if (dwTag == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, BeginString);
pBuffer += WriteHexBuffer(pBuffer, pTable, pLineStart, nInputTable);
pBuffer += WriteObject(pBuffer, EndString);
}
else
{
pBuffer += WriteObject(pBuffer, BeginArray);
for (j=0; j<nInputTable; j++)
{
if (pHostClut)
pBuffer += WriteInt(pBuffer, *((PWORD)pTable));
else
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
}
}
else
{
if (dwTag == LUT8_TYPE)
{
pBuffer += WriteStringToken(pBuffer, 143, nInputTable);
pBuffer += WriteByteString(pBuffer, pTable, nInputTable);
}
else
{
pBuffer += WriteHNAToken(pBuffer, 149, nInputTable);
if (pHostClut)
pBuffer += WriteIntStringU2S_L(pBuffer, pTable, nInputTable);
else
pBuffer += WriteIntStringU2S(pBuffer, pTable, nInputTable);
}
}
pBuffer += WriteObject(pBuffer, DefOp);
}
return (DWORD) (pBuffer - pStart);
}
/*
* CreateOutputArray
* Function:
* This function creates the Color Rendering Dictionary (CRD)
* from the data supplied in the ColorProfile's LUT8 or LUT16 tag.
* Arguments:
* pBuffer - pointer to receive the data
* nOutputChannels- number of output channels
* nOutputTable - size of output table
* dwOffset - offset into the output table
* pIntent - rendering intent signature (eg. A2B0)
* dwTag - signature of the look up table (8 or 16 bits)
* pLut - pointer to the look up table
* bBinary - TRUE if binary data is requested
* Returns:
* Length of the data created in bytes
*/
DWORD
CreateOutputArray(
PBYTE pBuffer,
DWORD nOutputChannels,
DWORD nOutputTable,
DWORD dwOffset,
PBYTE pIntent,
DWORD dwTag,
PBYTE pLut,
BOOL bBinary,
PBYTE pHostClut
)
{
DWORD i, j;
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
if (pHostClut)
{
nOutputChannels = ((PHOSTCLUT)pHostClut)->nOutputCh;
nOutputTable = ((PHOSTCLUT)pHostClut)->nOutputEntries;
dwTag = ((PHOSTCLUT)pHostClut)->nLutBits == 8 ? LUT8_TYPE : LUT16_TYPE;
}
for (i=0; i<nOutputChannels; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, Slash);
if (pHostClut)
pBuffer += WriteObject(pBuffer, PreViewOutArray);
else
pBuffer += WriteObject(pBuffer, OutputArray);
pBuffer += WriteObject(pBuffer, pIntent);
pBuffer += WriteInt(pBuffer, i);
if (pHostClut)
{
pTable = ((PHOSTCLUT)pHostClut)->outputArray[i];
}
else
{
if (dwTag == LUT8_TYPE)
{
pTable = (PBYTE)(((PLUT8TYPE)pLut)->data) +
dwOffset + nOutputTable * i;
}
else
{
pTable = (PBYTE)(((PLUT16TYPE)pLut)->data) +
2 * dwOffset + 2 * nOutputTable * i;
}
}
if (! bBinary)
{
if (dwTag == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, BeginString);
pBuffer += WriteHexBuffer(pBuffer, pTable, pLineStart, nOutputTable);
pBuffer += WriteObject(pBuffer, EndString);
}
else
{
pBuffer += WriteObject(pBuffer, BeginArray);
for (j=0; j<nOutputTable; j++)
{
if (pHostClut)
pBuffer += WriteInt(pBuffer, *((PWORD)pTable));
else
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
}
}
else
{
if (dwTag == LUT8_TYPE)
{
pBuffer += WriteStringToken(pBuffer, 143, 256);
pBuffer += WriteByteString(pBuffer, pTable, 256L);
}
else
{
pBuffer += WriteHNAToken(pBuffer, 149, nOutputTable);
if (pHostClut)
pBuffer += WriteIntStringU2S_L(pBuffer, pTable, nOutputTable);
else
pBuffer += WriteIntStringU2S(pBuffer, pTable, nOutputTable);
}
}
pBuffer += WriteObject(pBuffer, DefOp);
}
return (DWORD)(pBuffer - pStart);
}
/*
* GetPublicArrayName
* Function:
* This function creates a string with the lookup table's signature
* Arguments:
* dwIntentSig - the look up table signature
* pPublicArrayName - pointer to buffer
* Returns:
* Length of the data created in bytes
*/
DWORD
GetPublicArrayName(
DWORD dwIntentSig,
PBYTE pPublicArrayName
)
{
*((DWORD *)pPublicArrayName) = dwIntentSig;
pPublicArrayName[sizeof(DWORD)] = '\0';
return sizeof(DWORD) + 1;
}
/*
* CreateMonoCRD
* function:
* this is the function which creates the Color Rendering Dictionary (CRD)
* from the data supplied in the GrayTRC tag.
* returns:
* BOOL -- !=0 if the function was successful,
* 0 otherwise.
* Returns number of bytes required/transferred
*/
BOOL
CreateMonoCRD(
PBYTE pProfile,
DWORD dwIndex,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent
)
{
PTAGDATA pTagData;
PCURVETYPE pData;
PBYTE pLineStart, pStart = pBuffer;
PWORD pCurve, pRevCurve, pRevCurveStart;
DWORD dwPCS, dwSize, nCount, i;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
dwPCS = GetCPConnSpace(pProfile);
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
nCount = FIX_ENDIAN(pData->nCount);
// Estimate size required to hold the CRD
dwSize = nCount * 6 * REVCURVE_RATIO + // Number of INT elements
2048; // + other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get Mono CRD\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Allocate memory, each entry occupy 2 bytes (1 word),
// input buffer = (nCount * sizeof(WORD)
// output buffer = (nCount * sizeof(WORD) * REVCURVE_RATIO)
if ((pRevCurveStart = MemAlloc(nCount * sizeof(WORD) * (REVCURVE_RATIO + 1))) == NULL)
{
WARNING((__TEXT("Unable to allocate memory for reverse curve\n")));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
// pCurve will points input buffer (which used in GetRevCurve)
pCurve = pRevCurveStart + nCount * REVCURVE_RATIO;
pRevCurve = pRevCurveStart;
(void)GetRevCurve(pData, pCurve, pRevCurve);
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
if (! GetCPMediaWhitePoint(pProfile, afxMediaWP))
{
afxMediaWP[0] = afxIlluminantWP[0];
afxMediaWP[1] = afxIlluminantWP[1];
afxMediaWP[2] = afxIlluminantWP[2];
}
}
// Start writing the CRD
pBuffer += WriteNewLineObject(pBuffer, BeginDict); // Begin dictionary
pBuffer += WriteObject(pBuffer, DictType); // Dictionary type
// Send /RenderingIntent
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentPer);
break;
case INTENT_SATURATION:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentSat);
break;
case INTENT_RELATIVE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentRCol);
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentACol);
break;
}
// Send /BlackPoint & /WhitePoint
pBuffer += SendCRDBWPoint(pBuffer, afxIlluminantWP);
// Send PQR
pBuffer += SendCRDPQR(pBuffer, dwIntent, afxIlluminantWP);
// Send LMN
pBuffer += SendCRDLMN(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP, dwPCS);
// /MatrixABC
if (dwPCS == SPACE_XYZ)
{
// Switch ABC to BAC, since we want to output B
// which is converted from Y
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
pBuffer += WriteObject(pBuffer, MatrixABCXYZCRD);
}
else if (dwPCS == SPACE_Lab)
{
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
pBuffer += WriteObject(pBuffer, MatrixABCLabCRD);
}
// /EncodeABC
if (nCount != 0)
{
pBuffer += WriteObject(pBuffer, NewLine);
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, EncodeABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteObject(pBuffer, BeginFunction);
if (nCount == 1) // Gamma supplied in ui16 format
{
PBYTE pTable;
pTable = (PBYTE) (pData->data);
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)));
pBuffer += WriteObject(pBuffer, DecodeA3Rev);
}
else
{
if (dwPCS == SPACE_Lab)
{
pBuffer += WriteObject(pBuffer, EncodeABCLab1);
}
pBuffer += WriteObject(pBuffer, StartClip);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nCount * REVCURVE_RATIO; i++)
{
pBuffer += WriteInt(pBuffer, *((WORD *)pRevCurve));
pRevCurve++;
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, IndexArray);
pBuffer += WriteObject(pBuffer, Scale16);
pBuffer += WriteObject(pBuffer, EndClip);
}
pBuffer += WriteObject (pBuffer, EndFunction);
pBuffer += WriteObject (pBuffer, DupOp);
pBuffer += WriteObject (pBuffer, DupOp);
pBuffer += WriteObject (pBuffer, EndArray);
}
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary definition
MemFree(pRevCurveStart);
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* CreateLutCRD
* function:
* this is the function which creates the Color Rendering Dictionary (CRD)
* from the data supplied in the ColorProfile's LUT8 or LUT16 tag.
* returns:
* BOOL -- !=0 if the function was successful,
* 0 otherwise.
* Returns number of bytes required/transferred
*/
BOOL
CreateLutCRD(
PBYTE pProfile,
DWORD dwIndex,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
BOOL bBinary
)
{
PTAGDATA pTagData;
PLUT16TYPE pLut;
PBYTE pTable;
PBYTE pLineStart, pStart = pBuffer;
DWORD dwPCS, dwSize, dwLutSig, dwTag, i, j;
DWORD nInputCh, nOutputCh, nGrids, nInputTable, nOutputTable, nNumbers;
FIX_16_16 afxIlluminantWP[3];
FIX_16_16 afxMediaWP[3];
char pPublicArrayName[5];
// Check if we can generate the CSA
// Required tags is AToBi, where i is the rendering intent
dwPCS = GetCPConnSpace(pProfile);
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
dwTag = FIX_ENDIAN(pTagData->tagType);
pLut = (PLUT16TYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
dwLutSig = FIX_ENDIAN(pLut->dwSignature);
if ((dwLutSig != LUT8_TYPE) && (dwLutSig != LUT16_TYPE))
{
WARNING((__TEXT("Invalid profile - unable to create Lut CRD\n")));
SetLastError(ERROR_INVALID_PROFILE);
return FALSE;
}
// Estimate size required to hold the CSA
(void)GetCLUTInfo(dwLutSig, (PBYTE)pLut, &nInputCh, &nOutputCh, &nGrids,
&nInputTable, &nOutputTable, NULL);
// Calculate size of buffer needed
dwSize = nInputCh * nInputTable * 6 +
nOutputCh * nOutputTable * 6 + // Number of INT bytes
nOutputCh * nGrids * nGrids * nGrids * 2 + // LUT HEX bytes
nInputCh * (STRLEN(IndexArray) +
STRLEN(StartClip) +
STRLEN(EndClip)) +
nOutputCh * (STRLEN(IndexArray) +
STRLEN(StartClip) +
STRLEN(EndClip)) +
2048; // + other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
else if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get DEFG CSA\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Support absolute whitePoint
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
if (! GetCPMediaWhitePoint(pProfile, afxMediaWP))
{
afxMediaWP[0] = afxIlluminantWP[0];
afxMediaWP[1] = afxIlluminantWP[1];
afxMediaWP[2] = afxIlluminantWP[2];
}
}
// Define global array used in EncodeABC and RenderTable
GetPublicArrayName(dwTag, pPublicArrayName);
pBuffer += WriteNewLineObject(pBuffer, CRDBegin);
pBuffer += EnableGlobalDict(pBuffer);
pBuffer += BeginGlobalDict(pBuffer);
pBuffer += CreateInputArray(pBuffer, nInputCh, nInputTable,
pPublicArrayName, dwLutSig, (PBYTE)pLut, bBinary, NULL);
i = nInputTable * nInputCh +
nGrids * nGrids * nGrids * nOutputCh;
pBuffer += CreateOutputArray(pBuffer, nOutputCh, nOutputTable, i,
pPublicArrayName, dwLutSig, (PBYTE)pLut, bBinary, NULL);
pBuffer += EndGlobalDict(pBuffer);
// Start writing the CRD
pBuffer += WriteNewLineObject(pBuffer, BeginDict); // Begin dictionary
pBuffer += WriteObject(pBuffer, DictType); // Dictionary type
// Send /RenderingIntent
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentPer);
break;
case INTENT_SATURATION:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentSat);
break;
case INTENT_RELATIVE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentRCol);
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentACol);
break;
}
// Send /BlackPoint & /WhitePoint
pBuffer += SendCRDBWPoint(pBuffer, afxIlluminantWP);
// Send PQR
pBuffer += SendCRDPQR(pBuffer, dwIntent, afxIlluminantWP);
// Send LMN
pBuffer += SendCRDLMN(pBuffer, dwIntent, afxIlluminantWP, afxMediaWP, dwPCS);
// Send ABC
pBuffer += SendCRDABC(pBuffer, pPublicArrayName, dwPCS, nInputCh,
(PBYTE)pLut, NULL, dwLutSig, bBinary);
// /RenderTable
pBuffer += WriteNewLineObject(pBuffer, RenderTableTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteInt(pBuffer, nGrids); // Send down Na
pBuffer += WriteInt(pBuffer, nGrids); // Send down Nb
pBuffer += WriteInt(pBuffer, nGrids); // Send down Nc
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginArray);
nNumbers = nGrids * nGrids * nOutputCh;
for (i=0; i<nGrids; i++) // Na strings should be sent
{
pBuffer += WriteObject(pBuffer, NewLine);
pLineStart = pBuffer;
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE)(((PLUT8TYPE)pLut)->data) + nInputTable * nInputCh + nNumbers * i;
}
else
{
pTable = (PBYTE)(((PLUT16TYPE)pLut)->data) + 2 * nInputTable * nInputCh + 2 * nNumbers * i;
}
if (! bBinary)
{
pBuffer += WriteObject(pBuffer, BeginString);
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteHexBuffer(pBuffer, pTable, pLineStart, nNumbers);
}
else
{
for (j=0; j<nNumbers; j++)
{
pBuffer += WriteHex(pBuffer, FIX_ENDIAN16(*((PWORD)pTable)) / 256);
pTable += sizeof(WORD);
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
}
pBuffer += WriteObject(pBuffer, EndString);
}
else
{
pBuffer += WriteStringToken(pBuffer, 143, nNumbers);
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteByteString(pBuffer, pTable, nNumbers);
}
else
{
pBuffer += WriteInt2ByteString(pBuffer, pTable, nNumbers);
}
}
}
pBuffer += WriteObject(pBuffer, EndArray); // End array
pBuffer += WriteInt(pBuffer, nOutputCh); // Send down m
pBuffer += SendCRDOutputTable(pBuffer, pPublicArrayName,
nOutputCh, dwLutSig, FALSE, bBinary);
pBuffer += WriteObject(pBuffer, EndArray); // End array
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, CRDEnd);
*pcbSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* CreateMatrixCRD
* function:
* this is the function which creates the Color Rendering Dictionary (CRD)
* from the data supplied in the redTRC, greenTRC, blueTRA, redColorant,
* greenColorant and BlueColorant tags
* returns:
* BOOL -- !=0 if the function was successful,
* 0 otherwise.
* Returns number of bytes required/transferred
*/
// With matrix/TRC model, only the CIEXYZ encoding of the PCS can be used.
// So, we don't need to worry about CIELAB.
BOOL
CreateMatrixCRD(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
BOOL bBinary
)
{
PTAGDATA pTagData;
DWORD dwRedTRCIndex, dwGreenTRCIndex, dwBlueTRCIndex;
DWORD dwRedCount, dwGreenCount, dwBlueCount;
PBYTE pMem = NULL;
PCURVETYPE pRed, pGreen, pBlue;
DWORD i, dwSize;
PBYTE pStart = pBuffer;
PWORD pRevCurve;
FIX_16_16 afxIlluminantWP[3];
double adColorant[9];
double adRevColorant[9];
// Check this is sRGB color profile or not.
if (IsSRGBColorProfile(pProfile))
{
dwSize = 4096; // hack - approx.
// Return buffer size, if this is a size request
if (! pBuffer)
{
*pcbSize = dwSize;
return TRUE;
}
// Check buffer size.
if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get sRGB CRD\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Start writing the CRD
pBuffer += WriteNewLineObject(pBuffer, CRDBegin);
pBuffer += WriteNewLineObject(pBuffer, BeginDict); // Begin dictionary
pBuffer += WriteObject(pBuffer, DictType); // Dictionary type
// Send /RenderingIntent
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentPer);
break;
case INTENT_SATURATION:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentSat);
break;
case INTENT_RELATIVE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentRCol);
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentACol);
break;
}
// Write prepaired sRGB CRD.
pBuffer += WriteNewLineObject(pBuffer, sRGBColorRenderingDictionary);
// End CRD.
pBuffer += WriteNewLineObject(pBuffer, CRDEnd);
}
else
{
// Get each TRC index for Red, Green and Blue.
if (!DoesCPTagExist(pProfile, TAG_REDTRC, &dwRedTRCIndex) ||
!DoesCPTagExist(pProfile, TAG_GREENTRC, &dwGreenTRCIndex) ||
!DoesCPTagExist(pProfile, TAG_BLUETRC, &dwBlueTRCIndex))
{
return FALSE;
}
// Get CURVETYPE data for each Red, Green and Blue
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwRedTRCIndex * sizeof(TAGDATA));
pRed = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwGreenTRCIndex * sizeof(TAGDATA));
pGreen = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwBlueTRCIndex * sizeof(TAGDATA));
pBlue = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
// Get curve count for each Red, Green and Blue.
dwRedCount = FIX_ENDIAN(pRed->nCount);
dwGreenCount = FIX_ENDIAN(pGreen->nCount);
dwBlueCount = FIX_ENDIAN(pBlue->nCount);
// Estimate the memory size required to hold CRD
dwSize = (dwRedCount + dwGreenCount + dwBlueCount) * 6 * REVCURVE_RATIO +
4096; // Number of INT elements + other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (pBuffer == NULL) // This is a size request
{
*pcbSize = dwSize;
return TRUE;
}
// Check buffer size.
if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get sRGB CRD\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Allocate buffer for curves
if ((pRevCurve = MemAlloc(dwRedCount * sizeof(WORD) * (REVCURVE_RATIO + 1))) == NULL)
{
WARNING((__TEXT("Unable to allocate memory for reserved curve\n")));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
MemFree(pMem);
return FALSE;
}
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, afxIlluminantWP);
// Start writing the CRD
pBuffer += EnableGlobalDict(pBuffer);
pBuffer += BeginGlobalDict(pBuffer);
pBuffer += CreateCRDRevArray(pProfile, pBuffer, pRed, pRevCurve, TAG_REDTRC, bBinary);
pBuffer += CreateCRDRevArray(pProfile, pBuffer, pGreen, pRevCurve, TAG_GREENTRC, bBinary);
pBuffer += CreateCRDRevArray(pProfile, pBuffer, pBlue, pRevCurve, TAG_BLUETRC, bBinary);
pBuffer += EndGlobalDict(pBuffer);
// Start writing the CRD
pBuffer += WriteNewLineObject(pBuffer, CRDBegin);
pBuffer += WriteNewLineObject(pBuffer, BeginDict); // Begin dictionary
pBuffer += WriteObject(pBuffer, DictType); // Dictionary type
// Send /RenderingIntent
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentPer);
break;
case INTENT_SATURATION:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentSat);
break;
case INTENT_RELATIVE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentRCol);
break;
case INTENT_ABSOLUTE_COLORIMETRIC:
pBuffer += WriteNewLineObject(pBuffer, IntentType);
pBuffer += WriteObject(pBuffer, IntentACol);
break;
}
// Send /BlackPoint & /WhitePoint
pBuffer += SendCRDBWPoint(pBuffer, afxIlluminantWP);
// Send PQR
pBuffer += SendCRDPQR(pBuffer, dwIntent, afxIlluminantWP);
// Send LMN
CreateColorantArray(pProfile, &adColorant[0], TAG_REDCOLORANT);
CreateColorantArray(pProfile, &adColorant[3], TAG_GREENCOLORANT);
CreateColorantArray(pProfile, &adColorant[6], TAG_BLUECOLORANT);
InvertColorantArray(adColorant, adRevColorant);
pBuffer += WriteNewLineObject(pBuffer, MatrixLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i = 0; i < 9; i++)
{
pBuffer += WriteDouble(pBuffer, adRevColorant[i]);
}
pBuffer += WriteObject(pBuffer, EndArray);
// /EncodeABC
pBuffer += WriteNewLineObject(pBuffer, EncodeABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += SendCRDRevArray(pProfile, pBuffer, pRed, TAG_REDTRC, bBinary);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += SendCRDRevArray(pProfile, pBuffer, pGreen, TAG_GREENTRC, bBinary);
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += SendCRDRevArray(pProfile, pBuffer, pBlue, TAG_BLUETRC, bBinary);
pBuffer += WriteNewLineObject(pBuffer, EndArray);
pBuffer += WriteObject(pBuffer, EndDict); // End dictionary definition
pBuffer += WriteNewLineObject(pBuffer, CRDEnd);
MemFree (pRevCurve);
}
*pcbSize = (DWORD)(pBuffer - pStart);
return TRUE;
}
DWORD
CreateCRDRevArray(
PBYTE pProfile,
PBYTE pBuffer,
PCURVETYPE pData,
PWORD pRevCurve,
DWORD dwTag,
BOOL bBinary
)
{
DWORD i, nCount;
PBYTE pStart, pLineStart;
PWORD pCurve;
pStart = pBuffer;
pLineStart = pBuffer;
nCount = FIX_ENDIAN(pData->nCount);
if (nCount > 1)
{
pBuffer += WriteNewLineObject(pBuffer, Slash);
pBuffer += WriteObject(pBuffer, InputArray);
pBuffer += WriteInt(pBuffer, (INT) dwTag);
pCurve = pRevCurve + (REVCURVE_RATIO * nCount);
GetRevCurve (pData, pCurve, pRevCurve);
if (!bBinary) // Output ASCII DATA
{
pBuffer += WriteObject(pBuffer, BeginArray);
for (i = 0; i < nCount * REVCURVE_RATIO; i++)
{
pBuffer += WriteInt(pBuffer, *pRevCurve);
pRevCurve++;
if (((DWORD) (pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
}
else // Output BINARY DATA
{
pBuffer += WriteHNAToken(pBuffer, 149, nCount);
pBuffer += WriteIntStringU2S_L(pBuffer, (PBYTE) pRevCurve, nCount);
}
pBuffer += WriteObject(pBuffer, DefOp);
}
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDRevArray(
PBYTE pProfile,
PBYTE pBuffer,
PCURVETYPE pData,
DWORD dwTag,
BOOL bBinary
)
{
DWORD nCount;
PBYTE pStart;
PWORD pTable;
pStart = pBuffer;
pBuffer += WriteObject(pBuffer, BeginFunction);
nCount = FIX_ENDIAN(pData->nCount);
if (nCount != 0)
{
if (nCount == 1) // Gamma supplied in ui16 format
{
pTable = pData->data;
pBuffer += WriteInt(pBuffer, FIX_ENDIAN16(*pTable));
pBuffer += WriteObject(pBuffer, DecodeA3Rev);
}
else
{
pBuffer += WriteObject(pBuffer, StartClip);
pBuffer += WriteObject(pBuffer, InputArray);
pBuffer += WriteInt(pBuffer, dwTag);
if (!bBinary) // Output ASCII CS
{
pBuffer += WriteObject(pBuffer, IndexArray);
}
else // Output BINARY CS
{
pBuffer += WriteObject(pBuffer, IndexArray16b);
}
pBuffer += WriteObject(pBuffer, Scale16);
pBuffer += WriteObject(pBuffer, EndClip);
}
}
pBuffer += WriteObject(pBuffer, EndFunction);
return (DWORD)(pBuffer - pStart);
}
BOOL
CreateColorantArray(
PBYTE pProfile,
double *lpArray,
DWORD dwTag
)
{
PTAGDATA pTagData;
PXYZTYPE pData;
PFIX_16_16 pTable;
DWORD i, dwIndex;
BYTE buffer[1000];
if (DoesCPTagExist(pProfile, dwTag, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = (PXYZTYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
pTable = pData->afxData;
for (i = 0; i < 3; i++)
{
FIX_16_16 afxData = FIX_ENDIAN(*pTable);
// Convert Fix 16.16 to double.
*lpArray = ((double) afxData) / ((double) FIX_16_16_SCALE);
pTable++; lpArray++;
}
return (TRUE);
}
return (FALSE);
}
#endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* GetRevCurve
* function:
* returns:
* BOOL -- TRUE: successful,
* FALSE: otherwise.
*/
BOOL
GetRevCurve(
PCURVETYPE pData,
PWORD pInput,
PWORD pOutput
)
{
PBYTE pTable;
DWORD nCount, dwStore, i, j;
DWORD dwBegin, dwEnd, dwTemp;
nCount = FIX_ENDIAN(pData->nCount);
pTable = (PBYTE)pData->data;
for (i=0; i<nCount; i++)
{
pInput[i] = FIX_ENDIAN16(*((PWORD)pTable));
pTable += sizeof(WORD);
}
j = nCount * REVCURVE_RATIO;
for (i=0; i<j; i++)
{
dwStore = i * 65535 / (j - 1);
pOutput[i] = (dwStore < 65535) ? (WORD) dwStore : 65535;
}
for (i=0; i<j; i++)
{
dwBegin = 0;
dwEnd = nCount - 1;
for (;;)
{
if ((dwEnd - dwBegin) <= 1)
break;
dwTemp = (dwEnd + dwBegin) / 2;
if (pOutput[i] < pInput[dwTemp])
dwEnd = dwTemp;
else
dwBegin = dwTemp;
}
if (pOutput[i] <= pInput[dwBegin])
{
dwStore = dwBegin;
}
else if (pOutput[i] >= pInput[dwEnd])
{
dwStore = dwEnd;
}
else
{
dwStore = (pInput[dwEnd] - pOutput[i]) / (pOutput[i] - pInput[dwBegin]);
dwStore = (dwBegin * dwStore + dwEnd) / (dwStore + 1);
}
dwStore = dwStore * 65535 / (nCount - 1);
pOutput[i] = (dwStore < 65535) ? (WORD) dwStore : 65535;
}
return TRUE;
}
BOOL
DoesCPTagExist(
PBYTE pProfile,
DWORD dwTag,
PDWORD pdwIndex
)
{
DWORD i, dwCount;
PTAGDATA pTagData;
BOOL bRc;
// Get count of tag items - it is right after the profile header
dwCount = FIX_ENDIAN(*((DWORD *)(pProfile + sizeof(PROFILEHEADER))));
// Tag data records follow the count.
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD));
// Check if any of these records match the tag passed in.
bRc = FALSE;
dwTag = FIX_ENDIAN(dwTag); // to match tags in profile
for (i=0; i<dwCount; i++)
{
if (pTagData->tagType == dwTag)
{
if (pdwIndex)
{
*pdwIndex = i;
}
bRc = TRUE;
break;
}
pTagData++; // Next record
}
return bRc;
}
BOOL
DoesTRCAndColorantTagExist(
PBYTE pProfile
)
{
if (DoesCPTagExist(pProfile,TAG_REDCOLORANT,NULL) &&
DoesCPTagExist(pProfile,TAG_REDTRC,NULL) &&
DoesCPTagExist(pProfile,TAG_GREENCOLORANT,NULL) &&
DoesCPTagExist(pProfile,TAG_GREENTRC,NULL) &&
DoesCPTagExist(pProfile,TAG_BLUECOLORANT,NULL) &&
DoesCPTagExist(pProfile,TAG_BLUETRC,NULL))
{
return TRUE;
}
return FALSE;
}
BOOL
GetCPWhitePoint(
PBYTE pProfile,
PFIX_16_16 pafxWP
)
{
pafxWP[0] = FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phIlluminant.ciexyzX);
pafxWP[1] = FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phIlluminant.ciexyzY);
pafxWP[2] = FIX_ENDIAN(((PPROFILEHEADER)pProfile)->phIlluminant.ciexyzZ);
return TRUE;
}
BOOL
GetCPMediaWhitePoint(
PBYTE pProfile,
PFIX_16_16 pafxMediaWP
)
{
PTAGDATA pTagData;
PDWORD pTable;
DWORD dwIndex, i;
if (DoesCPTagExist (pProfile, TAG_MEDIAWHITEPOINT, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
// Skip the first 2 DWORDs to get to the real data
pTable = (PDWORD)(pProfile + FIX_ENDIAN(pTagData->dwOffset)) + 2;
for (i=0; i<3; i++)
{
pafxMediaWP[i] = FIX_ENDIAN(*pTable);
pTable++;
}
return TRUE;
}
return FALSE;
}
BOOL
GetCPElementDataSize(
PBYTE pProfile,
DWORD dwIndex,
PDWORD pcbSize)
{
PTAGDATA pTagData;
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
// Actual data Size of elements of type 'dataType' is 3 DWORDs less than the
// total tag data size
*pcbSize = FIX_ENDIAN(pTagData->cbSize) - 3 * sizeof(DWORD);
return TRUE;
}
BOOL
GetCPElementSize(
PBYTE pProfile,
DWORD dwIndex,
PDWORD pcbSize)
{
PTAGDATA pTagData;
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
*pcbSize = FIX_ENDIAN(pTagData->cbSize);
return TRUE;
}
BOOL
GetCPElementDataType(
PBYTE pProfile,
DWORD dwIndex,
PDWORD pdwDataType)
{
PTAGDATA pTagData;
PBYTE pData;
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = pProfile + FIX_ENDIAN(pTagData->dwOffset);
*pdwDataType = FIX_ENDIAN(*((DWORD *)(pData + 2 * sizeof(DWORD))));
return TRUE;
}
BOOL
GetCPElementData(
PBYTE pProfile,
DWORD dwIndex,
PBYTE pBuffer,
PDWORD pdwSize
)
{
PTAGDATA pTagData;
PBYTE pData;
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pData = pProfile + FIX_ENDIAN(pTagData->dwOffset);
// Actual data Size of elements of type 'dataType' is 3 DWORDs less than the
// total tag data size
*pdwSize = FIX_ENDIAN(pTagData->cbSize) - 3 * sizeof(DWORD);
if (pBuffer)
{
CopyMemory(pBuffer, (pData + 3*sizeof(DWORD)), *pdwSize);
}
return TRUE;
}
BOOL
GetTRCElementSize(
PBYTE pProfile,
DWORD dwTag,
PDWORD pdwIndex,
PDWORD pdwSize
)
{
DWORD dwDataType;
if (!DoesCPTagExist(pProfile, dwTag, pdwIndex) ||
!GetCPElementDataType(pProfile, *pdwIndex, &dwDataType) ||
!(dwDataType != SIG_CURVE_TYPE) ||
!GetCPElementSize(pProfile, *pdwIndex, pdwSize))
{
return FALSE;
}
return TRUE;
}
DWORD
Ascii85Encode(
PBYTE pBuffer,
DWORD dwDataSize,
DWORD dwBufSize
)
{
// BUGBUG - To be done
#if 0
PBYTE pTempBuf, pPtr;
DWORD dwASCII85Size = 0;
DWORD dwBufSize = DataSize * 5 / 4 + sizeof(ASCII85DecodeBegin)+sizeof(ASCII85DecodeEnd) + 2048;
if ((pTempBuf = (PBYTE)MemAlloc(dwBufSize)))
{
pPtr = pTempBuf;
pPtr += WriteObject(pPtr, NewLine);
pPtr += WriteObject(pPtr, ASCII85DecodeBegin);
pPtr += WriteObject(pPtr, NewLine);
pPtr += WriteASCII85Cont(pPtr, dwBufSize, pBuffer, dwDataSize);
pPtr += WriteObject(pPtr, ASCII85DecodeEnd);
dwAscii85Size = (DWORD)(pPtr - pTempBuf);
lstrcpyn(pBuffer, pTempBuf, dwAscii85Size);
MemFree(pTempBuf);
}
return dwAscii85Size;
#else
return 0;
#endif
}
/*
* Function to write the Homogeneous Number Array token into the buffer
*/
DWORD
WriteHNAToken(
PBYTE pBuffer,
BYTE token,
DWORD dwNum
)
{
*pBuffer++ = token;
*pBuffer++ = 32; // 16-bit fixed integer, high-order byte first
*pBuffer++ = (BYTE)((dwNum & 0xFF00) >> 8);
*pBuffer++ = (BYTE)(dwNum & 0x00FF);
return 4;
}
/*
* Function to convert 2-bytes unsigned integer to 2-bytes signed
* integer(-32768) and write them to the buffer. High byte first.
*/
DWORD
WriteIntStringU2S(
PBYTE pBuffer,
PBYTE pData,
DWORD dwNum
)
{
DWORD i, dwTemp;
for (i=0; i<dwNum; i++)
{
dwTemp = FIX_ENDIAN16(*((PWORD)pData)) - 32768;
*pBuffer++ = (BYTE)((dwTemp & 0xFF00) >> 8);
*pBuffer++ = (BYTE)(dwTemp & 0x00FF);
pData += sizeof(WORD);
}
return dwNum * 2;
}
/*
* Function to convert 2-bytes unsigned integer to 2-bytes signed
* integer(-32768) and write them to the buffer. Low-order byte first.
*/
DWORD
WriteIntStringU2S_L(
PBYTE pBuffer,
PBYTE pData,
DWORD dwNum
)
{
DWORD i, dwTemp;
for (i=0; i<dwNum; i++)
{
dwTemp = *((PWORD)pData) - 32768;
*pBuffer++ = (BYTE)((dwTemp & 0xFF00) >> 8);
*pBuffer++ = (BYTE)(dwTemp & 0x00FF);
pData += sizeof(WORD);
}
return dwNum * 2;
}
/*
* Function to put the chunk of memory as string of Hex
*/
DWORD
WriteHexBuffer(
PBYTE pBuffer,
PBYTE pData,
PBYTE pLineStart,
DWORD dwBytes
)
{
PBYTE pStart = pBuffer;
for ( ; dwBytes ; dwBytes-- )
{
WriteHex(pBuffer, *pData);
pBuffer += 2;
pData++;
if (((DWORD)(pBuffer - pLineStart)) > MAX_LINELEN)
{
pLineStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
}
}
return( (DWORD)(pBuffer - pStart));
}
/*
* Function to write the string token into the buffer
*/
DWORD
WriteStringToken(
PBYTE pBuffer,
BYTE token,
DWORD dwNum
)
{
*pBuffer++ = token;
*pBuffer++ = (BYTE)((dwNum & 0xFF00) >> 8);
*pBuffer++ = (BYTE)(dwNum & 0x00FF);
return 3;
}
/*
* Function to put the chunk of memory into buffer
*/
DWORD
WriteByteString(
PBYTE pBuffer,
PBYTE pData,
DWORD dwBytes
)
{
DWORD i;
for (i=0; i<dwBytes; i++)
*pBuffer++ = *pData++;
return dwBytes;
}
/*
* Function to put the chunk of memory into buffer
*/
DWORD
WriteInt2ByteString(
PBYTE pBuffer,
PBYTE pData,
DWORD dwBytes
)
{
DWORD i;
for (i=0; i<dwBytes ; i++)
{
*pBuffer++ = (BYTE)(FIX_ENDIAN16(*((PWORD)pData))/256);
pData += sizeof(WORD);
}
return dwBytes;
}
#ifndef KERNEL_MODE
DWORD
WriteFixed(
PBYTE pBuffer,
FIX_16_16 fxNum
)
{
double dFloat = (double) ((long) fxNum) / (double) FIX_16_16_SCALE;
return (WriteDouble(pBuffer,dFloat));
}
#else
DWORD
WriteFixed(
PBYTE pBuffer,
FIX_16_16 fxNum
)
{
PBYTE pStart = pBuffer;
DWORD i;
// Integer portion
#ifndef KERNEL_MODE
pBuffer += wsprintfA(pBuffer, "%lu", fxNum >> FIX_16_16_SHIFT);
#else
pBuffer += OPSprintf(pBuffer, "%l", fxNum >> FIX_16_16_SHIFT);
#endif
// Fractional part
fxNum &= 0xffff;
if (fxNum != 0)
{
// We output a maximum of 6 digits after the
// decimal point
*pBuffer++ = '.';
i = 0;
while (fxNum && i++ < 6)
{
fxNum *= 10;
*pBuffer++ = (BYTE)(fxNum >> FIX_16_16_SHIFT) + '0'; // quotient + '0'
fxNum -= FLOOR(fxNum); // remainder
}
}
*pBuffer++ = ' ';
return (DWORD) (pBuffer - pStart);
}
#endif
DWORD
WriteFixed2dot30(
PBYTE pBuffer,
DWORD fxNum
)
{
PBYTE pStart = pBuffer;
DWORD i;
// Integer portion
#ifndef KERNEL_MODE
pBuffer += wsprintfA(pBuffer, "%lu", fxNum >> 30);
#else
pBuffer += OPSprintf(pBuffer, "%l", fxNum >> 30);
#endif
// Fractional part
fxNum &= 0x3fffffffL;
if (fxNum != 0)
{
// We output a maximum of 10 digits after the
// decimal point
*pBuffer++ = '.';
i = 0;
while (fxNum && i++ < 10)
{
fxNum *= 10;
*pBuffer++ = (BYTE)(fxNum >> 30) + '0'; // quotient + '0'
fxNum -= ((fxNum >> 30) << 30); // remainder
}
}
*pBuffer++ = ' ';
return (DWORD) (pBuffer - pStart);
}
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* Function to write the float into the buffer
*/
DWORD WriteDouble(PBYTE pBuffer, double dFloat)
{
LONG lFloat = (LONG) floor(dFloat * 10000.0 + 0.5);
double dFloat1 = lFloat / 10000.0 ;
double dInt = floor(fabs(dFloat1));
double dFract = fabs(dFloat1) - dInt ;
char cSign = ' ' ;
if (dFloat1 < 0)
{
cSign = '-' ;
}
return (wsprintfA(pBuffer, (LPSTR) "%c%d.%0.4lu ",
cSign, (WORD) dInt , (DWORD) (dFract * 10000.0)));
}
#endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
DWORD WriteNewLineObject(
PBYTE pBuffer,
const char *pData)
{
PBYTE pStart = pBuffer;
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, pData);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDBWPoint(
PBYTE pBuffer,
PFIX_16_16 pafxWP
)
{
PBYTE pStart = pBuffer;
int i;
// /BlackPoint
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, BlackPointTag);
pBuffer += WriteObject(pBuffer, BlackPoint);
// /WhitePoint
pBuffer += WriteObject(pBuffer, NewLine);
pBuffer += WriteObject(pBuffer, WhitePointTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteFixed(pBuffer, pafxWP[i]);
}
pBuffer += WriteObject(pBuffer, EndArray);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDPQR(
PBYTE pBuffer,
DWORD dwIntent,
PFIX_16_16 pafxWP
)
{
PBYTE pStart = pBuffer;
int i;
if (dwIntent != INTENT_ABSOLUTE_COLORIMETRIC)
{
// /RangePQR
pBuffer += WriteNewLineObject(pBuffer, RangePQRTag);
pBuffer += WriteObject(pBuffer, RangePQR);
// /MatrixPQR
pBuffer += WriteNewLineObject(pBuffer, MatrixPQRTag);
pBuffer += WriteObject(pBuffer, MatrixPQR);
}
else
{
// /RangePQR
pBuffer += WriteNewLineObject(pBuffer, RangePQRTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteFixed(pBuffer, 0);
pBuffer += WriteFixed(pBuffer, pafxWP[i]);
}
pBuffer += WriteObject(pBuffer, EndArray);
// /MatrixPQR
pBuffer += WriteNewLineObject(pBuffer, MatrixPQRTag);
pBuffer += WriteObject(pBuffer, Identity);
}
// /TransformPQR
pBuffer += WriteNewLineObject(pBuffer, TransformPQRTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer,
(dwIntent != INTENT_ABSOLUTE_COLORIMETRIC) ? TransformPQR[i] : NullOp);
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDLMN(
PBYTE pBuffer,
DWORD dwIntent,
PFIX_16_16 pafxIlluminantWP,
PFIX_16_16 pafxMediaWP,
DWORD dwPCS
)
{
PBYTE pStart = pBuffer;
DWORD i, j;
// /MatrixLMN
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
pBuffer += WriteNewLineObject(pBuffer, MatrixLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
pBuffer += WriteFixed(pBuffer,
(i == j) ? FIX_DIV(pafxIlluminantWP[i], pafxMediaWP[i]) : 0);
}
pBuffer += WriteObject(pBuffer, EndArray);
}
// /RangeLMN
pBuffer += WriteNewLineObject(pBuffer, RangeLMNTag);
if (dwPCS == SPACE_XYZ)
{
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteFixed(pBuffer, 0);
pBuffer += WriteFixed(pBuffer, pafxIlluminantWP[i]);
}
pBuffer += WriteObject(pBuffer, EndArray);
}
else
{
pBuffer += WriteObject(pBuffer, RangeLMNLab);
}
// /EncodeLMN
pBuffer += WriteNewLineObject(pBuffer, EncodeLMNTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
pBuffer += WriteObject(pBuffer, BeginFunction);
if (dwPCS != SPACE_XYZ)
{
pBuffer += WriteFixed(pBuffer, pafxIlluminantWP[i]);
pBuffer += WriteObject(pBuffer, DivOp);
pBuffer += WriteObject(pBuffer, EncodeLMNLab);
}
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDABC(
PBYTE pBuffer,
PBYTE pPublicArrayName,
DWORD dwPCS,
DWORD nInputCh,
PBYTE pLut,
PFIX_16_16 e,
DWORD dwLutSig,
BOOL bBinary
)
{
PBYTE pLineStart, pStart = pBuffer;
PBYTE pTable;
DWORD i, j;
FIX_16_16 fxTempMatrixABC[9];
// /RangeABC
pBuffer += WriteNewLineObject(pBuffer, RangeABCTag);
pBuffer += WriteObject(pBuffer, RangeABC);
// /MatrixABC
pBuffer += WriteNewLineObject(pBuffer, MatrixABCTag);
if (dwPCS == SPACE_XYZ)
{
pBuffer += WriteObject(pBuffer, BeginArray);
if (e)
{
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
pBuffer += WriteFixed(pBuffer, e[i + j * 3]);
}
}
}
else
{
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE) &((PLUT8TYPE)pLut)->e00;
}
else
{
pTable = (PBYTE) &((PLUT16TYPE)pLut)->e00;
}
for (i=0; i<9; i++)
{
fxTempMatrixABC[i] = FIX_DIV(FIX_ENDIAN(*((PDWORD)pTable)), CIEXYZRange);
pTable += sizeof(DWORD);
}
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
pBuffer += WriteFixed(pBuffer, fxTempMatrixABC[i + j * 3]);
}
}
}
pBuffer += WriteObject(pBuffer, EndArray);
}
else
{
pBuffer += WriteObject(pBuffer, MatrixABCLabCRD);
}
// /EncodeABC
if (nInputCh == 0)
{
return (DWORD)(pBuffer - pStart);
}
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, EncodeABCTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<nInputCh; i++)
{
pLineStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, BeginFunction);
if (dwPCS == SPACE_Lab)
{
pBuffer += WriteObject(pBuffer, (i == 0) ? EncodeABCLab1 : EncodeABCLab2);
}
pBuffer += WriteObject(pBuffer, StartClip);
if (e)
pBuffer += WriteObject(pBuffer, PreViewInArray);
else
pBuffer += WriteObject(pBuffer, InputArray);
pBuffer += WriteObject(pBuffer, pPublicArrayName);
pBuffer += WriteInt(pBuffer, i);
if (!bBinary) // Output ASCII CRD
{
pBuffer += WriteNewLineObject(pBuffer, IndexArray);
}
else
{ // Output BINARY CRD
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, IndexArray);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray16b);
}
}
pBuffer += WriteObject(pBuffer, (dwLutSig == LUT8_TYPE) ?
Scale8 : Scale16);
pBuffer += WriteObject(pBuffer, EndClip);
pBuffer += WriteObject(pBuffer, EndFunction);
}
pBuffer += WriteObject(pBuffer, EndArray);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCRDOutputTable(
PBYTE pBuffer,
PBYTE pPublicArrayName,
DWORD nOutputCh,
DWORD dwLutSig,
BOOL bHost,
BOOL bBinary
)
{
PBYTE pStart = pBuffer;
DWORD i;
for (i=0; i<nOutputCh; i++)
{
pBuffer += WriteNewLineObject(pBuffer, BeginFunction);
pBuffer += WriteObject(pBuffer, Clip01);
if (bHost)
pBuffer += WriteObject(pBuffer, PreViewOutArray);
else
pBuffer += WriteObject(pBuffer, OutputArray);
pBuffer += WriteObject(pBuffer, pPublicArrayName);
pBuffer += WriteInt(pBuffer, i);
if (! bBinary)
{
pBuffer += WriteObject(pBuffer, NewLine);
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, TFunction8);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray);
pBuffer += WriteObject(pBuffer, Scale16);
}
}
else
{
if (dwLutSig == LUT8_TYPE)
{
pBuffer += WriteObject(pBuffer, TFunction8);
}
else
{
pBuffer += WriteObject(pBuffer, IndexArray16b);
pBuffer += WriteObject(pBuffer, Scale16);
}
}
pBuffer += WriteObject(pBuffer, EndFunction);
}
return (DWORD)(pBuffer - pStart);
}
VOID
GetCLUTInfo(
DWORD dwLutSig,
PBYTE pLut,
PDWORD pnInputCh,
PDWORD pnOutputCh,
PDWORD pnGrids,
PDWORD pnInputTable,
PDWORD pnOutputTable,
PDWORD pdwSize
)
{
if (dwLutSig == LUT8_TYPE)
{
*pnInputCh = ((PLUT8TYPE)pLut)->nInputChannels;
*pnOutputCh = ((PLUT8TYPE)pLut)->nOutputChannels;
*pnGrids = ((PLUT8TYPE)pLut)->nClutPoints;
*pnInputTable = 256L;
*pnOutputTable = 256L;
if (pdwSize)
*pdwSize = 1;
}
else
{
*pnInputCh = ((PLUT16TYPE)pLut)->nInputChannels;
*pnOutputCh = ((PLUT16TYPE)pLut)->nOutputChannels;
*pnGrids = ((PLUT16TYPE)pLut)->nClutPoints;
*pnInputTable = FIX_ENDIAN16(((PLUT16TYPE)pLut)->wInputEntries);
*pnOutputTable = FIX_ENDIAN16(((PLUT16TYPE)pLut)->wOutputEntries);
if (pdwSize)
*pdwSize = 2;
}
return;
}
DWORD
EnableGlobalDict(
PBYTE pBuffer
)
{
PBYTE pStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, CurrentGlobalOp);
pBuffer += WriteObject(pBuffer, TrueOp);
pBuffer += WriteObject(pBuffer, SetGlobalOp);
return (DWORD)(pBuffer - pStart);
}
DWORD
BeginGlobalDict(
PBYTE pBuffer
)
{
PBYTE pStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, GlobalDictOp);
pBuffer += WriteObject(pBuffer, BeginOp);
return (DWORD)(pBuffer - pStart);
}
DWORD
EndGlobalDict(
PBYTE pBuffer
)
{
PBYTE pStart = pBuffer;
pBuffer += WriteNewLineObject(pBuffer, EndOp);
pBuffer += WriteObject(pBuffer, SetGlobalOp);
return (DWORD)(pBuffer - pStart);
}
DWORD
SendCSABWPoint(
PBYTE pBuffer,
DWORD dwIntent,
PFIX_16_16 pafxIlluminantWP,
PFIX_16_16 pafxMediaWP
)
{
PBYTE pStart = pBuffer;
int i;
// /BlackPoint
pBuffer += WriteNewLineObject(pBuffer, BlackPointTag);
pBuffer += WriteObject(pBuffer, BlackPoint);
// /WhitePoint
pBuffer += WriteNewLineObject(pBuffer, WhitePointTag);
pBuffer += WriteObject(pBuffer, BeginArray);
for (i=0; i<3; i++)
{
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
pBuffer += WriteFixed(pBuffer, pafxMediaWP[i]);
}
else
{
pBuffer += WriteFixed(pBuffer, pafxIlluminantWP[i]);
}
}
pBuffer += WriteObject(pBuffer, EndArray);
return (DWORD)(pBuffer - pStart);
}
VOID
GetMediaWP(
PBYTE pProfile,
DWORD dwIntent,
PFIX_16_16 pafxIlluminantWP,
PFIX_16_16 pafxMediaWP
)
{
if (dwIntent == INTENT_ABSOLUTE_COLORIMETRIC)
{
if (! GetCPMediaWhitePoint(pProfile, pafxMediaWP))
{
pafxMediaWP[0] = pafxIlluminantWP[0];
pafxMediaWP[1] = pafxIlluminantWP[1];
pafxMediaWP[2] = pafxIlluminantWP[2];
}
}
return;
}
BOOL
GetCRDInputOutputArraySize(
PBYTE pProfile,
DWORD dwIntent,
PDWORD pdwInTblSize,
PDWORD pdwOutTblSize,
PDWORD pdwTag,
PDWORD pnGrids
)
{
PTAGDATA pTagData;
PLUT16TYPE pLut;
DWORD dwIndex, dwLutSig;
DWORD nInputEntries, nOutputEntries;
DWORD nInputCh, nOutputCh, nGrids;
BOOL bRet;
// Make sure required tags exist
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
*pdwTag = TAG_BToA0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
case INTENT_ABSOLUTE_COLORIMETRIC:
*pdwTag = TAG_BToA1;
break;
case INTENT_SATURATION:
*pdwTag = TAG_BToA2;
break;
default:
WARNING((__TEXT("Invalid intent passed to GetCRDInputOutputArraySize: %d\n"), dwIntent));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DoesCPTagExist(pProfile, *pdwTag, &dwIndex))
{
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pLut = (PLUT16TYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
dwLutSig = FIX_ENDIAN(pLut->dwSignature);
if ((dwLutSig != LUT8_TYPE) && (dwLutSig != LUT16_TYPE))
{
WARNING((__TEXT("Invalid Lut type - unable to create proofing CRD\n")));
SetLastError(ERROR_INVALID_PROFILE);
return FALSE;
}
(void)GetCLUTInfo(dwLutSig, (PBYTE)pLut, &nInputCh, &nOutputCh,
&nGrids, &nInputEntries, &nOutputEntries, NULL);
if (pdwInTblSize)
{
if (nInputCh != 3)
{
return FALSE;
}
*pdwInTblSize = nInputCh * nInputEntries * 6; // Number of INT bytes
*pnGrids = nGrids;
}
if (pdwOutTblSize)
{
if ((nOutputCh != 3) && (nOutputCh != 4))
{
return FALSE;
}
*pdwOutTblSize = nOutputCh * nOutputEntries * 6; // Number of INT bytes
*pnGrids = nGrids;
}
return TRUE;
}
else
{
// Matrix icc profile.
*pnGrids = 2;
if (pdwInTblSize)
{
bRet = GetHostCSA(pProfile, NULL, pdwInTblSize,
dwIntent, TYPE_CIEBASEDDEF);
*pdwInTblSize = *pdwInTblSize * 3;
}
if (bRet && pdwOutTblSize)
{
bRet = GetHostCSA(pProfile, NULL, pdwInTblSize,
dwIntent, TYPE_CIEBASEDDEF);
*pdwOutTblSize = *pdwOutTblSize * 3;
}
return bRet;
}
}
#if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
DWORD
CreateHostLutCRD(
PBYTE pProfile,
DWORD dwIndex,
PBYTE pBuffer,
DWORD dwIntent
)
{
PLUT16TYPE pLut;
PHOSTCLUT pHostClut;
PTAGDATA pTagData;
PBYTE pTable;
DWORD nInputCh, nOutputCh, nGrids;
DWORD nInputEntries, nOutputEntries, nNumbers;
DWORD dwPCS, dwLutSig;
DWORD dwSize, i, j;
PBYTE pStart = pBuffer;
// Check if we can generate the CSA
// Required tags is AToBi, where i is the rendering intent
dwPCS = GetCPConnSpace(pProfile);
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pLut = (PLUT16TYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
dwLutSig = FIX_ENDIAN(pLut->dwSignature);
if ((dwLutSig != LUT8_TYPE) && (dwLutSig != LUT16_TYPE))
{
WARNING((__TEXT("Invalid profile - unable to create Lut CRD\n")));
SetLastError(ERROR_INVALID_PROFILE);
return 0;
}
(void)GetCLUTInfo(dwLutSig, (PBYTE)pLut, &nInputCh, &nOutputCh,
&nGrids, &nInputEntries, &nOutputEntries, &i);
if (((nOutputCh != 3) && (nOutputCh != 4)) || (nInputCh != 3))
{
return 0;
}
if (pBuffer == NULL)
{
// Return size
dwSize = nInputCh * nInputEntries * i + // Input table 8/16-bits
nOutputCh * nOutputEntries * i + // Output table 8/16-bits
nOutputCh * nGrids * nGrids * nGrids + // CLUT 8-bits only
sizeof(HOSTCLUT) + // Data structure
2048; // Other PS stuff
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
return dwSize;
}
pHostClut = (PHOSTCLUT)pBuffer;
pBuffer += sizeof(HOSTCLUT);
pHostClut->wSize = sizeof(HOSTCLUT);
pHostClut->wDataType = DATATYPE_LUT;
pHostClut->dwPCS = dwPCS;
pHostClut->dwIntent = dwIntent;
pHostClut->nLutBits = (dwLutSig == LUT8_TYPE) ? 8 : 16;
(void)GetCPWhitePoint(pProfile, pHostClut->afxIlluminantWP);
// Support absolute whitePoint
if (!GetCPMediaWhitePoint(pProfile, pHostClut->afxMediaWP))
{
pHostClut->afxMediaWP[0] = pHostClut->afxIlluminantWP[0];
pHostClut->afxMediaWP[1] = pHostClut->afxIlluminantWP[1];
pHostClut->afxMediaWP[2] = pHostClut->afxIlluminantWP[2];
}
pHostClut->nInputCh = (BYTE)nInputCh;
pHostClut->nOutputCh = (BYTE)nOutputCh;
pHostClut->nClutPoints = (BYTE)nGrids;
pHostClut->nInputEntries = (WORD)nInputEntries;
pHostClut->nOutputEntries = (WORD)nOutputEntries;
// Input array
pBuffer += CreateHostInputOutputArray(
pBuffer,
pHostClut->inputArray,
nInputCh,
nInputEntries,
0,
dwLutSig,
(PBYTE)pLut);
// The offset to the position of output array.
i = nInputEntries * nInputCh +
nGrids * nGrids * nGrids * nOutputCh;
// Output array
pBuffer += CreateHostInputOutputArray(
pBuffer,
pHostClut->outputArray,
nOutputCh,
nOutputEntries,
i,
dwLutSig,
(PBYTE)pLut);
// Matrix
if (dwPCS == SPACE_XYZ)
{
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE) &((PLUT8TYPE)pLut)->e00;
} else
{
pTable = (PBYTE) &((PLUT16TYPE)pLut)->e00;
}
for (i=0; i<9; i++)
{
pHostClut->e[i] = FIX_DIV(FIX_ENDIAN(*((PDWORD)pTable)), CIEXYZRange);
pTable += sizeof(DWORD);
}
}
// RenderTable
nNumbers = nGrids * nGrids * nOutputCh;
pHostClut->clut = pBuffer;
for (i=0; i<nGrids; i++) // Na strings should be sent
{
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE)(((PLUT8TYPE)pLut)->data) +
nInputEntries * nInputCh +
nNumbers * i;
}
else
{
pTable = (PBYTE)(((PLUT16TYPE)pLut)->data) +
2 * nInputEntries * nInputCh +
2 * nNumbers * i;
}
if (dwLutSig == LUT8_TYPE)
{
CopyMemory(pBuffer, pTable, nNumbers);
pBuffer += nNumbers;
}
else
{
for (j=0; j<nNumbers; j++)
{
*pBuffer++ = (BYTE)(FIX_ENDIAN16(*((PWORD)pTable)) / 256);
pTable += sizeof(WORD);
}
}
}
return (DWORD)(pBuffer - pStart);
}
DWORD
CreateHostMatrixCSAorCRD(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pcbSize,
DWORD dwIntent,
BOOL bCSA
)
{
PTAGDATA pTagData;
DWORD dwRedTRCIndex, dwGreenTRCIndex, dwBlueTRCIndex;
DWORD dwRedCount, dwGreenCount, dwBlueCount;
PCURVETYPE pRed, pGreen, pBlue;
PHOSTCLUT pHostClut;
PBYTE pStart = pBuffer;
DWORD i, dwSize;
double adArray[9], adRevArray[9], adTemp[9];
// Get each TRC index for Red, Green and Blue.
if (!DoesCPTagExist(pProfile, TAG_REDTRC, &dwRedTRCIndex) ||
!DoesCPTagExist(pProfile, TAG_GREENTRC, &dwGreenTRCIndex) ||
!DoesCPTagExist(pProfile, TAG_BLUETRC, &dwBlueTRCIndex))
{
return FALSE;
}
// Get CURVETYPE data for each Red, Green and Blue
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwRedTRCIndex * sizeof(TAGDATA));
pRed = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwGreenTRCIndex * sizeof(TAGDATA));
pGreen = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwBlueTRCIndex * sizeof(TAGDATA));
pBlue = (PCURVETYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
// Get curve count for each Red, Green and Blue.
dwRedCount = FIX_ENDIAN(pRed->nCount);
dwGreenCount = FIX_ENDIAN(pGreen->nCount);
dwBlueCount = FIX_ENDIAN(pBlue->nCount);
// Estimate the memory size required to hold CRD
dwSize = (dwRedCount + dwGreenCount + dwBlueCount) * 2 +
sizeof(HOSTCLUT) + 2048; // data structure + extra safe space
// Add space for new line.
dwSize += (((dwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
if (pBuffer == NULL) // This is a size request
{
*pcbSize = dwSize;
return TRUE;
}
// Check buffer size.
if (*pcbSize < dwSize)
{
WARNING((__TEXT("Buffer too small to get Host Matrix CSA/CRD\n")));
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
pHostClut = (PHOSTCLUT)pBuffer;
pBuffer += sizeof(HOSTCLUT);
pHostClut->wSize = sizeof(HOSTCLUT);
pHostClut->wDataType = DATATYPE_MATRIX;
pHostClut->dwPCS = SPACE_XYZ;
pHostClut->dwIntent = dwIntent;
pHostClut->nClutPoints = 2;
(void)GetCPWhitePoint(pProfile, pHostClut->afxIlluminantWP);
if (bCSA)
{
pHostClut->nInputEntries = (USHORT) dwRedCount;
pHostClut->nInputCh = 3;
pBuffer += CreateHostTRCInputTable(pBuffer, pHostClut,
pRed, pGreen, pBlue);
}
else
{
pHostClut->nOutputEntries = (USHORT) dwRedCount;
pHostClut->nOutputCh = 3;
pBuffer += CreateHostRevTRCInputTable(pBuffer, pHostClut,
pRed, pGreen, pBlue);
}
if (!CreateColorantArray(pProfile, &adTemp[0], TAG_REDCOLORANT) ||
!CreateColorantArray(pProfile, &adTemp[3], TAG_GREENCOLORANT) ||
!CreateColorantArray(pProfile, &adTemp[6], TAG_BLUECOLORANT))
{
WARNING((__TEXT("Fail to create colorant array for Host Matrix CSA/CRD\n")));
return FALSE;
}
for (i = 0; i < 9; i++)
{
adArray[i] = adTemp[i/8*8 + i*3%8];
}
if (bCSA)
{
for (i = 0; i < 9; i++)
{
// Convert double to Fix 16.16
pHostClut->e[i] = (FIX_16_16)(adArray[i] * (double)FIX_16_16_SCALE);
}
}
else
{
InvertColorantArray(adArray, adRevArray);
for (i = 0; i < 9; i++)
{
// Convert double to Fix 16.16
pHostClut->e[i] = (FIX_16_16)(adRevArray[i] * (double)FIX_16_16_SCALE);
}
}
*pcbSize = (DWORD)(pBuffer - pStart);
return TRUE;
}
DWORD
CreateHostTRCInputTable(
PBYTE pBuffer,
PHOSTCLUT pHostClut,
PCURVETYPE pRed,
PCURVETYPE pGreen,
PCURVETYPE pBlue
)
{
DWORD i;
PWORD pBuffer16 = (PWORD) pBuffer;
PWORD pTable;
// Red
pHostClut->inputArray[0] = (PBYTE) pBuffer16;
pTable = pRed->data;
for (i = 0; i < pHostClut->nInputEntries; i++)
{
*pBuffer16++ = FIX_ENDIAN16(*pTable);
pTable++;
}
// Green
pHostClut->inputArray[1] = (PBYTE) pBuffer16;
pTable = pGreen->data;
for (i = 0; i < pHostClut->nInputEntries; i++)
{
*pBuffer16++ = FIX_ENDIAN16(*pTable);
pTable++;
}
// Blue
pHostClut->inputArray[2] = (PBYTE) pBuffer16;
pTable = pBlue->data;
for (i = 0; i < pHostClut->nInputEntries; i++)
{
*pBuffer16++ = FIX_ENDIAN16(*pTable);
pTable++;
}
return (DWORD)((PBYTE)pBuffer16 - pBuffer);
}
DWORD
CreateHostRevTRCInputTable(
PBYTE pBuffer,
PHOSTCLUT pHostClut,
PCURVETYPE pRed,
PCURVETYPE pGreen,
PCURVETYPE pBlue
)
{
PWORD pTemp = MemAlloc(pHostClut->nOutputEntries * (REVCURVE_RATIO + 1) * 2);
if (! pTemp)
{
return 0;
}
// Red
pHostClut->outputArray[0] = pBuffer;
GetRevCurve(pRed, pTemp, (PWORD) pHostClut->outputArray[0]);
// Green
pHostClut->outputArray[1] = pHostClut->outputArray[0] +
2 * REVCURVE_RATIO * pHostClut->nOutputEntries;
GetRevCurve(pGreen, pTemp, (PWORD) pHostClut->outputArray[1]);
// Blue
pHostClut->outputArray[2] = pHostClut->outputArray[1] +
2 * REVCURVE_RATIO * pHostClut->nOutputEntries;
GetRevCurve(pBlue, pTemp, (PWORD) pHostClut->outputArray[2]);
MemFree(pTemp);
return (DWORD)(2 * REVCURVE_RATIO * pHostClut->nOutputEntries * 3);
}
/*
* 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
*/
BOOL
GetHostColorRenderingDictionary(
PBYTE pProfile,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pdwSize
)
{
DWORD dwBToATag, dwIndex;
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
dwBToATag = TAG_BToA0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
case INTENT_ABSOLUTE_COLORIMETRIC:
dwBToATag = TAG_BToA1;
break;
case INTENT_SATURATION:
dwBToATag = TAG_BToA2;
break;
default:
*pdwSize = 0;
return FALSE;
}
if (DoesCPTagExist(pProfile, dwBToATag, &dwIndex))
{
*pdwSize = CreateHostLutCRD(pProfile, dwIndex, pBuffer, dwIntent);
return *pdwSize > 0;
}
else if (DoesTRCAndColorantTagExist(pProfile))
{
return CreateHostMatrixCSAorCRD(pProfile, pBuffer, pdwSize, dwIntent, FALSE);
}
else
{
return FALSE;
}
}
/*
* 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
*/
DWORD
CreateHostInputOutputArray(
PBYTE pBuffer,
PBYTE *ppArray,
DWORD nNumChan,
DWORD nTableSize,
DWORD dwOffset,
DWORD dwLutSig,
PBYTE pLut
)
{
PBYTE pStart = pBuffer;
PBYTE pTable;
DWORD i, j;
for (i=0; i<nNumChan; i++)
{
ppArray[i] = pBuffer;
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE) (((PLUT8TYPE)pLut)->data) +
dwOffset + nTableSize * i;
CopyMemory(pBuffer, pTable, nTableSize);
pBuffer += nTableSize;
}
else
{
pTable = (PBYTE) (((PLUT16TYPE)pLut)->data) +
2 * dwOffset +
2 * nTableSize * i;
for (j=0; j<nTableSize; j++)
{
*((PWORD)pBuffer) = FIX_ENDIAN16(*((PWORD)pTable));
pBuffer += sizeof(WORD);
pTable += sizeof(WORD);
}
}
}
return (DWORD) (pBuffer - pStart);
}
/*
* 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.
*/
BOOL
GetHostCSA(
PBYTE pProfile,
PBYTE pBuffer,
PDWORD pdwSize,
DWORD dwIntent,
DWORD dwType
)
{
PHOSTCLUT pHostClut;
PTAGDATA pTagData;
PLUT16TYPE pLut;
DWORD dwAToBTag;
DWORD dwPCS, dwLutSig;
DWORD nInputCh, nOutputCh, nGrids, SecondGrids;
DWORD nInputTable, nOutputTable, nNumbers;
DWORD dwIndex, i, j, k;
PBYTE pTable;
PBYTE pStart = pBuffer;
switch (dwIntent)
{
case INTENT_PERCEPTUAL:
dwAToBTag = TAG_AToB0;
break;
case INTENT_RELATIVE_COLORIMETRIC:
case INTENT_ABSOLUTE_COLORIMETRIC:
dwAToBTag = TAG_AToB1;
break;
case INTENT_SATURATION:
dwAToBTag = TAG_AToB2;
break;
default:
WARNING((__TEXT("Invalid intent passed to GetHostCSA: %d\n"), dwIntent));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
break;
}
if (!DoesCPTagExist(pProfile, dwAToBTag, &dwIndex))
{
if (DoesTRCAndColorantTagExist(pProfile) && (dwType == TYPE_CIEBASEDDEF))
{
// Create Host CSA from Matrix.
return CreateHostMatrixCSAorCRD(pProfile,pBuffer,pdwSize,dwIntent,TRUE);
}
else
{
WARNING((__TEXT("AToB tag not present for intent %d\n"), dwIntent));
SetLastError(ERROR_TAG_NOT_PRESENT);
return FALSE;
}
}
// Check if we can generate the CSA
dwPCS = GetCPConnSpace(pProfile);
pTagData = (PTAGDATA)(pProfile + sizeof(PROFILEHEADER) + sizeof(DWORD) +
dwIndex * sizeof(TAGDATA));
pLut = (PLUT16TYPE)(pProfile + FIX_ENDIAN(pTagData->dwOffset));
dwLutSig = FIX_ENDIAN(pLut->dwSignature);
if (((dwPCS != SPACE_Lab) && (dwPCS != SPACE_XYZ)) ||
((dwLutSig != LUT8_TYPE) && (dwLutSig != LUT16_TYPE)))
{
WARNING((__TEXT("Invalid color space - unable to create DEF(G) host CSA\n")));
SetLastError(ERROR_INVALID_PROFILE);
return FALSE;
}
// Estimate the memory size required to hold CSA
(void)GetCLUTInfo(dwLutSig, (PBYTE)pLut, &nInputCh, &nOutputCh, &nGrids,
&nInputTable, &nOutputTable, &i);
if (!(nOutputCh == 3) ||
!((nInputCh == 3) && (dwType == TYPE_CIEBASEDDEF)) &&
!((nInputCh == 4) && (dwType == TYPE_CIEBASEDDEFG)))
{
return FALSE;
}
if (pBuffer == NULL)
{
// Return size
if (dwType == TYPE_CIEBASEDDEFG)
*pdwSize = nOutputCh * nGrids * nGrids * nGrids * nGrids;
else
*pdwSize = nOutputCh * nGrids * nGrids * nGrids;
*pdwSize += // 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) + 2048; // data structure + other PS stuff
// Add space for new line.
*pdwSize += (((*pdwSize) / MAX_LINELEN) + 1) * STRLEN(NewLine);
return TRUE;
}
pHostClut = (PHOSTCLUT)pBuffer;
pBuffer += sizeof(HOSTCLUT);
pHostClut->wSize = sizeof(HOSTCLUT);
pHostClut->wDataType = DATATYPE_LUT;
pHostClut->dwPCS = dwPCS;
pHostClut->dwIntent = dwIntent;
pHostClut->nLutBits = (dwLutSig == LUT8_TYPE) ? 8 : 16;
// Get info about Illuminant White Point from the header
(void)GetCPWhitePoint(pProfile, pHostClut->afxIlluminantWP);
pHostClut->nInputCh = (BYTE)nInputCh;
pHostClut->nOutputCh = (BYTE)nOutputCh;
pHostClut->nClutPoints = (BYTE)nGrids;
pHostClut->nInputEntries = (WORD)nInputTable;
pHostClut->nOutputEntries = (WORD)nOutputTable;
// Input Array
pBuffer += CreateHostInputOutputArray(pBuffer, pHostClut->inputArray,
nInputCh, nInputTable, 0, dwLutSig, (PBYTE)pLut);
if (dwType == TYPE_CIEBASEDDEFG)
{
i = nInputTable * nInputCh +
nGrids * nGrids * nGrids * nGrids * nOutputCh;
}
else
{
i = nInputTable * nInputCh +
nGrids * nGrids * nGrids * nOutputCh;
}
// Output Array
pBuffer += CreateHostInputOutputArray(pBuffer, pHostClut->outputArray,
nOutputCh, nOutputTable, i, dwLutSig, (PBYTE)pLut);
// /Table
pHostClut->clut = pBuffer;
nNumbers = nGrids * nGrids * nOutputCh;
SecondGrids = 1;
if (dwType == TYPE_CIEBASEDDEFG)
{
SecondGrids = nGrids;
}
for (i=0; i<nGrids; i++) // Nh strings should be sent
{
for (k=0; k<SecondGrids; k++)
{
if (dwLutSig == LUT8_TYPE)
{
pTable = (PBYTE) (((PLUT8TYPE)pLut)->data) +
nInputTable * nInputCh +
nNumbers * (i * SecondGrids + k);
}
else
{
pTable = (PBYTE) (((PLUT16TYPE)pLut)->data) +
2 * nInputTable * nInputCh +
2 * nNumbers * (i * SecondGrids + k);
}
if (dwLutSig == LUT8_TYPE)
{
CopyMemory(pBuffer, pTable, nNumbers);
pBuffer += nNumbers;
}
else
{
for (j=0; j<nNumbers; j++)
{
*pBuffer++ = (BYTE)(FIX_ENDIAN16(*((PWORD)pTable)) / 256);
pTable += sizeof(WORD);
}
}
}
}
*pdwSize = (DWORD) (pBuffer - pStart);
return TRUE;
}
/*
* 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.
*/
BOOL
GetHostColorSpaceArray(
PBYTE pProfile,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pdwSize
)
{
DWORD dwDev;
BOOL bRc = FALSE;
dwDev = GetCPDevSpace(pProfile);
switch (dwDev)
{
case SPACE_RGB:
bRc = GetHostCSA(pProfile, pBuffer, pdwSize,
dwIntent, TYPE_CIEBASEDDEF);
break;
case SPACE_CMYK:
bRc = GetHostCSA(pProfile, pBuffer, pdwSize,
dwIntent, TYPE_CIEBASEDDEFG);
break;
default:
break;
}
return bRc;
}
/*
* 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
*/
BOOL
DoHostConversionCRD(
PHOSTCLUT pHostCRD,
PHOSTCLUT pHostCSA,
float *pfInput,
float *pfOutput,
BOOL bCheckOutputTable
)
{
float fTemp[MAXCHANNELS];
float fTemp1[MAXCHANNELS];
DWORD i, j;
// Input XYZ or Lab in range [0 2]
// When sampling the deviceCRD, skip the input table.
// If pHostCSA is not NULL, the current CRD is targetCRD, we
// need to do input table conversion
if (pHostCSA)
{
// Convert Lab to XYZ in range [ 0 whitePoint ]
if ((pHostCRD->dwPCS == SPACE_XYZ) &&
(pHostCSA->dwPCS == SPACE_Lab))
{
LabToXYZ(pfInput, fTemp1, pHostCRD->afxIlluminantWP);
}
else if ((pHostCRD->dwPCS == SPACE_Lab) &&
(pHostCSA->dwPCS == SPACE_XYZ))
{
// Convert XYZ to Lab in range [ 0 1]
XYZToLab(pfInput, fTemp, pHostCSA->afxIlluminantWP);
}
else if ((pHostCRD->dwPCS == SPACE_Lab) &&
(pHostCSA->dwPCS == SPACE_Lab))
{
// Convert Lab to range [ 0 1]
for (i=0; i<3; i++)
fTemp[i] = pfInput[i] / 2;
}
else
{
// Convert XYZ to XYZ (based on white point) to range [0 1]
// TODO:
// different intents using different conversion.
// icRelativeColorimetric: using Bradford transform.
// icAbsoluteColorimetric: using scaling.
for (i=0; i<3; i++)
fTemp1[i] = (pfInput[i] * pHostCRD->afxIlluminantWP[i]) / pHostCSA->afxIlluminantWP[i];
}
// Matrix, used for XYZ data only.
if (pHostCRD->dwPCS == SPACE_XYZ)
{
ApplyMatrix(pHostCRD->e, fTemp1, fTemp);
}
if (pHostCRD->wDataType != DATATYPE_MATRIX)
{
// Search input Table
(void)CheckInputOutputTable(pHostCRD, fTemp, FALSE, TRUE);
}
}
// If the current CRD is device CRD, we do not need to do input
// table conversion
else
{
WORD nGrids;
nGrids = pHostCRD->nClutPoints;
// 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 (pHostCRD->wDataType == DATATYPE_MATRIX)
{
for (i = 0; i < 3; i++)
{
fTemp[i] = pfInput[i];
}
}
else
{
for (i=0; i<3; i++)
{
fTemp[i] = pfInput[i] * (nGrids - 1);
if (fTemp[i] > (nGrids - 1))
fTemp[i] = (float)(nGrids - 1);
}
}
}
if (pHostCRD->wDataType != DATATYPE_MATRIX)
{
// Rendering table
(void)CheckColorLookupTable(pHostCRD, fTemp);
}
// Output RGB or CMYK in range [0 1]
if (bCheckOutputTable)
{
(void)CheckInputOutputTable(pHostCRD, fTemp, FALSE, FALSE);
}
for (i=0; (i<=MAXCHANNELS) && (i<pHostCRD->nOutputCh); i++)
{
pfOutput[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
*/
BOOL
DoHostConversionCSA(
PHOSTCLUT pHostClut,
float *pfInput,
float *pfOutput
)
{
float fTemp[MAXCHANNELS];
DWORD i;
// Input RGB or CMYK in range [0 1]
for (i=0; (i<=MAXCHANNELS) && (i<pHostClut->nInputCh); i++)
{
fTemp[i] = pfInput[i];
}
// Search input Table
(void)CheckInputOutputTable(pHostClut, fTemp, TRUE, TRUE);
if (pHostClut->wDataType == DATATYPE_MATRIX)
{
ApplyMatrix(pHostClut->e, fTemp, pfOutput);
}
else
{
// Rendering table
(void)CheckColorLookupTable(pHostClut, fTemp);
// Output Table
(void)CheckInputOutputTable(pHostClut, fTemp, TRUE, FALSE);
// Output XYZ or Lab in range [0 2]
for (i=0; (i<=MAXCHANNELS) && (i<pHostClut->nOutputCh); i++)
{
pfOutput[i] = fTemp[i];
}
}
return TRUE;
}
/*
* CheckInputOutputTable
* function:
* This function check inputTable.
* parameters:
* LPHOSTCLUT lpHostClut --
* float far *fTemp -- Input / output data
* returns:
* BOOL -- TRUE
*/
BOOL
CheckInputOutputTable(
PHOSTCLUT pHostClut,
float *pfTemp,
BOOL bCSA,
BOOL bInputTable
)
{
PBYTE *ppArray;
float fIndex;
DWORD nNumCh;
DWORD nNumEntries, i;
WORD nGrids;
WORD floor1, ceiling1;
if (bInputTable)
{
nNumCh = pHostClut->nInputCh;
nNumEntries = pHostClut->nInputEntries - 1;
ppArray = pHostClut->inputArray;
}
else
{
nNumCh = pHostClut->nOutputCh;
nNumEntries = pHostClut->nOutputEntries - 1;
ppArray = pHostClut->outputArray;
}
nGrids = pHostClut->nClutPoints;
for (i=0; (i<=MAXCHANNELS) && (i<nNumCh); i++)
{
pfTemp[i] = (pfTemp[i] < 0) ? 0 : ((pfTemp[i] > 1) ? 1 : pfTemp[i]);
fIndex = pfTemp[i] * nNumEntries;
if (pHostClut->nLutBits == 8)
{
floor1 = ppArray[i][(DWORD)fIndex];
ceiling1 = ppArray[i][((DWORD)fIndex) + 1];
pfTemp[i] = (float)(floor1 + (ceiling1 - floor1) * (fIndex - floor(fIndex)));
if (bCSA && !bInputTable)
pfTemp[i] = pfTemp[i] / 127.0f;
else
pfTemp[i] = pfTemp[i] / 255.0f;
}
else
{
floor1 = ((PWORD)(ppArray[i]))[(DWORD)fIndex];
ceiling1 = ((PWORD)(ppArray[i]))[((DWORD)fIndex) + 1];
pfTemp[i] = (float)(floor1 + (ceiling1 - floor1) * (fIndex - floor(fIndex)));
if (bCSA && !bInputTable)
pfTemp[i] = pfTemp[i] / 32767.0f;
else
pfTemp[i] = pfTemp[i] / 65535.0f;
}
if (bInputTable)
{
pfTemp[i] *= (nGrids - 1);
if (pfTemp[i] > (nGrids - 1))
pfTemp[i] = (float)(nGrids - 1);
}
}
return TRUE;
}
/*
* 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
*/
float g(
float f
)
{
float fRc;
if (f >= (6.0f/29.0f))
{
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
*/
float
inverse_g(
float f
)
{
double fRc;
if (f >= (6.0f*6.0f*6.0f)/(29.0f*29.0f*29.0f))
{
fRc = pow(f, 1.0 / 3.0);
}
else
{
fRc = f * (841.0f / 108.0f) + (4.0f / 29.0f);
}
return (float)fRc;
}
void
LabToXYZ(
float *pfInput,
float *pfOutput,
PFIX_16_16 pafxWP
)
{
float fL, fa, fb;
fL = (pfInput[0] * 50 + 16) / 116;
fa = (pfInput[1] * 128 - 128) / 500;
fb = (pfInput[2] * 128 - 128) / 200;
pfOutput[0] = pafxWP[0] * g(fL + fa) / FIX_16_16_SCALE;
pfOutput[1] = pafxWP[1] * g(fL) / FIX_16_16_SCALE;
pfOutput[2] = pafxWP[2] * g(fL - fb) / FIX_16_16_SCALE;
return;
}
void
XYZToLab(
float *pfInput,
float *pfOutput,
PFIX_16_16 pafxWP
)
{
float fL, fa, fb;
fL = inverse_g(pfInput[0] * FIX_16_16_SCALE / pafxWP[0]);
fa = inverse_g(pfInput[1] * FIX_16_16_SCALE / pafxWP[1]);
fb = inverse_g(pfInput[2] * FIX_16_16_SCALE / pafxWP[2]);
pfOutput[0] = (fa * 116 - 16) / 100;
pfOutput[1] = (fL * 500 - fa * 500 + 128) / 255;
pfOutput[2] = (fa * 200 - fb * 200 + 128) / 255;
return;
}
BOOL
TableInterp3(
PHOSTCLUT pHostClut,
float *pfTemp
)
{
PBYTE v000, v001, v010, v011;
PBYTE v100, v101, v110, v111;
float fA, fB, fC;
float fVx0x, fVx1x;
float fV0xx, fV1xx;
DWORD tmpA, tmpBC;
DWORD cellA, cellB, cellC;
DWORD idx;
WORD nGrids;
WORD nOutputCh;
cellA = (DWORD)pfTemp[0];
fA = pfTemp[0] - cellA;
cellB = (DWORD)pfTemp[1];
fB = pfTemp[1] - cellB;
cellC = (DWORD)pfTemp[2];
fC = pfTemp[2] - cellC;
nGrids = pHostClut->nClutPoints;
nOutputCh = pHostClut->nOutputCh;
tmpA = nOutputCh * nGrids * nGrids;
tmpBC = nOutputCh * (nGrids * cellB + cellC);
// Calculate 8 surrounding cells.
v000 = pHostClut->clut + tmpA * cellA + tmpBC;
v001 = (cellC < (DWORD)(nGrids - 1)) ? v000 + nOutputCh : v000;
v010 = (cellB < (DWORD)(nGrids - 1)) ? v000 + nOutputCh * nGrids : v000;
v011 = (cellC < (DWORD)(nGrids - 1)) ? v010 + nOutputCh : v010 ;
v100 = (cellA < (DWORD)(nGrids - 1)) ? v000 + tmpA : v000;
v101 = (cellC < (DWORD)(nGrids - 1)) ? v100 + nOutputCh : v100;
v110 = (cellB < (DWORD)(nGrids - 1)) ? v100 + nOutputCh * nGrids : v100;
v111 = (cellC < (DWORD)(nGrids - 1)) ? v110 + nOutputCh : v110;
for (idx=0; idx<nOutputCh; idx++)
{
// Calculate the average of 4 bottom cells.
fVx0x = *v000 + fC * (int)((int)*v001 - (int)*v000);
fVx1x = *v010 + fC * (int)((int)*v011 - (int)*v010);
fV0xx = fVx0x + fB * (fVx1x - fVx0x);
// Calculate the average of 4 upper cells.
fVx0x = *v100 + fC * (int)((int)*v101 - (int)*v100);
fVx1x = *v110 + fC * (int)((int)*v111 - (int)*v110);
fV1xx = fVx0x + fB * (fVx1x - fVx0x);
// Calculate the bottom and upper average.
pfTemp[idx] = (fV0xx + fA * (fV1xx - fV0xx)) / MAXCOLOR8;
if ( idx < (DWORD)(nOutputCh - 1))
{
v000++;
v001++;
v010++;
v011++;
v100++;
v101++;
v110++;
v111++;
}
}
return TRUE;
}
BOOL
TableInterp4(
PHOSTCLUT pHostClut,
float *pfTemp
)
{
PBYTE v0000, v0001, v0010, v0011;
PBYTE v0100, v0101, v0110, v0111;
PBYTE v1000, v1001, v1010, v1011;
PBYTE v1100, v1101, v1110, v1111;
float fH, fI, fJ, fK;
float fVxx0x, fVxx1x;
float fVx0xx, fVx1xx;
float fV0xxx, fV1xxx;
DWORD tmpH, tmpI, tmpJK;
DWORD cellH, cellI, cellJ, cellK;
DWORD idx;
WORD nGrids;
WORD nOutputCh;
cellH = (DWORD)pfTemp[0];
fH = pfTemp[0] - cellH;
cellI = (DWORD)pfTemp[1];
fI = pfTemp[1] - cellI;
cellJ = (DWORD)pfTemp[2];
fJ = pfTemp[2] - cellJ;
cellK = (DWORD)pfTemp[3];
fK = pfTemp[3] - cellK;
nGrids = pHostClut->nClutPoints;
nOutputCh = pHostClut->nOutputCh;
tmpI = nOutputCh * nGrids * nGrids;
tmpH = tmpI * nGrids;
tmpJK = nOutputCh * (nGrids * cellJ + cellK);
// Calculate 16 surrounding cells.
v0000 = pHostClut->clut + tmpH * cellH + tmpI * cellI + tmpJK;
v0001 = (cellK < (DWORD)(nGrids - 1))? v0000 + nOutputCh : v0000;
v0010 = (cellJ < (DWORD)(nGrids - 1))? v0000 + nOutputCh * nGrids : v0000;
v0011 = (cellK < (DWORD)(nGrids - 1))? v0010 + nOutputCh : v0010;
v0100 = (cellI < (DWORD)(nGrids - 1))? v0000 + tmpI : v0000;
v0101 = (cellK < (DWORD)(nGrids - 1))? v0100 + nOutputCh : v0100;
v0110 = (cellJ < (DWORD)(nGrids - 1))? v0100 + nOutputCh * nGrids : v0100;
v0111 = (cellK < (DWORD)(nGrids - 1))? v0110 + nOutputCh : v0110;
v1000 = (cellH < (DWORD)(nGrids - 1))? v0000 + tmpH : v0000;
v1001 = (cellK < (DWORD)(nGrids - 1))? v1000 + nOutputCh : v1000;
v1010 = (cellJ < (DWORD)(nGrids - 1))? v1000 + nOutputCh * nGrids : v1000;
v1011 = (cellK < (DWORD)(nGrids - 1))? v1010 + nOutputCh : v1010;
v1100 = (cellI < (DWORD)(nGrids - 1))? v1000 + tmpI : v1000;
v1101 = (cellK < (DWORD)(nGrids - 1))? v1100 + nOutputCh : v1100;
v1110 = (cellJ < (DWORD)(nGrids - 1))? v1100 + nOutputCh * nGrids : v1100;
v1111 = (cellK < (DWORD)(nGrids - 1))? v1110 + nOutputCh : v1110;
for (idx=0; idx<nOutputCh; idx++)
{
// Calculate the average of 8 bottom cells.
fVxx0x = *v0000 + fK * (int)((int)*v0001 - (int)*v0000);
fVxx1x = *v0010 + fK * (int)((int)*v0011 - (int)*v0010);
fVx0xx = fVxx0x + fJ * (fVxx1x - fVxx0x);
fVxx0x = *v0100 + fK * (int)((int)*v0101 - (int)*v0100);
fVxx1x = *v0110 + fK * (int)((int)*v0111 - (int)*v0110);
fVx1xx = fVxx0x + fJ * (fVxx1x - fVxx0x);
fV0xxx = fVx0xx + fI * (fVx1xx - fVx0xx);
// Calculate the average of 8 upper cells.
fVxx0x = *v1000 + fK * (int)((int)*v1001 - (int)*v1000);
fVxx1x = *v1010 + fK * (int)((int)*v1011 - (int)*v1010);
fVx0xx = fVxx0x + fJ * (fVxx1x - fVxx0x);
fVxx0x = *v1100 + fK * (int)((int)*v1101 - (int)*v1100);
fVxx1x = *v1110 + fK * (int)((int)*v1111 - (int)*v1110);
fVx1xx = fVxx0x + fJ * (fVxx1x - fVxx0x);
fV1xxx = fVx0xx + fI * (fVx1xx - fVx0xx);
// Calculate the bottom and upper average.
pfTemp[idx] = (fV0xxx + fH * (fV1xxx - fV0xxx)) / MAXCOLOR8;
if (idx < (DWORD)(nOutputCh - 1))
{
v0000++;
v0001++;
v0010++;
v0011++;
v0100++;
v0101++;
v0110++;
v0111++;
v1000++;
v1001++;
v1010++;
v1011++;
v1100++;
v1101++;
v1110++;
v1111++;
}
}
return TRUE;
}
BOOL
InvertColorantArray(
double *lpInMatrix,
double *lpOutMatrix)
{
double det;
double *a;
double *b;
double *c;
a = &(lpInMatrix[0]);
b = &(lpInMatrix[3]);
c = &(lpInMatrix[6]);
det = a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] -
(a[2] * b[1] * c[0] + a[1] * b[0] * c[2] + a[0] * b[2] * c[1]);
if (det == 0.0) // What to do?
{
lpOutMatrix[0] = 1.0;
lpOutMatrix[1] = 0.0;
lpOutMatrix[2] = 0.0;
lpOutMatrix[3] = 0.0;
lpOutMatrix[4] = 1.0;
lpOutMatrix[5] = 0.0;
lpOutMatrix[6] = 0.0;
lpOutMatrix[7] = 0.0;
lpOutMatrix[8] = 1.0;
}
else
{
lpOutMatrix[0] = (b[1] * c[2] - b[2] * c[1]) / det;
lpOutMatrix[3] = -(b[0] * c[2] - b[2] * c[0]) / det;
lpOutMatrix[6] = (b[0] * c[1] - b[1] * c[0]) / det;
lpOutMatrix[1] = -(a[1] * c[2] - a[2] * c[1]) / det;
lpOutMatrix[4] = (a[0] * c[2] - a[2] * c[0]) / det;
lpOutMatrix[7] = -(a[0] * c[1] - a[1] * c[0]) / det;
lpOutMatrix[2] = (a[1] * b[2] - a[2] * b[1]) / det;
lpOutMatrix[5] = -(a[0] * b[2] - a[2] * b[0]) / det;
lpOutMatrix[8] = (a[0] * b[1] - a[1] * b[0]) / det;
}
return (TRUE);
}
VOID
ApplyMatrix(
FIX_16_16 *e,
float *Input,
float *Output)
{
DWORD i, j;
for (i=0; i<3; i++)
{
j = i * 3;
Output[i] = ((e[j] * Input[0]) / FIX_16_16_SCALE) +
((e[j + 1] * Input[1]) / FIX_16_16_SCALE) +
((e[j + 2] * Input[2]) / FIX_16_16_SCALE);
}
}
/*
* 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
*/
BOOL
CheckColorLookupTable(
PHOSTCLUT pHostClut,
float *pfTemp
)
{
if (pHostClut->nInputCh == 3)
{
return TableInterp3(pHostClut, pfTemp);
}
else if (pHostClut->nInputCh == 4)
{
return TableInterp4(pHostClut, pfTemp);
}
else
return FALSE;
}
// For testing purposes
BOOL WINAPI
GetPS2PreviewCRD (
HPROFILE hDestProfile,
HPROFILE hTargetProfile,
DWORD dwIntent,
PBYTE pBuffer,
PDWORD pcbSize,
LPBOOL pbBinary
)
{
PPROFOBJ pDestProfObj;
PPROFOBJ pTargetProfObj;
pDestProfObj = (PPROFOBJ)HDLTOPTR(hDestProfile);
pTargetProfObj = (PPROFOBJ)HDLTOPTR(hTargetProfile);
return InternalGetPS2PreviewCRD(pDestProfObj->pView, pTargetProfObj->pView, dwIntent, pBuffer, pcbSize, pbBinary);
}
#endif // !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
/*
* Crc - 32 BIT ANSI X3.66 CRC checksum files
* Copyright (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
static DWORD crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
DWORD crc32(PBYTE buff, DWORD length)
{
DWORD crc, charcnt;
BYTE c;
crc = 0xFFFFFFFF;
charcnt = 0;
for (charcnt = 0 ; charcnt < length ; charcnt++)
{
c = buff[charcnt];
crc = crc_32_tab[(crc ^ c) & 0xff] ^ (crc >> 8);
}
return crc;
}
/*
* IsSRGBColorProfile
* function: check if the profile is sRGB
* parameters:
* cp -- Color Profile handle
* returns:
* BOOL -- TRUE if the profile is sRGB
* FALSE otherwise.
*/
BOOL IsSRGBColorProfile(
PBYTE pProfile
)
{
BOOL bMatch = FALSE;
DWORD dwRedTRCIndex, dwGreenTRCIndex, dwBlueTRCIndex;
DWORD dwRedCIndex, dwGreenCIndex, dwBlueCIndex;
DWORD dwSize;
DWORD dwRedTRCSize=0, dwGreenTRCSize=0, dwBlueTRCSize=0;
DWORD dwRedCSize=0, dwGreenCSize=0, dwBlueCSize=0;
PBYTE pRed, pGreen, pBlue, pRedC, pGreenC, pBlueC;
BYTE DataBuffer[ALIGN_DWORD(sRGB_TAGSIZE)];
if (DoesCPTagExist(pProfile, TAG_REDTRC, &dwRedTRCIndex) &&
GetCPElementDataSize(pProfile, dwRedTRCIndex, &dwRedTRCSize) &&
DoesCPTagExist(pProfile, TAG_GREENTRC, &dwGreenTRCIndex) &&
GetCPElementDataSize(pProfile, dwGreenTRCIndex, &dwGreenTRCSize) &&
DoesCPTagExist(pProfile, TAG_BLUETRC, &dwBlueTRCIndex) &&
GetCPElementDataSize(pProfile, dwBlueTRCIndex, &dwBlueTRCSize) &&
DoesCPTagExist(pProfile, TAG_REDCOLORANT, &dwRedCIndex) &&
GetCPElementDataSize(pProfile, dwRedCIndex, &dwRedCSize) &&
DoesCPTagExist(pProfile, TAG_GREENCOLORANT, &dwGreenCIndex) &&
GetCPElementDataSize(pProfile, dwGreenCIndex, &dwGreenCSize) &&
DoesCPTagExist(pProfile, TAG_BLUECOLORANT, &dwBlueCIndex) &&
GetCPElementDataSize(pProfile, dwBlueCIndex, &dwBlueCSize))
{
dwSize = dwRedTRCSize + dwGreenTRCSize + dwBlueTRCSize +
dwRedCSize + dwGreenCSize + dwBlueCSize;
if (dwSize == sRGB_TAGSIZE)
{
ZeroMemory(DataBuffer,sizeof(DataBuffer));
pRed = DataBuffer;
pGreen = pRed + dwRedTRCSize;
pBlue = pGreen + dwGreenTRCSize;
pRedC = pBlue + dwBlueTRCSize;
pGreenC = pRedC + dwRedCSize;
pBlueC = pGreenC + dwGreenCSize;
if (GetCPElementData(pProfile, dwRedTRCIndex, pRed, &dwRedTRCSize) &&
GetCPElementData(pProfile, dwGreenTRCIndex, pGreen, &dwGreenTRCSize) &&
GetCPElementData(pProfile, dwBlueTRCIndex, pBlue, &dwBlueTRCSize) &&
GetCPElementData(pProfile, dwRedCIndex, pRedC, &dwRedCSize) &&
GetCPElementData(pProfile, dwGreenCIndex, pGreenC, &dwGreenCSize) &&
GetCPElementData(pProfile, dwBlueCIndex, pBlueC, &dwBlueCSize))
{
bMatch = (crc32(DataBuffer, sRGB_TAGSIZE) == sRGB_CRC);
}
}
}
return (bMatch);
}