#ifndef ICC_H
#define ICC_H
/*
 * International Color Consortium Format Library (icclib)
 *
 * Author:  Graeme W. Gill
 * Date:    99/11/29
 * Version: 2.01
 *
 * Copyright 1997, 1998, 1999, 2000, 2001 Graeme W. Gill
 * Please refer to Licence.txt file for details.
 */

/* We can get some subtle errors if certain headers aren't included */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>

/*
 *  Note XYZ scaling to 1.0, not 100.0
 */

/* Make allowance for shared library use */
#ifdef ICCLIB_SHARED		/* Compiling or Using shared library version */
# ifdef ICCLIB_EXPORTS		/* Compiling shared library */
#  ifdef NT
#   define ICCLIB_API __declspec(dllexport)
#  endif /* NT */
# else						/* Using shared library */
#  ifdef NT
#   define ICCLIB_API __declspec(dllimport)
#   ifdef ICCLIB_DEBUG
#    pragma comment (lib, "icclibd.lib")
#   else
#    pragma comment (lib, "icclib.lib")
#   endif	/* DEBUG */
#  endif /* NT */
# endif
#else						/* Using static library */
# define ICCLIB_API	/* empty */
#endif

#ifdef __cplusplus
        extern "C" {
#endif

/* ---------------------------------------------- */
/* Platform specific defines */
/* It is assumed that the native machine size is 32 bits */
#ifndef INR8
#define INR8   signed char		/* 8 bit signed */
#endif
#ifndef INR16
#define INR16  signed short		/* 16 bit signed */
#endif
#ifndef INR32
#define INR32  signed long		/* 32 bit signed */
#endif
#ifndef ORD8
#define ORD8   unsigned char	/* 8 bit unsigned */
#endif
#ifndef ORD16
#define ORD16  unsigned short	/* 16 bit unsigned */
#endif
#ifndef ORD32
#define ORD32  unsigned long	/* 32 bit unsigned */
#endif

#include "icc9809.h"	/* Standard ICC definitions, version ICC.1:1998-09 with mods noted. */

/* Note that the prefix icm is used for the native Machine */
/* equivalents of the file structures defined in icc34.h */

/* ---------------------------------------------- */
/* System interface objects. The defaults can be replaced */
/* for adaption to different system environments */

/* File access class interface definition */
#define ICM_FILE_BASE																		\
        /* Public: */																			\
                                                                                                                                                                                        \
        /* Set current position to offset. Return 0 on success, nz on failure. */				\
        int    (*seek) (struct _icmFile *p, long int offset);									\
                                                                                                                                                                                        \
        /* Read count items of size length. Return number of items successfully read. */ 		\
        size_t (*read) (struct _icmFile *p, void *buffer, size_t size, size_t count);			\
                                                                                                                                                                                        \
        /* write count items of size length. Return number of items successfully written. */ 	\
        size_t (*write)(struct _icmFile *p, void *buffer, size_t size, size_t count);			\
                                                                                                                                                                                        \
        /* flush all write data out to secondary storage. Return nz on failure. */				\
        int (*flush)(struct _icmFile *p);														\
                                                                                                                                                                                        \
        /* we're done with the file object, return nz on failure */								\
        int (*del)(struct _icmFile *p);															\

/* Common file interface class */
struct _icmFile {
        ICM_FILE_BASE
}; typedef struct _icmFile icmFile;

/* - - - - - - - - - - - - - - - - - - - - -  */

/* Implementation of file access class based on standard file I/O */
struct _icmFileStd {
        ICM_FILE_BASE

        /* Private: */
        FILE *fp;
        int   doclose;		/* nz if free should close */
}; typedef struct _icmFileStd icmFileStd;

/* Create given a file name */
icmFile *new_icmFileStd_name(char *name, char *mode);

/* Create given a (binary) FILE* */
icmFile *new_icmFileStd_fp(FILE *fp);

/* - - - - - - - - - - - - - - - - - - - - -  */
/* Implementation of file access class based on a memory image */
struct _icmFileMem {
        ICM_FILE_BASE

        /* Private: */
        unsigned char *start, *cur, *end;

}; typedef struct _icmFileMem icmFileMem;

/* Create a memory image file access class */
icmFile *new_icmFileMem(void *base, size_t length);

/* - - - - - - - - - - - - - - - - - - - - -  */
/* Heap allocator class interface definition */
#define ICM_ALLOC_BASE																		\
        /* Public: */																			\
                                                                                                                                                                                        \
        void *(*malloc) (struct _icmAlloc *p, size_t size);										\
        void *(*calloc) (struct _icmAlloc *p, size_t num, size_t size);							\
        void *(*realloc)(struct _icmAlloc *p, void *ptr, size_t size);							\
        void  (*free)   (struct _icmAlloc *p, void *ptr);										\
                                                                                                                                                                                        \
        /* we're done with the allocator object */												\
        void (*del)(struct _icmAlloc *p);														\

/* Common heap allocator interface class */
struct _icmAlloc {
        ICM_ALLOC_BASE
}; typedef struct _icmAlloc icmAlloc;

/* - - - - - - - - - - - - - - - - - - - - -  */

/* Implementation of heap class based on standard system malloc */
struct _icmAllocStd {
        ICM_ALLOC_BASE
}; typedef struct _icmAllocStd icmAllocStd;

/* Create a standard alloc object */
icmAlloc *new_icmAllocStd(void);

/* --------------------------------- */
/* Assumed constants                 */

#define MAX_CHAN 15		/* Maximum number of color channels */

/* --------------------------------- */
/* tag and other compound structures */

typedef int icmSig;	/* Otherwise un-enumerated 4 byte signature */

typedef struct {
        ORD32 l;			/* High and low components of signed 64 bit */
        INR32 h;
} icmInt64;

typedef struct {
        ORD32 l,h;			/* High and low components of unsigned 64 bit */
} icmUint64;

/* XYZ Number */
typedef struct {
    double  X;
    double  Y;
    double  Z;
} icmXYZNumber;

/* Response 16 number */
typedef struct {
        double	       deviceValue;	/* The device value in range 0.0 - 1.0 */
        double	       measurement;	/* The reading value */
} icmResponse16Number;

/*
 *  read and write method error codes:
 *  0 = sucess
 *  1 = file format/logistical error
 *  2 = system error
 */

#define ICM_BASE_MEMBERS																\
        /* Private: */																		\
        icTagTypeSignature  ttype;		/* The tag type signature */						\
        struct _icc    *icp;			/* Pointer to ICC we're a part of */				\
        int	           touched;			/* Flag for write bookeeping */						\
    int            refcount;		/* Reference count for sharing */					\
        unsigned int   (*get_size)(struct _icmBase *p);										\
        int            (*read)(struct _icmBase *p, unsigned long len, unsigned long of);	\
        int            (*write)(struct _icmBase *p, unsigned long of);						\
        void           (*del)(struct _icmBase *p);											\
                                                                                                                                                                                \
        /* Public: */																		\
        void           (*dump)(struct _icmBase *p, FILE *op, int verb);						\
        int            (*allocate)(struct _icmBase *p);

/* Base tag element data object */
struct _icmBase {
        ICM_BASE_MEMBERS
}; typedef struct _icmBase icmBase;

/* UInt8 Array */
struct _icmUInt8Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    unsigned int   *data;		/* Pointer to array of data */
}; typedef struct _icmUInt8Array icmUInt8Array;

