6915 lines
179 KiB
C
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);
|
|
}
|
|
|
|
|
|
|
|
|