/* uInt16 Array */
struct _icmUInt16Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    unsigned int	*data;		/* Pointer to array of data */
}; typedef struct _icmUInt16Array icmUInt16Array;

/* uInt32 Array */
struct _icmUInt32Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    unsigned int	*data;		/* Pointer to array of data */
}; typedef struct _icmUInt32Array icmUInt32Array;

/* UInt64 Array */
struct _icmUInt64Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    icmUint64		*data;		/* Pointer to array of hight data */
}; typedef struct _icmUInt64Array icmUInt64Array;

/* u16Fixed16 Array */
struct _icmU16Fixed16Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    double			*data;		/* Pointer to array of hight data */
}; typedef struct _icmU16Fixed16Array icmU16Fixed16Array;

/* s15Fixed16 Array */
struct _icmS15Fixed16Array {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    double			*data;		/* Pointer to array of hight data */
}; typedef struct _icmS15Fixed16Array icmS15Fixed16Array;

/* XYZ Array */
struct _icmXYZArray {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	size;		/* Allocated and used size of the array */
    icmXYZNumber	*data;		/* Pointer to array of data */
}; typedef struct _icmXYZArray icmXYZArray;

/* Curve */
typedef enum {
    icmCurveUndef           = -1, /* Undefined curve */
    icmCurveLin             = 0,  /* Linear transfer curve */
    icmCurveGamma           = 1,  /* Gamma power transfer curve */
    icmCurveSpec            = 2   /* Specified curve */
} icmCurveStyle;

/* Curve reverse lookup information */
typedef struct {
        int inited;				/* Flag */
        double rmin, rmax;		/* Range of reverse grid */
        double qscale;			/* Quantising scale factor */
        long rsize;				/* Number of reverse lists */
        int **rlists;			/* Array of list of fwd values that may contain output value */
                                                        /* Offset 0 = allocated size */
                                                        /* Offset 1 = next free index */
                                                        /* Offset 2 = first fwd index */
        unsigned long size;		/* Copy of forward table size */
        double       *data;		/* Copy of forward table data */
} icmRevTable;

struct _icmCurve {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */
        icmRevTable  rt;			/* Reverse table information */

        /* Public: */
    icmCurveStyle   flag;		/* Style of curve */
        unsigned long	size;		/* Allocated and used size of the array */
    double         *data;  		/* Curve data scaled to range 0.0 - 1.0 */
                                                                /* or data[0] = gamma value */
        /* Translate a value through the curve, return warning flags */
        int (*lookup_fwd) (struct _icmCurve *p, double *out, double *in);	/* Forwards */
        int (*lookup_bwd) (struct _icmCurve *p, double *out, double *in);	/* Backwards */

}; typedef struct _icmCurve icmCurve;

/* Data */
typedef enum {
    icmDataUndef           = -1, /* Undefined data curve */
    icmDataASCII           = 0,  /* ASCII data curve */
    icmDataBin             = 1   /* Binary data */
} icmDataStyle;

struct _icmData {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
    icmDataStyle	flag;		/* Style of data */
        unsigned long	size;		/* Allocated and used size of the array (inc ascii null) */
    unsigned char	*data;  	/* data or string, NULL if size == 0 */
}; typedef struct _icmData icmData;

/* text */
struct _icmText {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _size;		/* Size currently allocated */

        /* Public: */
        unsigned long	 size;		/* Allocated and used size of desc, inc null */
        char             *data;		/* ascii string (null terminated), NULL if size==0 */
}; typedef struct _icmText icmText;

/* The base date time number */
struct _icmDateTimeNumber {
        ICM_BASE_MEMBERS

        /* Public: */
    unsigned int      year;
    unsigned int      month;
    unsigned int      day;
    unsigned int      hours;
    unsigned int      minutes;
    unsigned int      seconds;
}; typedef struct _icmDateTimeNumber icmDateTimeNumber;

#ifdef NEW
/ * DeviceSettings */

/*
   I think this all works like this:

Valid setting = (   (platform == platform1 and platform1.valid)
                 or (platform == platform2 and platform2.valid)
                 or ...
                )

where
        platformN.valid = (   platformN.combination1.valid
                           or platformN.combination2.valid
                           or ...
                          )

where
        platformN.combinationM.valid = (    platformN.combinationM.settingstruct1.valid
                                        and platformN.combinationM.settingstruct2.valid
                                        and ...
                                       )

where
        platformN.combinationM.settingstructP.valid = (   platformN.combinationM.settingstructP.setting1.valid
                                                       or platformN.combinationM.settingstructP.setting2.valid
                                                       or ...
                                                      )

 */

/* The Settings Structure holds an array of settings of a particular type */
struct _icmSettingStruct {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _num;				/* Size currently allocated */

        /* Public: */
        icSettingsSig       settingSig;		/* Setting identification */
        unsigned long       numSettings; 	/* number of setting values */
        union {								/* Setting values - type depends on Sig */
                icUInt64Number      *resolution;
                icDeviceMedia       *media;
                icDeviceDither      *halftone;
        }
}; typedef struct _icmSettingStruct icmSettingStruct;

/* A Setting Combination holds all arrays of different setting types */
struct _icmSettingComb {
        /* Private: */
        unsigned int   _num;			/* number currently allocated */

        /* Public: */
        unsigned long       numStructs;   /* num of setting structures */
        icmSettingStruct    *data;
}; typedef struct _icmSettingComb icmSettingComb;

/* A Platform Entry holds all setting combinations */
struct _icmPlatformEntry {
        /* Private: */
        unsigned int   _num;			/* number currently allocated */

        /* Public: */
        icPlatformSignature platform;
        unsigned long       numCombinations;    /* num of settings and allocated array size */
        icmSettingComb      *data;
}; typedef struct _icmPlatformEntry icmPlatformEntry;

/* The Device Settings holds all platform settings */
struct _icmDeviceSettings {
        /* Private: */
        unsigned int   _num;			/* number currently allocated */

        /* Public: */
        unsigned long       numPlatforms;	/* num of platforms and allocated array size */
        icmPlatformEntry    *data;			/* Array of pointers to platform entry data */
}; typedef struct _icmDeviceSettings icmDeviceSettings;

#endif /* NEW */

/* lut */
struct _icmLut {
        ICM_BASE_MEMBERS

        /* Private: */
        /* Cache appropriate normalization routines */
        int dinc[MAX_CHAN];				/* Dimensional increment through clut */
        int dcube[1 << MAX_CHAN];		/* Hyper cube offsets */
        icmRevTable  rit;				/* Reverse input table information */
        icmRevTable  rot;				/* Reverse output table information */

        unsigned int inputTable_size;	/* size allocated to input table */
        unsigned int clutTable_size;	/* size allocated to clut table */
        unsigned int outputTable_size;	/* size allocated to output table */

        /* return the minimum and maximum values of the given channel in the clut */
        void (*min_max) (struct _icmLut *pp, double *minv, double *maxv, int chan);

        /* Translate color values through 3x3 matrix, input tables only, multi-dimensional lut, */
        /* or output tables, */
        int (*lookup_matrix)  (struct _icmLut *pp, double *out, double *in);
        int (*lookup_input)   (struct _icmLut *pp, double *out, double *in);
        int (*lookup_clut_nl) (struct _icmLut *pp, double *out, double *in);
        int (*lookup_clut_sx) (struct _icmLut *pp, double *out, double *in);
        int (*lookup_output)  (struct _icmLut *pp, double *out, double *in);

        /* Public: */

        /* return non zero if matrix is non-unity */
        int (*nu_matrix) (struct _icmLut *pp);

    unsigned int	inputChan;      /* Num of input channels */
    unsigned int	outputChan;     /* Num of output channels */
    unsigned int	clutPoints;     /* Num of grid points */
    unsigned int	inputEnt;       /* Num of in-table entries (must be 256 for Lut8) */
    unsigned int	outputEnt;      /* Num of out-table entries (must be 256 for Lut8) */
    double			e[3][3];		/* 3 * 3 array */
        double	        *inputTable;	/* The in-table: [inputChan * inputEnt] */
        double	        *clutTable;		/* The clut: [(clutPoints ^ inputChan) * outputChan] */
        double	        *outputTable;	/* The out-table: [outputChan * outputEnt] */
        /* inputTable  is organized [inputChan 0..ic-1][inputEnt 0..ie-1] */
        /* clutTable   is organized [inputChan 0, 0..cp-1]..[inputChan ic-1, 0..cp-1]
                                                                        [outputChan 0..oc-1] */
        /* outputTable is organized [outputChan 0..oc-1][outputEnt 0..oe-1] */

        /* Helper function to setup the three tables contents */
        int (*set_tables) (
                struct _icmLut *p,						/* Pointer to Lut object */
                void   *cbctx,							/* Opaque callback context pointer value */
                icColorSpaceSignature insig, 			/* Input color space */
                icColorSpaceSignature outsig, 			/* Output color space */
                void (*infunc)(void *cbctx, double *out, double *in),
                                                                /* Input transfer function, inspace->inspace' (NULL = default) */
                double *inmin, double *inmax,			/* Maximum range of inspace' values */
                                                                                                /* (NULL = default) */
                void (*clutfunc)(void *cbntx, double *out, double *in),
                                                                /* inspace' -> outspace' transfer function */
                double *clutmin, double *clutmax,		/* Maximum range of outspace' values */
                                                                                                /* (NULL = default) */
                void (*outfunc)(void *cbntx, double *out, double *in));
                                                                /* Output transfer function, outspace'->outspace (NULL = deflt) */

}; typedef struct _icmLut icmLut;

/* Measurement Data */
struct _icmMeasurement {
        ICM_BASE_MEMBERS

        /* Public: */
    icStandardObserver           observer;       /* Standard observer */
    icmXYZNumber                 backing;        /* XYZ for backing */
    icMeasurementGeometry        geometry;       /* Meas. geometry */
    double                       flare;          /* Measurement flare */
    icIlluminant                 illuminant;     /* Illuminant */
}; typedef struct _icmMeasurement icmMeasurement;

/* Named color */

/* Structure that holds each named color data */
typedef struct {
        struct _icc      *icp;				/* Pointer to ICC we're a part of */
        char              root[32];			/* Root name for color */
        double            pcsCoords[3];		/* icmNC2: PCS coords of color */
        double            deviceCoords[MAX_CHAN];	/* Dev coords of color */
} icmNamedColorVal;

struct _icmNamedColor {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int      _count;			/* Count currently allocated */

        /* Public: */
    unsigned int      vendorFlag;		/* Bottom 16 bits for IC use */
    unsigned int      count;			/* Count of named colors */
    unsigned int      nDeviceCoords;	/* Num of device coordinates */
    char              prefix[32];		/* Prefix for each color name (null terminated) */
    char              suffix[32];		/* Suffix for each color name (null terminated) */
    icmNamedColorVal  *data;			/* Array of [count] color values */
}; typedef struct _icmNamedColor icmNamedColor;

/* textDescription */
struct _icmTextDescription {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned long  _size;			/* Size currently allocated */
        unsigned long  uc_size;			/* uc Size currently allocated */
        int            (*core_read)(struct _icmTextDescription *p, char **bpp, char *end);
        int            (*core_write)(struct _icmTextDescription *p, char **bpp);

        /* Public: */
        unsigned long	  size;			/* Allocated and used size of desc, inc null */
        char              *desc;		/* ascii string (null terminated) */

        unsigned int      ucLangCode;	/* UniCode language code */
        unsigned long	  ucSize;		/* Allocated and used size of ucDesc in wchars, inc null */
        ORD16             *ucDesc;		/* The UniCode description (null terminated) */

        ORD16             scCode;		/* ScriptCode code */
        unsigned long	  scSize;		/* Used size of scDesc in bytes, inc null */
        ORD8              scDesc[67];	/* ScriptCode Description (null terminated, max 67) */
}; typedef struct _icmTextDescription icmTextDescription;

/* Profile sequence structure */
struct _icmDescStruct {
        /* Private: */
        struct _icc      *icp;				/* Pointer to ICC we're a part of */

        /* Public: */
        int             (*allocate)(struct _icmDescStruct *p);	/* Allocate method */
    icmSig            deviceMfg;		/* Dev Manufacturer */
    unsigned int      deviceModel;		/* Dev Model */
    icmUint64         attributes;		/* Dev attributes */
    icTechnologySignature technology;	/* Technology sig */
        icmTextDescription device;			/* Manufacturer text (sub structure) */
        icmTextDescription model;			/* Model text (sub structure) */
}; typedef struct _icmDescStruct icmDescStruct;

/* Profile sequence description */
struct _icmProfileSequenceDesc {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int	 _count;			/* number currently allocated */

        /* Public: */
    unsigned int      count;			/* Number of descriptions */
        icmDescStruct     *data;			/* array of [count] descriptions */
}; typedef struct _icmProfileSequenceDesc icmProfileSequenceDesc;

/* signature (only ever used for technology ??) */
struct _icmSignature {
        ICM_BASE_MEMBERS

        /* Public: */
    icTechnologySignature sig;	/* Signature */
}; typedef struct _icmSignature icmSignature;

/* Per channel Screening Data */
typedef struct {
        /* Public: */
    double            frequency;		/* Frequency */
    double            angle;			/* Screen angle */
    icSpotShape       spotShape;		/* Spot Shape encodings below */
} icmScreeningData;

struct _icmScreening {
        ICM_BASE_MEMBERS

        /* Private: */
        unsigned int   _channels;			/* number currently allocated */

        /* Public: */
    unsigned int      screeningFlag;	/* Screening flag */
    unsigned int      channels;			/* Number of channels */
    icmScreeningData  *data;			/* Array of screening data */
}; typedef struct _icmScreening icmScreening;

/* Under color removal, black generation */
struct _icmUcrBg {
        ICM_BASE_MEMBERS

        /* Private: */
    unsigned int      UCR_count;		/* Currently allocated UCR count */
    unsigned int      BG_count;			/* Currently allocated BG count */
        unsigned long	  _size;			/* Currently allocated string size */

        /* Public: */
    unsigned int      UCRcount;			/* Undercolor Removal Curve length */
    double           *UCRcurve;		    /* The array of UCR curve values, 0.0 - 1.0 */
                                                                                /* or 0.0 - 100 % if count = 1 */
    unsigned int      BGcount;			/* Black generation Curve length */
    double           *BGcurve;			/* The array of BG curve values, 0.0 - 1.0 */
                                                                                /* or 0.0 - 100 % if count = 1 */
        unsigned long	  size;				/* Allocated and used size of desc, inc null */
        char              *string;			/* UcrBg description (null terminated) */
}; typedef struct _icmUcrBg icmUcrBg;

/* viewingConditionsType */
struct _icmViewingConditions {
        ICM_BASE_MEMBERS

        /* Public: */
    icmXYZNumber    illuminant;		/* In candelas per sq. meter */
    icmXYZNumber    surround;		/* In candelas per sq. meter */
    icIlluminant    stdIlluminant;	/* See icIlluminant defines */
}; typedef struct _icmViewingConditions icmViewingConditions;

/* Postscript Color Rendering Dictionary names type */
struct _icmCrdInfo {
        ICM_BASE_MEMBERS
        /* Private: */
    unsigned long    _ppsize;		/* Currently allocated size */
        unsigned long    _crdsize[4];	/* Currently allocated sizes */

        /* Public: */
    unsigned long    ppsize;		/* Postscript product name size (including null) */
    char            *ppname;		/* Postscript product name (null terminated) */
        unsigned long    crdsize[4];	/* Rendering intent 0-3 CRD names sizes (icluding null) */
        char            *crdname[4];	/* Rendering intent 0-3 CRD names (null terminated) */
}; typedef struct _icmCrdInfo icmCrdInfo;

/* Apple ColorSync 2.5 video card gamma type */
struct _icmVideoCardGammaTable {
        unsigned short   channels;		/* # of gamma channels (1 or 3) */
        unsigned short   entryCount; 	/* 1-based number of entries per channel */
        unsigned short   entrySize;		/* size in bytes of each entry */
        void            *data;			/* variable size data */
}; typedef struct _icmVideoCardGammaTable icmVideoCardGammaTable;

struct _icmVideoCardGammaFormula {
        double           redGamma;		/* must be > 0.0 */
        double           redMin;		/* must be > 0.0 and < 1.0 */
        double           redMax;		/* must be > 0.0 and < 1.0 */
        double           greenGamma;   	/* must be > 0.0 */
        double           greenMin;		/* must be > 0.0 and < 1.0 */
        double           greenMax;		/* must be > 0.0 and < 1.0 */
        double           blueGamma;		/* must be > 0.0 */
        double           blueMin;		/* must be > 0.0 and < 1.0 */
        double           blueMax;		/* must be > 0.0 and < 1.0 */
}; typedef struct _icmVideoCardGammaFormula icmVideoCardGammaFormula;

enum {
        icmVideoCardGammaTableType = 0,
        icmVideoCardGammaFormulaType = 1
};

struct _icmVideoCardGamma {
        ICM_BASE_MEMBERS
        unsigned long                tagType;		/* eg. table or formula, use above enum */
        union {
                icmVideoCardGammaTable   table;
                icmVideoCardGammaFormula formula;
        } u;
}; typedef struct _icmVideoCardGamma icmVideoCardGamma;

/* ------------------------------------------------- */
/* The Profile header */
struct _icmHeader {
        /* Private: */
        unsigned int           (*get_size)(struct _icmHeader *p);
        int                    (*read)(struct _icmHeader *p, unsigned long len, unsigned long of);
        int                    (*write)(struct _icmHeader *p, unsigned long of);
        void                   (*del)(struct _icmHeader *p);
        struct _icc            *icp;			/* Pointer to ICC we're a part of */
    unsigned int            size;			/* Profile size in bytes */

        /* public: */
        void                   (*dump)(struct _icmHeader *p, FILE *op, int verb);

        /* Values that must be set before writing */
    icProfileClassSignature deviceClass;	/* Type of profile */
    icColorSpaceSignature   colorSpace;		/* Clr space of data */
    icColorSpaceSignature   pcs;			/* PCS: XYZ or Lab */
    icRenderingIntent       renderingIntent;/* Rendering intent */

        /* Values that should be set before writing */
    icmSig                  manufacturer;	/* Dev manufacturer */
    icmSig		            model;			/* Dev model */
    icmUint64               attributes;		/* Device attributes.l */
    unsigned int            flags;			/* Various bits */

        /* Values that may optionally be set before writing */
    /* icmUint64            attributes;		   Device attributes.h (see above) */
    icmSig                  creator;		/* Profile creator */

        /* Values that are not normally set, since they have defaults */
    icmSig                  cmmId;			/* CMM for profile */
    int            			majv, minv, bfv;/* Format version - major, minor, bug fix */
    icmDateTimeNumber       date;			/* Creation Date */
    icPlatformSignature     platform;		/* Primary Platform */
    icmXYZNumber            illuminant;		/* Profile illuminant */

}; typedef struct _icmHeader icmHeader;

/* ---------------------------------------------------------- */
/* Objects for accessing lookup functions */

/* Public: Parameter to get_luobj function */
typedef enum {
    icmFwd           = 0,  /* Device to PCS, or Device 1 to Last Device */
    icmBwd           = 1,  /* PCS to Device, or Last Device to Device */
    icmGamut         = 2,  /* PCS Gamut check */
    icmPreview       = 3   /* PCS to PCS preview */
} icmLookupFunc;

/* Public: Parameter to get_luobj function */
typedef enum {
    icmLuOrdNorm     = 0,  /* Normal profile preference: Lut, matrix, monochrome */
    icmLuOrdRev      = 1   /* Reverse profile preference: monochrome, matrix, monochrome */
} icmLookupOrder;

/* Public: Lookup algorithm object type */
typedef enum {
    icmMonoFwdType       = 0,	/* Monochrome, Forward */
    icmMonoBwdType       = 1,	/* Monochrome, Backward */
    icmMatrixFwdType     = 2,	/* Matrix, Forward */
    icmMatrixBwdType     = 3,	/* Matrix, Backward */
    icmLutType           = 4	/* Multi-dimensional Lookup Table */
} icmLuAlgType;

#define LU_ICM_BASE_MEMBERS																	\
        /* Private: */																		\
        icmLuAlgType   ttype;		    	/* The object tag */							\
        struct _icc    *icp;				/* Pointer to ICC we're a part of */			\
        icRenderingIntent intent;			/* Effective intent */							\
        icmLookupFunc function;				/* Functionality being used */					\
        icmXYZNumber pcswht, whitePoint, blackPoint;	/* White and black point info */	\
        double toAbs[3][3];					/* Matrix to convert from relative to absolute */ \
        double fromAbs[3][3];				/* Matrix to convert from absolute to relative */ \
    icColorSpaceSignature inSpace;		/* Native Clr space of input */					\
    icColorSpaceSignature outSpace;		/* Native Clr space of output */				\
        icColorSpaceSignature pcs;			/* Native PCS */								\
    icColorSpaceSignature e_inSpace;	/* Effective Clr space of input */				\
    icColorSpaceSignature e_outSpace;	/* Effective Clr space of output */				\
        icColorSpaceSignature e_pcs;		/* Effective PCS */								\
                                                                                                                                                                                \
        /* Public: */																		\
        void           (*del)(struct _icmLuBase *p);										\
                                    /* Internal native colorspaces */     							\
        void           (*lutspaces) (struct _icmLuBase *p, icColorSpaceSignature *ins, int *inn,	\
                                                           icColorSpaceSignature *outs, int *outn);	\
                                                                                                \
                                 /* External effecive colorspaces */							\
        void           (*spaces) (struct _icmLuBase *p, icColorSpaceSignature *ins, int *inn,	\
                                         icColorSpaceSignature *outs, int *outn,				\
                                         icmLuAlgType *alg, icRenderingIntent *intt, 			\
                                         icmLookupFunc *fnc, icColorSpaceSignature *pcs); 		\
                                                                                                                                                                                        \
        /* Get the effective input space and output space ranges */								\
        void (*get_ranges) (struct _icmLuBase *p,												\
                double *inmin, double *inmax,		/* Maximum range of inspace values */			\
                double *outmin, double *outmax);	/* Maximum range of outspace values */			\
                                                                                                                                                                                        \
        void           (*wh_bk_points)(struct _icmLuBase *p, icmXYZNumber *wht, icmXYZNumber *blk);	\
        int            (*lookup) (struct _icmLuBase *p, double *out, double *in);

        /* Translate color values through profile */
        /* 0 = success */
        /* 1 = warning: clipping occured */
        /* 2 = fatal: other error */

/* Base lookup object */
struct _icmLuBase {
        LU_ICM_BASE_MEMBERS
}; typedef struct _icmLuBase icmLuBase;

/* Monochrome  Fwd & Bwd type object */
struct _icmLuMono {
        LU_ICM_BASE_MEMBERS
        icmCurve    *grayCurve;

        /* Overall lookups */
        int (*fwd_lookup) (struct _icmLuBase *p, double *out, double *in);
        int (*bwd_lookup) (struct _icmLuBase *p, double *out, double *in);

        /* Components of lookup */
        int (*fwd_curve) (struct _icmLuMono *p, double *out, double *in);
        int (*fwd_map)   (struct _icmLuMono *p, double *out, double *in);
        int (*fwd_abs)   (struct _icmLuMono *p, double *out, double *in);
        int (*bwd_abs)   (struct _icmLuMono *p, double *out, double *in);
        int (*bwd_map)   (struct _icmLuMono *p, double *out, double *in);
        int (*bwd_curve) (struct _icmLuMono *p, double *out, double *in);

}; typedef struct _icmLuMono icmLuMono;

/* 3D Matrix Fwd & Bwd type object */
struct _icmLuMatrix {
        LU_ICM_BASE_MEMBERS
        icmCurve    *redCurve, *greenCurve, *blueCurve;
        icmXYZArray *redColrnt, *greenColrnt, *blueColrnt;
    double		mx[3][3];	/* 3 * 3 conversion matrix */
    double		bmx[3][3];	/* 3 * 3 backwards conversion matrix */

        /* Overall lookups */
        int (*fwd_lookup) (struct _icmLuBase *p, double *out, double *in);
        int (*bwd_lookup) (struct _icmLuBase *p, double *out, double *in);

        /* Components of lookup */
        int (*fwd_curve)  (struct _icmLuMatrix *p, double *out, double *in);
        int (*fwd_matrix) (struct _icmLuMatrix *p, double *out, double *in);
        int (*fwd_abs)    (struct _icmLuMatrix *p, double *out, double *in);
        int (*bwd_abs)    (struct _icmLuMatrix *p, double *out, double *in);
        int (*bwd_matrix) (struct _icmLuMatrix *p, double *out, double *in);
        int (*bwd_curve)  (struct _icmLuMatrix *p, double *out, double *in);

}; typedef struct _icmLuMatrix icmLuMatrix;

/* Multi-D. Lut type object */
struct _icmLuLut {
        LU_ICM_BASE_MEMBERS

        /* private: */
        icmLut *lut;								/* Lut to use */
        int    usematrix;							/* non-zero if matrix should be used */
    double imx[3][3];							/* 3 * 3 inverse conversion matrix */
        int    imx_valid;							/* Inverse matrix is valid */
        void (*in_normf)(double *out, double *in);	/* Lut input data normalizing function */
        void (*in_denormf)(double *out, double *in);/* Lut input data de-normalizing function */
        void (*out_normf)(double *out, double *in);	/* Lut output data normalizing function */
        void (*out_denormf)(double *out, double *in);/* Lut output de-normalizing function */
        void (*e_in_denormf)(double *out, double *in);/* Effective input de-normalizing function */
        void (*e_out_denormf)(double *out, double *in);/* Effecive output de-normalizing function */
        /* function chosen out of lut->lookup_clut_sx and lut->lookup_clut_nl to imp. clut() */
        int (*lookup_clut) (struct _icmLut *pp, double *out, double *in);	/* clut function */

        /* public: */

        /* Components of lookup */
        int (*in_abs)  (struct _icmLuLut *p, double *out, double *in);	/* Should be in icmLut ? */
        int (*matrix)  (struct _icmLuLut *p, double *out, double *in);
        int (*input)   (struct _icmLuLut *p, double *out, double *in);
        int (*clut)    (struct _icmLuLut *p, double *out, double *in);
        int (*output)  (struct _icmLuLut *p, double *out, double *in);
        int (*out_abs) (struct _icmLuLut *p, double *out, double *in);	/* Should be in icmLut ? */

        /* Some inverse components */
        /* Should be in icmLut ??? */
        int (*inv_out_abs) (struct _icmLuLut *p, double *out, double *in);
        int (*inv_output)  (struct _icmLuLut *p, double *out, double *in);
        /* inv_clut is beyond scope of icclib. See argyll for solution! */
        int (*inv_input)   (struct _icmLuLut *p, double *out, double *in);
        int (*inv_matrix)  (struct _icmLuLut *p, double *out, double *in);
        int (*inv_in_abs)  (struct _icmLuLut *p, double *out, double *in);

        /* Get various types of information about the LuLut */
        void (*get_info) (struct _icmLuLut *p, icmLut **lutp,
                         icmXYZNumber *pcswhtp, icmXYZNumber *whitep,
                         icmXYZNumber *blackp);

        /* Get the native input space and output space ranges */
        void (*get_lutranges) (struct _icmLuLut *p,
                double *inmin, double *inmax,		/* Maximum range of inspace values */
                double *outmin, double *outmax);	/* Maximum range of outspace values */

        /* Get the matrix contents */
        void (*get_matrix) (struct _icmLuLut *p, double m[3][3]);

}; typedef struct _icmLuLut icmLuLut;

/* ---------------------------------------------------------- */
/* A tag */
typedef struct {
    icTagSignature      sig;			/* The tag signature */
        icTagTypeSignature  ttype;			/* The tag type signature */
    unsigned int        offset;			/* File offset to start header */
    unsigned int        size;			/* Size in bytes */
        icmBase            *objp;			/* In memory data structure */
} icmTag;

/* Pseudo enumerations valid as parameter to get_luobj(): */

/* To be specified where an intent is not appropriate */
#define icmDefaultIntent ((icRenderingIntent)98)

/* Pseudo PCS colospace used to indicate the native PCS */
#define icmSigDefaultData ((icColorSpaceSignature) 0x0)

/* The ICC object */
struct _icc {
        /* Public: */
        unsigned int (*get_size)(struct _icc *p);				/* Return total size needed, 0 = err. */
        int          (*read)(struct _icc *p, icmFile *fp, unsigned long of);	/* Returns error code */
        int          (*write)(struct _icc *p, icmFile *fp, unsigned long of);/* Returns error code */
        void         (*dump)(struct _icc *p, FILE *op, int verb);	/* Dump whole icc */
        void         (*del)(struct _icc *p);						/* Free whole icc */
        int          (*find_tag)(struct _icc *p, icTagSignature sig);
                                                                                                                        /* Returns 1 if found, 2 readable */
        icmBase *    (*read_tag)(struct _icc *p, icTagSignature sig);
                                                                                                                        /* Returns pointer to object */
        icmBase *    (*add_tag)(struct _icc *p, icTagSignature sig, icTagTypeSignature ttype);
                                                                                                                        /* Returns pointer to object */
        int          (*rename_tag)(struct _icc *p, icTagSignature sig, icTagSignature sigNew);
                                                                                                                        /* Rename and existing tag */
        icmBase *    (*link_tag)(struct _icc *p, icTagSignature sig, icTagSignature ex_sig);
                                                                                                                        /* Returns pointer to object */
        int          (*unread_tag)(struct _icc *p, icTagSignature sig);
                                                                                                                /* Unread a tag (free on refcount == 0 */
        int          (*read_all_tags)(struct _icc *p); /* Read all the tags, non-zero on error. */

        int          (*delete_tag)(struct _icc *p, icTagSignature sig);
                                                                                                                        /* Returns 0 if deleted OK */
        icmLuBase *  (*get_luobj) (struct _icc *p,
                                     icmLookupFunc func,			/* Functionality */
                                         icRenderingIntent intent,		/* Intent */
                                         icColorSpaceSignature pcsor,	/* PCS overide (0 = def) */
                                         icmLookupOrder order);			/* Search Order */
                                         /* Return appropriate lookup object */
                                         /* NULL on error, check errc+err for reason */

    icmHeader       *header;			/* The header */
        char             err[512];			/* Error message */
        int              errc;				/* Error code */

        /* Private: ? */
        icmAlloc        *al;				/* Heap allocator */
        int              del_al;			/* NZ if heap allocator should be deleted */
        icmFile         *fp;				/* File associated with object */
        unsigned long    of;				/* Offset of the profile within the file */
    unsigned int     count;				/* Num tags in the profile */
    icmTag          *data;    			/* The tagTable and tagData */

        }; typedef struct _icc icc;

/* ========================================================== */
/* Utility structures and declarations */

/* Structure to hold pseudo-hilbert counter info */
struct _psh {
        int      di;	/* Dimensionality */
        unsigned res;	/* Resolution per coordinate */
        unsigned bits;	/* Bits per coordinate */
        unsigned ix;	/* Current binary index */
        unsigned tmask;	/* Total 2^n count mask */
        unsigned count;	/* Usable count */
}; typedef struct _psh psh;

/* Type of encoding to be returned as a string */
typedef enum {
    icmScreenEncodings,
    icmDeviceAttributes,
        icmProfileHeaderFlags,
        icmAsciiOrBinaryData,
        icmTagSignature,
        icmTechnologySignature,
        icmTypeSignature,
        icmColorSpaceSignature,
        icmProfileClassSignaure,
        icmPlatformSignature,
        icmMeasurementFlare,
        icmMeasurementGeometry,
        icmRenderingIntent,
        icmSpotShape,
        icmStandardObserver,
        icmIlluminant,
        icmLuAlg
} icmEnumType;

/* ========================================================== */
/* Public function declarations */
/* Create an empty object. Return null on error */
extern ICCLIB_API icc *new_icc(void);				/* Default allocator */
extern ICCLIB_API icc *new_icc_a(icmAlloc *al);		/* With allocator class */

/* - - - - - - - - - - - - - */
/* Some useful utilities: */

/* Return a string that represents a tag */
extern ICCLIB_API char *tag2str(int tag);

/* Return a tag created from a string */
extern ICCLIB_API int str2tag(const char *str);

/* Return a string description of the given enumeration value */
extern ICCLIB_API const char *icm2str(icmEnumType etype, int enumval);

/* CIE XYZ to perceptual Lab */
extern ICCLIB_API void icmXYZ2Lab(icmXYZNumber *w, double *out, double *in);

/* Perceptual Lab to CIE XYZ */
extern ICCLIB_API void icmLab2XYZ(icmXYZNumber *w, double *out, double *in);

/* The standard D50 illuminant value */
extern ICCLIB_API icmXYZNumber icmD50;

/* The standard D65 illuminant value */
extern ICCLIB_API icmXYZNumber icmD65;

/* The default black value */
extern ICCLIB_API icmXYZNumber icmBlack;

/* Initialise a pseudo-hilbert grid counter, return total usable count. */
extern ICCLIB_API unsigned psh_init(psh *p, int di, unsigned res, int co[]);

/* Reset the counter */
extern ICCLIB_API void psh_reset(psh *p);

/* Increment pseudo-hilbert coordinates */
/* Return non-zero if count rolls over to 0 */
extern ICCLIB_API int psh_inc(psh *p, int co[]);

/* Chromatic Adaption transform utility */
/* Return a 3x3 chromatic adaption matrix */
void icmChromAdaptMatrix(
        int flags,				/* Flags as defined below */
        icmXYZNumber d_wp,		/* Destination white point */
        icmXYZNumber s_wp,		/* Source white point */
        double mat[3][3]		/* Destination matrix */
);

#define ICM_CAM_BRADFORD	0x0001	/* Use Bradford sharpened response space */
#define ICM_CAM_MULMATRIX	0x0002	/* Transform the given matrix */

/* Return the normal Delta E given two Lab values */
extern ICCLIB_API double icmLabDE(double *in1, double *in2);

/* Return the normal Delta E squared, given two Lab values */
extern ICCLIB_API double icmLabDEsq(double *in1, double *in2);

/* Return the CIE94 Delta E color difference measure for two Lab values */
extern ICCLIB_API double icmCIE94(double *in1, double *in2);

/* Return the CIE94 Delta E color difference measure squared, for two Lab values */
extern ICCLIB_API double icmCIE94sq(double *in1, double *in2);

/* Simple macro to transfer an array to an XYZ number */
#define icmAry2XYZ(xyz, ary) ((xyz).X = (ary)[0], (xyz).Y = (ary)[1], (xyz).Z = (ary)[2])

/* And the reverse */
#define icmXYZ2Ary(ary, xyz) ((ary)[0] = (xyz).X, (ary)[1] = (xyz).Y, (ary)[2] = (xyz).Z)

/* ---------------------------------------------------------- */

#ifdef __cplusplus
        }
#endif

#endif /* ICC_H */
