#ifndef XICC_H
#define XICC_H
/* 
 * International Color Consortium color transform expanded support
 *
 * Author:  Graeme W. Gill
 * Date:    28/6/00
 * Version: 1.00
 *
 * Copyright 2000, 2011 Graeme W. Gill
 * All rights reserved.
 * This material is licenced under the GNU AFFERO GENERAL PUB LICENSE Version 3 :-
 * see the License.txt file for licencing details.
 *
 * Based on the old iccXfm class.
 */

/*
 * This library expands the icclib functionality,
 * particularly in creating and exercising color transforms.
 *
 * For the moment, this support is concentrated around the
 * Lut and Matrix subsets of the ICC profile tranforms.
 *
 * It is intended to allow color transformation, storage and retrieval
 * of ICC profiles, while permitting inititialization from scattered
 * data, reversing of the transform, and specific manipulations of
 * the internal processing elements.
 *
 * This class bases much of it's functionality on that of the
 * underlying icclib icmLuBase.
 */

#include "icc.h"		/* icclib ICC definitions */ 
#include "cgats.h"		/* CGAT format */	
#include "rspl.h"		/* rspllib thin plate spline definitions */
#include "gamut.h"		/* gamut definitions */
#include "xutils.h"		/* Utility functions */
#include "xcam.h"		/* CAM definitions */
#include "xspect.h"		/* Spectral conversion object */
#include "xcolorants.h"	/* Known colorants support */
#include "insttypes.h"	/* Instrument type support */
#include "mpp.h"		/* model printer profile support */
#include "moncurve.h"	/* monotonic curve support */
						/* (more at the end) */

#define XICC_USE_HK 1	/* [Set] Set to 1 to use Helmholtz-Kohlraush in all CAM conversions */
#define XICC_NEUTRAL_CMYK_BLACK		/* Use neutral axis black, else use K direction black. */
#define XICC_BLACK_POINT_TOLL 0.5			/* Tollerance of CMYK black point location */ 
#define XICC_BLACK_FIND_ABERR_WEIGHT 10.0	/* Weight of ab error against min L in BP */

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

/* The "effective" PCS colorspace is the one specified by the PCS override, and */
/* visible in the overal profile conversion. The "native" PCS colorspace is the one */
/* that the underlying tags actually represent, and the PCS that the individual */
/* stages within each profile type handle (unless the ICX_MERGED flag is set, in which */
/* case the clut == native PCS appears to be the effective one). The conversion between */
/* the native and effective PCS is generally done in the to/from_abs() conversions. */

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

/* Pseudo intents, valid as parameter to xicc get_luobj(): */

/* Default Color Appearance Space, based on absolute colorimetric */
#define icxAppearance ((icRenderingIntent)994)

/* Represents icAbsoluteColorimetric, converted to Color Appearance space */
#define icxAbsAppearance ((icRenderingIntent)995)	/* Fixed D50 white point */

/* Special Color Appearance Space, based on "absolute" perceptual */
#define icxPerceptualAppearance ((icRenderingIntent)996)

/* Default Color Appearance Space, based on "absolute" saturation */
#define icxSaturationAppearance ((icRenderingIntent)997)

/* These two are for completeness, they are unlikely to be useful: */
/* Special Color Appearance Space, based on "absolute" perceptual */
#define icxAbsPerceptualAppearance ((icRenderingIntent)998)

/* Default Color Appearance Space, based on "absolute" saturation */
#define icxAbsSaturationAppearance ((icRenderingIntent)999)


/* Pseudo PCS colospace returned as PCS for intent icxAppearanceJab */
#define icxSigJabData ((icColorSpaceSignature) icmMakeTag('J','a','b',' '))

/* Pseudo PCS colospace returned as PCS for intent icxAppearanceJCh */
#define icxSigJChData ((icColorSpaceSignature) icmMakeTag('J','C','h',' '))

/* Pseudo PCS colospace returned as PCS */
#define icxSigLChData ((icColorSpaceSignature) icmMakeTag('L','C','h',' '))

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


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

/* A 3x3 matrix model */
struct _icxMatrixModel {
	void *imp;		/* Opaque implementation */

	icc *picc;		/* ICC profile used to set cone space matrix, NULL for Bradford. */
	int isLab;		/* Convert lookup to Lab */

	void (*force) (struct _icxMatrixModel *p, double *targ, double *in);
	void (*lookup) (struct _icxMatrixModel *p, double *out, double *in);
	void (*del) (struct _icxMatrixModel *p);

}; typedef struct _icxMatrixModel icxMatrixModel;

/* Create a matrix model of a set of points, and return an object to lookup */
/* points from the model. Return NULL on error. */
icxMatrixModel *new_MatrixModel(
icc *picc,			/* ICC profile used to set cone space matrix, NULL for Bradford. */
int verb,			/* NZ if verbose */
int nodp,			/* Number of points */
cow *ipoints,		/* Array of input points in XYZ space */
int isLab,			/* nz if data points are Lab */
int quality,		/* Quality metric, 0..3 (-1 == 2 orders only) */
int isLinear,		/* NZ if pure linear, gamma = 1.0 */
int isGamma,		/* NZ if gamma rather than shaper */
int isShTRC,		/* NZ if shared TRCs */
int shape0gam,		/* NZ if zero'th order shaper should be gamma function */
int clipbw,			/* Prevent white > 1 and -ve black */
int clipprims,		/* Prevent primaries going -ve */
double smooth,		/* Smoothing factor (nominal 1.0) */
double scale		/* Amount to scale device values */
);

/* ------------------------------------------------------------------------------ */
/* Basic class keeps extra state for an icc, and provides the */
/* expanded set of methods. */

/* Black generation rule */
/* The rule is all in terms of device K and L* values */
typedef enum {
    icxKvalue    = 0,	/* K is specified as output K target by PCS auxiliary */
    icxKlocus    = 1,	/* K is specified as proportion of K locus by PCS auxiliary */
    icxKluma5    = 2,	/* K is specified as locus by 5 parameters as a function of L */
    icxKluma5k   = 3,	/* K is specified as K value by 5 parameters as a function of L */
    icxKl5l      = 4,	/* K is specified as locus by 2x5 parameters as a function of L and K locus aux */
    icxKl5lk      = 5	/* K is specified as K value by 2x5 parameters as a function of L and K value aux */
} icxKrule;

/* Curve parameters */
typedef struct {
	double Ksmth;		/* K smoothing filter extent */
	double Kstle;		/* K start level at white end (0.0 - 1.0)*/
	double Kstpo;		/* K start point as prop. of L locus (0.0 - 1.0) */
	double Kenpo;		/* K end point as prop. of L locus (0.0 - 1.0) */
	double Kenle;		/* K end level at Black end (0.0 - 1.0) */
	double Kshap;		/* K transition shape, 0.0-1.0 concave, 1.0-2.0 convex */
	double Kskew;		/* K transition shape skew, 1.0 = even */
} icxInkCurve;

/* Default black generation smoothing value */
#define ICXINKDEFSMTH 0.09	/* Transition window of +/- ICXINKDEFSMTH */
#define ICXINKDEFSKEW 2.0	/* Curve shape skew (matches typical device behaviour) */

/* Structure to convey inking details */
typedef struct {
	double tlimit;		/* Total ink limit, > 0.0 to < inputChan, < 0.0 == off */
	double klimit;		/* Black limit, > 0.0 to < 1.0, < 0.0 == off */
	icxKrule k_rule;	/* type of K generation rule */
	int KonlyLmin;		/* Use K only black Locus Lmin */
	icxInkCurve c;		/* K curve, or locus minimum curve */
	icxInkCurve x;		/* locus maximum curve if icxKl5l */
} icxInk;

/* Structure to convey inverse lookup clip handling details */
struct _icxClip {
	int     nearclip;				/* Flag - use near clipping not vector */
	int     LabLike;				/* Flag It's an Lab like colorspace */
	int     fdi;					/* Dimentionality of clip vector */
	struct  _icxCuspMap *cm;		/* Cusp map for computing vector (if !NULL) */
	double  ocent[MXDO];			/* Default center of clut output gamut used if cm == NULL */
}; typedef struct _icxClip icxClip;

/* Structure to convey viewing conditions */
typedef struct {
	ViewingCondition Ev;/* Enumerated Viewing Condition */
	double Wxyz[3];		/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
	double La;			/* Adapting/Surround Luminance cd/m^2 */
	double Yb;			/* Relative Luminance of Background to reference white */
	double Lv;			/* Luminance of white in the Image/Scene/Viewing field (cd/m^2) */
						/* Ignored if Ev is set to other than vc_none */
	double Yf;			/* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
	double Yg;			/* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
	double Gxyz[3];		/* The Glare white coordinates (ie the Ambient color) */
						/* will be taken from Wxyz if Gxyz <= 0.0 */
	double hkscale;		/* [1.0] HK scaling factor */
	double mtaf;		/* [0.0] Mid tone partial adapation factor from Wxyz to Wxyz2 0.0 .. 1.0 */
	double Wxyz2[3];	/* Mid tone Adapted White XYZ (Y range 0.0 .. 1.0) */
	char *desc;			/* Possible description of this VC */
} icxViewCond;

#define XICC_DEFAULT_GLARE 5	/* Default glare in % */

/* Method of black point adaptation */
typedef enum {
	gmm_BPadpt    = 0,		/* Adapt source black point to destination */
	gmm_noBPadpt  = 1,		/* Don't adapt black point to destination */ 
	gmm_bendBP    = 2,		/* Don't adapt black point, bend it to dest. at end */  
	gmm_clipBP    = 3		/* Don't adapt black point, clip it to dest. at end */  
} icx_BPmap;

/* Structure to convey gamut mapping intent */
typedef struct {
	int    usecas;			/* 0x0 Use relative Lab space */
							/* 0x1 Use Absolute Lab Space */
							/* 0x2 Use Color Appearance Space */
							/* 0x3 Use Absolute Color Appearance Space */
							/* 0x102 Use Color Appearance Space with luminence scaling */
	int    usemap;			/* NZ if Gamut mapping should be used, else clip */
	double greymf;			/* Grey axis hue matching factor, 0.0 - 1.0 */
	double glumwcpf;		/* Grey axis luminance white compression factor, 0.0 - 1.0 */
	double glumwexf;		/* Grey axis luminance white expansion factor, 0.0 - 1.0 */
	double glumbcpf;		/* Grey axis luminance black compression factor, 0.0 - 1.0 */
	double glumbexf;		/* Grey axis luminance black expansion factor, 0.0 - 1.0 */
	double glumknf;			/* Grey axis luminance knee factor, 0.0 - 1.0 */
	icx_BPmap bph;			/* Method of black point adapation */
	double gamcpf;			/* Gamut compression factor, 0.0 - 1.0 */
	double gamexf;			/* Gamut expansion factor, 0.0 - 1.0 */
	double gamcknf;			/* Gamut compression knee factor, 0.0 - 1.0 */
	double gamxknf;			/* Gamut expansion knee factor, 0.0 - 1.0 */
	double gampwf;			/* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
	double gamlpwf;			/* Gamut Lightness preserving perceptual Map whtg. factor, 0.0 - 1.0 */
	double gamswf;			/* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
	double satenh;			/* Saturation enhancement value, 0.0 - Inf */
	double hkscale;			/* [1.0] Optional HK scaling factor */
	char *as;				/* Alias string (option name) */
	char *desc;				/* Possible description of this VC */
	icRenderingIntent icci;	/* Closest ICC intent */
} icxGMappingIntent;

struct _xicc {
	/* Private: */
	icc *pp;			/* ICC profile we expand */

	struct _xcal *cal;	/* Optional device cal, NULL if none */
	int nodel_cal;		/* Flag, nz if cal was provided externally and shouldn't be deleted */

	/* Public: */
	void                 (*del)(struct _xicc *p);

	/* "use" flags */
#define ICX_CLIP_VECTOR  0x0000		/* If clipping is needed, clip in vector direction (default) */
#define ICX_CLIP_NEAREST 0x0010		/* If clipping is needed, clip to nearest */
#define ICX_MERGE_CLUT   0x0020		/* Merge the output() and out_abs() into the clut(), */
									/* for improved performance on reading, and */
									/* clipping in effective output space on inverse lookup. */
									/* Reduces accuracy noticably though. */
									/* Output output() and out_abs() become NOPs */
#define ICX_CAM_CLIP     0x0100		/* Use CAM space during invfwd clipping lookup, */
									/* irrespective of the native or effective PCS. */
									/* Ignored if MERGE_CLUT is set or vector clip is used. */
									/* May halve the inverse lookup performance! */ 
#define ICX_INT_SEPARATE 0x0400		/* Handle 4 dimensional devices with fixed inking rules */
									/* with an optimised internal separation pass, rather */
									/* than a point by point inverse locus lookup . */
									/* NOT IMPLEMENTED YET */
#define ICX_FAST_SETUP   0x0800		/* Improve initial setup speed at the cost of throughput */
#define ICX_VERBOSE      0x8000		/* Turn on verboseness during creation */

	                                /* Returm a lookup object from the icc */
	struct _icxLuBase *  (*get_luobj) (struct _xicc *p,
	                                   int flags,				/* clip, merge flags */
	                                   icmLookupFunc func,		/* Functionality */
	                                   icRenderingIntent intent,/* Intent */
	                                   icColorSpaceSignature pcsor,	/* PCS override (0 = def) */
	                                   icmLookupOrder order,	/* Search Order */
	                                   icxViewCond *vc,			/* Viewing Condition - only */
	                                                            /* used if pcsor == CIECAM. */
																/* or ICX_CAM_CLIP flag. */
	                                   icxInk *ink);			/* inking details (NULL = def) */


										/* Set a xluobj and icc table from scattered data */
										/* Return appropriate lookup object */
										/* NULL on error, check errc+err for reason */
	/* "create" flags */
#define ICX_SET_WHITE       0x00010000	/* find, set and make relative to the white point */
#define ICX_SET_WHITE_US    0x00030000	/* find, set and make relative to the white point hue, */
										/* but not scale to W L value, to avoid input clipping */
#define ICX_SET_WHITE_ABS   0x00050000	/* Set dummy D50 white point to force absolute intent.  */
#define ICX_SET_WHITE_C     0x00090000	/* find, set and make relative to the white point hue, */
										/* and clip any cLUT values over D50 to D50 */
#define ICX_SET_BLACK       0x00100000	/* find and set the black point */
#define ICX_WRITE_WBL       0x00200000	/* Matrix: write White, Black & Luminance tags */
#define ICX_CLIP_WB         0x00400000	/* Clip white and black to be < 1 and > 0 respectively */
#define ICX_CLIP_PRIMS      0x00800000	/* Clip matrix primaries to be > 0 */
#define ICX_NO_IN_SHP_LUTS  0x01000000	/* Lut/Mtx: Don't create input (Device) shaper curves. */
#define ICX_NO_IN_POS_LUTS  0x02000000	/* LuLut: Don't create input (Device) postion curves. */
#define ICX_NO_OUT_LUTS     0x04000000	/* LuLut: Don't create output (PCS) curves. */
//#define ICX_2PASSSMTH     0x08000000	/* If LuLut: Use Gaussian smoothing */
//#define ICX_EXTRA_FIT     0x10000000	/* If LuLut: Counteract scat data point errors. */
/* And  ICX_VERBOSE         			   Turn on verboseness during creation */
	struct _icxLuBase * (*set_luobj) (struct _xicc *p,
	                                  icmLookupFunc func,		/* Functionality to set */
	                                  icRenderingIntent intent,	/* Intent to set */
	                                  icmLookupOrder order,		/* Search Order */
	                                  int flags,				/* white/black point flags */
	                                  int no,					/* Total Number of points */
	                                  int nobw,					/* Number of points to look */
																/* for white & black patches in */
	                                  cow *points,				/* Array of input points */
	                                  icxMatrixModel *skm, 		/* Optional skeleton model */
	                                  double dispLuminance,		/* > 0.0 if display luminance */
	                                                                    /* value and is known */
	                                  double wpscale,			/* > 0.0 if input white pt is */
	                                                                    /* is to be scaled */
//									  double *bpo, 				/* != NULL black point override */
	                                  double smooth,			/* RSPL smoothing factor, */
	                                                                        /* -ve if raw */
	                                  double avgdev,			/* Avge Dev. of points */
	                                  double demph,				/* cLut dark emphasis factor */
	                                  icxViewCond *vc,			/* Viewing Condition - only */
	                                                            /* used if pcsor == CIECAM. */
																/* or ICX_CAM_CLIP flag. */
	                                  icxInk *ink,				/* inking details */
	                                  struct _xcal *cal,		/* Optional cal Will override any */
																/* existing, not deltd with xicc. */
	                                  int quality);				/* Quality metric, 0..3 */


								/* Return the devices viewing conditions. */
								/* Return value 0 if it is well defined */
								/* Return value 1 if it is a guess */
								/* Return value 2 if it is not possible/appropriate */
	int     (*get_viewcond)(struct _xicc *p, icxViewCond *vc);

	char             err[512];			/* Error message */
	int              errc;				/* Error code */
}; typedef struct _xicc xicc;

/* ~~~~~ */
/* Might be good to add a slow but very precise vector and closest "clip to gamut" */
/* function for use in setting white and black points. Use this in profile. */

xicc *new_xicc(icc *picc);

/* ------------------------------------------------------------------------------ */
/* Expanded lookup object support */
#define XLU_BASE_MEMBERS																\
	/* Private: */																		\
	int              trace;					/* Optional run time tracing flag */		\
	struct _xicc    *pp;					/* Pointer to XICC we're a part of */		\
	icmLuBase       *plu;					/* Pointer to icm Lu we are expanding */	\
	int              flags;					/* Flags passed to get_luobj */				\
	icmLookupFunc    func;					/* Function passed to get_luobj */			\
	icRenderingIntent intent;				/* Effective/External Intent */				\
											/* "in" and "out" are in reference to */	\
											/* the requested lookup direction. */		\
    icColorSpaceSignature ins;				/* Effective/External Clr space of input */	\
    icColorSpaceSignature outs;				/* Effective/External Clr space of output */\
	icColorSpaceSignature pcs;				/* Effective/External PCS */				\
    icColorSpaceSignature natis;			/* Native input Clr space */				\
    icColorSpaceSignature natos;			/* Native output Clr space */				\
    icColorSpaceSignature natpcs;			/* Native PCS Clr space */					\
    int	inputChan;      					/* Num of input channels */					\
    int	outputChan;     					/* Num of output channels */				\
	double ninmin[MXDI];					/* icc Native Input color space minimum */	\
	double ninmax[MXDI];					/* icc Native Input color space maximum */	\
	double noutmin[MXDO];					/* icc Native Output color space minimum */	\
	double noutmax[MXDO];					/* icc Native Output color space maximum */	\
	double inmin[MXDI];						/* icx Effective Input color space minimum */	\
	double inmax[MXDI];						/* icx Effective Input color space maximum */	\
	double outmin[MXDO];					/* icx Effective Output color space minimum */	\
	double outmax[MXDO];					/* icx Effective Output color space maximum */	\
	icxViewCond  vc;						/* Viewing Condition for CIECAM97s */		\
	icxcam      *cam;						/* CAM conversion */						\
																						\
	/* Attributes inhereted by ixcLu's */												\
	int noisluts;	/* Flag - If LuLut: Don't create input (Device) shaper curves. */			\
	int noipluts;	/* Flag - If LuLut: Don't create input (Device) position curves. */	\
	int nooluts;	/* Flag - If LuLut: Don't create output (PCS) curves. */			\
	int nearclip;	/* Flag - If clipping occurs, return the nearest solution, */		\
	int mergeclut;	/* Flag - If LuLut: Merge output() and out_abs() into clut(). */	\
	int camclip;	/* Flag - If LuLut: Use CIECAM for clut reverse lookup clipping */ \
	int intsep;		/* Flag - If LuLut: Do internal separation for 4d device */			\
	int fastsetup;	/* Flag - If LuLut: Do fast setup at cost of slower throughput */	\
																						\
	/* Public: */																		\
	void    (*del)(struct _icxLuBase *p);												\
																						\
								/* Return Internal native colorspaces */				\
	void    (*lutspaces) (struct _icxLuBase *p, icColorSpaceSignature *ins, int *inn,	\
	                                        icColorSpaceSignature *outs, int *outn,		\
	                                        icColorSpaceSignature *pcs);				\
																						\
								/* External effective colorspaces */       	    		\
	void    (*spaces) (struct _icxLuBase *p, icColorSpaceSignature *ins, int *inn,		\
	                                     icColorSpaceSignature *outs, int *outn,		\
	                                     icmLuAlgType *alg, icRenderingIntent *intt,	 \
	                                     icmLookupFunc *fnc, icColorSpaceSignature *pcs); \
																						\
	/* Get the Native input space and output space ranges */							\
	void (*get_native_ranges) (struct _icxLuBase *p,										\
		double *inmin, double *inmax,		/* Maximum range of inspace values */		\
		double *outmin, double *outmax);	/* Maximum range of outspace values */		\
																						\
																						\
	/* Get the Effective input space and output space ranges */							\
	void (*get_ranges) (struct _icxLuBase *p,											\
		double *inmin, double *inmax,		/* Maximum range of inspace values */		\
		double *outmin, double *outmax);	/* Maximum range of outspace values */		\
																						\
																						\
	/* Return the media white and black points */										\
	/* in the effective PCS colorspace. */												\
	/* (ie. these will be relative values for relative intent etc.) */					\
	void    (*efv_wh_bk_points)(struct _icxLuBase *p, double *wht, double *blk, double *kblk);	\
																						\
	/* Translate color values through profile */										\
	/* 0 = success */																	\
	/* 1 = warning: clipping occured */													\
	/* 2 = fatal: other error */														\
																						\
	/* (Note that clipping is not a reliable means of detecting out of gamut in the */	\
	/* lookup(bwd) call for clut based profiles, but is for inv_lookup() calls.) */		\
																						\
	int            (*lookup) (struct _icxLuBase *p, double *out, double *in);			\
											/* Requested conversion */					\
	int			   (*inv_lookup) (struct _icxLuBase *p, double *out, double *in);		\
											/* Inverse conversion */					\
																						\
	/* Given an xicc lookup object, returm a gamut object. */							\
	/* Note that the Effective PCS must be Lab or Jab */								\
	/* A icxLuLut type must be icmFwd or icmBwd, */										\
	/* and for icmFwd, the ink limit (if supplied) */									\
	/* will be applied. */																\
	/* Return NULL on error, check xicc errc+err for reason */							\
	gamut * (*get_gamut) (struct _icxLuBase *plu,	/* xicc lookup object */			\
	                      double detail);			/* gamut detail level, 0.0 = def */	\
																						\
	/* Given an xicc lookup object, return an icxCuspMap object. */						\
	/* Note that the PCS must be Lab or Jab. */											\
	/* An icxLuLut type must be icmFwd, and the ink limit (if supplied) */				\
	/* will be applied. */																\
	/* Return NULL on error, check errc+err for reason */								\
	struct _icxCuspMap *(*get_cuspmap)(struct _icxLuBase *p, int res);					\
																						\
	/* The following two functions expose the relative colorimetric native ICC PCS */	\
	/* <--> absolute/CAM space transform, so that CAM based gamut compression */		\
	/* can be applied in creating the ICC Lut tabls in profout.c. */					\
																						\
	/* Given a native ICC relative XYZ or Lab PCS value, convert in the fwd */			\
	/* direction into the nominated Effective output PCS (ie. Absolute, Jab etc.) */	\
	void (*fwd_relpcs_outpcs) (struct _icxLuBase *p, icColorSpaceSignature is,			\
	                                                   double *out, double *in);		\
																						\
	/* Given a nominated Effective output PCS (ie. Absolute, Jab etc.), convert it */	\
	/* in the bwd direction into a native ICC relative XYZ or Lab PCS value */			\
	void (*bwd_outpcs_relpcs) (struct _icxLuBase *p, icColorSpaceSignature os,			\
	                                                   double *out, double *in);		\
																						\


/* Base xlookup object */
struct _icxLuBase {
	XLU_BASE_MEMBERS
}; typedef struct _icxLuBase icxLuBase;

/* Monochrome  Fwd & Bwd type object */
struct _icxLuMono {
	XLU_BASE_MEMBERS

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

	/* Components of Device to PCS lookup */
	int (*fwd_curve) (struct _icxLuMono *p, double *out, double *in);
	int (*fwd_map)   (struct _icxLuMono *p, double *out, double *in);
	int (*fwd_abs)   (struct _icxLuMono *p, double *out, double *in);

	/* Components of PCS to Device lookup */
	int (*bwd_abs)   (struct _icxLuMono *p, double *out, double *in);
	int (*bwd_map)   (struct _icxLuMono *p, double *out, double *in);
	int (*bwd_curve) (struct _icxLuMono *p, double *out, double *in);

}; typedef struct _icxLuMono icxLuMono;

/* 3D Matrix Fwd & Bwd type object */
struct _icxLuMatrix {
	XLU_BASE_MEMBERS

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

	/* Components of Device to PCS lookup */
	int (*fwd_curve)  (struct _icxLuMatrix *p, double *out, double *in);
	int (*fwd_matrix) (struct _icxLuMatrix *p, double *out, double *in);
	int (*fwd_abs)    (struct _icxLuMatrix *p, double *out, double *in);

	/* Components of PCS to Device lookup */
	int (*bwd_abs)    (struct _icxLuMatrix *p, double *out, double *in);
	int (*bwd_matrix) (struct _icxLuMatrix *p, double *out, double *in);
	int (*bwd_curve)  (struct _icxLuMatrix *p, double *out, double *in);

}; typedef struct _icxLuMatrix icxLuMatrix;

/* Multi-D. Lut type object */
struct _icxLuLut {
	XLU_BASE_MEMBERS

	/* private: */
	icmLut *lut;							/* ICC Lut that is being used */
	rspl	        *inputTable[MXDI];		/* The input lookups */
	rspl	        *clutTable;				/* The multi dimention lookup */
	rspl	        *cclutTable;			/* Alternate multi dimention lookup in CAM space */
	rspl	        *outputTable[MXDO];		/* The output lookups */

	/* Inverted RSPLs used to speed ink limit calculation */
	/* input' -> input */
	rspl *revinputTable[MXDI];

	/* In/Out lookup flags used for rspl init. callback */
	int iol_out;	/* Non-zero if output lookup */
	int iol_ch;		/* Channel */

	/* In/Out inversion support */
	double inputClipc[MXDI];	/* The input lookups clip center */
	double outputClipc[MXDO];	/* The output lookups clip center */

	/* clut inversion support */
	double      icent[MXDI];		/* center of input gamut */
	double      licent[MXDI];		/* last icent value used */

	icxClip clip;					/* Clip setup information */

	int kch;						/* Black ink channel if discovered */
									/* -1 if not known or applicable */
									/* (Only set by icxLu_comp_bk_point()) */
	icxInk      ink;				/* inking details */
	double Lmin, Lmax;				/* L min/max for inking rule */

	/* Auxiliary parameter flags, non-zero for inputs that will be */
	/* used as auxiliary parameters the rspl input */
	/* dimensionality exceeds the output dimension (i.e. CMYK->Lab) */
	int auxm[MXDI];	

	/* Auxiliar linearization function - NULL if none */
 	/* Only the used auxiliary chanels need be calculated. */
	/* ~~ not implimented yet ~~~ */
//	void (*auxlinf)(void *auxlinf_ctx, double inout[MXDI]);

	/* Opaque context for auxlin */
//	void *auxlinf_ctx;

	/* Temporary icm fwd abs XYZ LuLut used for setting up icx clut */
	icmLuBase *absxyzlu;

	/* Optional function to compute the input chanel */
 	/* sum from the raw rspl input values. NULL if not used. */
	/* Use this to take account of any transformation beyond */
	/* the input space, or 6 color masquerading as 4 etc. */
	double (*limitf)(void *limitf_ctx, float in[MXDI]);		/* ~~ not implimented yet */

	/* Opaque context for limitf */
	void *limitf_ctx;

	/* Input space sum limit. Points with a limitf() over */
	/* this number will not be considered in gamut. Valid if gt 0 */
	double slimit;

	/* public: */

	/* Note that black inking rules are always defined and provided */
	/* in dev[] and pcs[] space, even for component functions */
	/* (ie. the implementation of the inking rule deals with */
	/*  the dev<->dev' and pcs<->pcs' conversions) */
	
	/* Requested direction component lookup */
	int (*in_abs)  (struct _icxLuLut *p, double *out, double *in);
	int (*matrix)  (struct _icxLuLut *p, double *out, double *in);
	int (*input)   (struct _icxLuLut *p, double *out, double *in);
	int (*clut)    (struct _icxLuLut *p, double *out, double *in);
	int (*clut_aux)(struct _icxLuLut *p, double *out, double *olimit,
	                                     double *auxv, double *in);
	int (*output)  (struct _icxLuLut *p, double *out, double *in);
	int (*out_abs) (struct _icxLuLut *p, double *out, double *in);

	/* Inverse direction component lookup (in reverse order) */
	int (*inv_out_abs) (struct _icxLuLut *p, double *out, double *in);
	int (*inv_output)  (struct _icxLuLut *p, double *out, double *in);
	int (*inv_clut)    (struct _icxLuLut *p, double *out, double *in);
	int (*inv_clut_aux)(struct _icxLuLut *p, double *out, double *auxv,
                 double *auxr, double *auxt, double *clipd, double *in);
	int (*inv_input)   (struct _icxLuLut *p, double *out, double *in);
	int (*inv_matrix)  (struct _icxLuLut *p, double *out, double *in);
	int (*inv_in_abs)  (struct _icxLuLut *p, double *out, double *in);

	/* Get locus information for a clut (see xlut.c for details) */
	int (*clut_locus)  (struct _icxLuLut *p, double *locus, double *out, double *in);

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

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

}; typedef struct _icxLuLut icxLuLut;

/* ------------------------------------------------------------------------------ */
/* Utility declarations and functions */

/* Utility that mirrors get_luobj intent handling: */
/* return nz if the intent implies Jab space */
int xiccIsIntentJab(icRenderingIntent intent);

/* Profile Creation Suplimental Information structure */
struct _profxinf {
    icmSig manufacturer;	/* Device manufacturer ICC Sig, 0 for default */
	char *deviceMfgDesc;	/* Manufacturer text description, NULL for none */

    icmSig model;			/* Device model ICC Sig, 0 for default */
	char *modelDesc;		/* Model text description, NULL for none */

    icmSig creator;			/* Profile creator ICC Sig, 0 for default */

	char *profDesc;			/* Text profile description, NULL for default */

	char *copyright;		/* Copyrigh text, NULL for default */

	/* Attribute flags */
	int transparency;		/* NZ for Trasparency, else Reflective */
	int matte;				/* NZ for Matte, else Glossy */
	int negative;			/* NZ for Negative, else Positive */
	int blackandwhite;		/* NZ for BlackAndWhite, else Color */

	/* Default intent */
	icRenderingIntent  default_ri;	/* Default rendering intent */

	/* Other stuff ICC ?? */

}; typedef struct _profxinf profxinf;

/* Set an icc's Lut tables, and take care of auxiliary continuity problems. */
/* Only useful if there are auxiliary device output chanels to be set. */
int icxLut_set_tables_auxfix(
icmLut *p,						/* Pointer to icmLut 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 *aux, double *auxr, double *pcs, double *in),
						/* inspace' -> outspace' transfer function, also */
						/* return the internal target PCS and the  (packed) auxiliary locus */
						/* range as [min0, max0, min1, max1...], and the actual auxiliary */
						/* target used. */
void (*clutpcsfunc)(void *cbntx, double *out, double *aux, double *pcs),
						/* Internal PCS + actual aux_target -> outspace' transfer function */
void (*clutipcsfunc)(void *cbntx, double *pcs, double *olimit, double *auxv, double *in),
						/* outspace' -> Internal PCS + auxv check 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) */
);

		
/* Return an enumerated viewing condition */
/* Return enumeration if OK, -999 if there is no such enumeration. */
/* xicc may be NULL if just the description is wanted, */
/* or an explicit white point is provided. */
int xicc_enum_viewcond(
xicc *p,			/* Expanded profile to get white point (May be NULL if desc NZ) */
icxViewCond *vc,	/* Viewing parameters to return, May be NULL if desc is nz */
int no,				/* Enumeration to return, -1 for default, -2 for none */
char *as,			/* String alias to number, NULL if none */
int desc,			/* NZ - Just return a description of this enumeration in vc */
double *wp			/* Provide XYZ white point if xicc is NULL */
);

/* Debug: dump a Viewing Condition to standard out */
void xicc_dump_viewcond(icxViewCond *vc);

/* Debug: dump an Inking setup to standard out */
void xicc_dump_inking(icxInk *ik);

/* Return enumerated gamut mapping intents */
/* Return 0 if OK, 1 if there is no such enumeration. */
/* Note the following fixed numbers meanings: */
#define icxNoGMIntent -1
#define icxDefaultGMIntent -2
#define icxAbsoluteGMIntent -3
#define icxRelativeGMIntent -4
#define icxPerceptualGMIntent -5
#define icxSaturationGMIntent -6
#define icxIllegalGMIntent -999
int xicc_enum_gmapintent(icxGMappingIntent *gmi, int no, char *as);
void xicc_dump_gmi(icxGMappingIntent *gmi);

/* - - - - - - - - - - */
/* Utility functions: */

/* Given an open icc profile, */
/* guess which channel is the black. */
/* Return -1 if there is no black channel or it can't be guessed */
int icxGuessBlackChan(icc *p);

/* Given an icc profile, try and create an xcal */
/* Return NULL on error or no cal */
struct _xcal *xiccReadCalTag(icc *p);

/* A callback that uses an xcal, that can be used with icc get_tac */
void xiccCalCallback(void *cntx, double *out, double *in);

/* Given an xicc icc profile, estmate the total ink limit and black ink limit. */
void icxGetLimits(xicc *p, double *tlimit, double *klimit);

/* Using the above function, set default total and black ink values */
void icxDefaultLimits(xicc *p, double *tlout, double tlin, double *klout, double klin);

/* Given a calibrated total ink limit and an xcal, return the */
/* equivalent underlying (pre-calibration) total ink limit. */
/* This is the maximum equivalent, that makes sure that */
/* the calibrated limit is met or exceeded. */
double icxMaxUnderlyingLimit(struct _xcal *cal, double ilimit);

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

/* Utility function - compute the clip vector direction. */
/* return NULL if vector clip isn't used. */
double *icxClipVector(
icxClip *p,			/* Clipping setup information */
double *in,			/* Target point */
double *cdirv,		/* Returned clip vector */
int safe			/* Flag - return safe vector */
);

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

/* CIE XYZ to perceptual Lab with partial derivatives. */
void icxdXYZ2Lab(icmXYZNumber *w, double *out, double dout[3][3], double *in);

/* Return the normal Delta E squared, given two Lab values, */
/* including partial derivatives. */
double icxdLabDEsq(double dout[2][3], double *Lab0, double *Lab1);

/* Return the CIE94 Delta E color difference measure, squared */
/* including partial derivatives. */
double icxdCIE94sq(double dout[2][3], double Lab0[3], double Lab1[3]);

/* Return the normal Delta E given two Lab values, */
/* including partial derivatives. */
double icxdLabDE(double dout[2][3], double *Lab0, double *Lab1);

/* Return the CIE94 Delta E color difference measure */
/* including partial derivatives. */
double icxdCIE94(double dout[2][3], double Lab0[3], double Lab1[3]);

/* - - - - - - - - - - */
/* Power like function, based on Graphics Gems adjustment curve. */
/* Avoids "toe" problem of pure power. */
/* Adjusted so that "power" 2 and 0.5 agree with real power at 0.5 */
double icx_powlike(double vv, double pp);

/* Compute the necessary aproximate power, to transform */
/* the given value from src to dst. They are assumed to be */
/* in the range 0.0 .. 1.0 */
double icx_powlike_needed(double src, double dst);

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

/* Transfer function */
double icxTransFunc(
double *v,			/* Pointer to first parameter */
int    luord,		/* Number of parameters */
double vv			/* Source of value */
);

/* Inverse Transfer function */
double icxInvTransFunc(
double *v,			/* Pointer to first parameter */
int    luord,		/* Number of parameters */
double vv			/* Source of value */
);

/* Transfer function with scaling */
double icxSTransFunc(
double *v,			/* Pointer to first parameter */
int    luord,		/* Number of parameters */
double vv,			/* Source of value */
double min,			/* Scale values */
double max
);

/* Inverse Transfer function with scaling */
double icxInvSTransFunc(
double *v,			/* Pointer to first parameter */
int    luord,		/* Number of parameters */
double vv,			/* Source of value */
double min,			/* Scale values */
double max
);

/* Transfer function with partial derivative */
/* with respect to the parameters. */
double icxdpTransFunc(
double *v,			/* Pointer to first parameter */
double *dv,			/* Return derivative wrt each parameter [luord] */
int    luord,		/* Number of parameters */
double vv			/* Source of value */
);

/* Transfer function with scaling and */
/* partial derivative with respect to the parameters. */
double icxdpSTransFunc(
double *v,			/* Pointer to first parameter */
double *dv,			/* Return derivative wrt each parameter [luord] */
int    luord,		/* Number of parameters */
double vv,			/* Source of value */
double min,			/* Scale values */
double max
);

/* Transfer function with partial derivative */
/* with respect to the input value. */
double icxdiTransFunc(
double *v,			/* Pointer to first parameter */
double *pdv,		/* Return derivative wrt source value [1] */
int    luord,		/* Number of parameters */
double vv			/* Source of value */
);

/* Transfer function with scaling and */
/* partial derivative with respect to the input value. */
double icxdiSTransFunc(
double *v,			/* Pointer to first parameter */
double *pdv,		/* Return derivative wrt source value [1] */
int    luord,		/* Number of parameters */
double vv,			/* Source of value */
double min,			/* Scale values */
double max
);

/* Transfer function with partial derivative */
/* with respect to the parameters and the input value. */
double icxdpdiTransFunc(
double *v,			/* Pointer to first parameter */
double *dv,			/* Return derivative wrt each parameter [luord] */
double *pdin,		/* Return derivative wrt source value [1] */
int    luord,		/* Number of parameters */
double vv			/* Source of value */
);

/* Transfer function with scaling and */
/* partial derivative with respect to the */
/* parameters and the input value. */
double icxdpdiSTransFunc(
double *v,			/* Pointer to first parameter */
double *dv,			/* Return derivative wrt each parameter [luord] */
double *pdin,		/* Return derivative wrt source value [1] */
int    luord,		/* Number of parameters */
double vv,			/* Source of value */
double min,			/* Scale values */
double max
);

/* Should add/move the spectro/moncurve stuff in here, */
/* since it has offset and scaling. */

/* - - - - - - - - - - */
/* Multi-plane interpolation - uses base + di slope values.  */
/* Parameters are assumed to be fdi groups of di + 1 parameters. */
void icxPlaneInterp(
double *v,			/* Pointer to first parameter [fdi * (di + 1)] */
int    fdi,			/* Number of output channels */
int    di,			/* Number of input channels */
double *out,		/* Resulting fdi values */
double *in			/* Input di values */
);

/* Matrix cube interpolation. with partial derivative */
/* with respect to the input and parameters. */
void icxdpdiPlaneInterp(
double *v,			/* Pointer to first parameter value [fdi * (di + 1)] */
double *dv,			/* Return [1 + di] deriv. wrt each parameter v */
double *din,		/* Return [fdi * di] deriv. wrt each input value */
int    fdi,			/* Number of output channels */
int    di,			/* Number of input channels */
double *out,		/* Resulting fdi values */
double *in			/* Input di values */
);

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

/* Matrix cube interpolation - interpolate between 2^di output corner values. */
/* Parameters are assumed to be fdi groups of 2^di parameters. */
void icxCubeInterp(
double *v,			/* Pointer to first parameter */
int    fdi,			/* Number of output channels */
int    di,			/* Number of input channels */
double *out,		/* Resulting fdi values */
double *in			/* Input di values */
);

/* Matrix cube interpolation. with partial derivative */
/* with respect to the input and parameters. */
void icxdpdiCubeInterp(
double *v,			/* Pointer to first parameter value */
double *dv,			/* Return [fdi * 2^di] deriv wrt each parameter v */
double *din,		/* Return [fdi * di] deriv wrt each input value */
int    fdi,			/* Number of output channels */
int    di,			/* Number of input channels */
double *out,		/* Resulting fdi values */
double *in			/* Input di values */
);

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

/* 3x3 matrix in 1D array multiplication */
void icxMulBy3x3Parm(
	double out[3],			/* Return input multiplied by matrix */
	double mat[9],			/* Matrix organised in [slow][fast] order */
	double in[3]			/* Input values */
);

/* 3x3 matrix in 1D array multiplication, with partial derivatives */
/* with respect to just the input. */
void icxdpdiiMulBy3x3Parm(
	double out[3],			/* Return input multiplied by matrix */
	double din[3][3],		/* Return deriv for each [output] with respect to [input] */
	double mat[9],			/* Matrix organised in [slow][fast] order */
	double in[3]			/* Input values */
);

/* 3x3 matrix in 1D array multiplication, with partial derivatives */
/* with respect to the input and parameters. */
void icxdpdiMulBy3x3Parm(
	double out[3],			/* Return input multiplied by matrix */
	double dv[3][9],		/* Return deriv for each [output] with respect to [param] */
	double din[3][3],		/* Return deriv for each [output] with respect to [input] */
	double mat[9],			/* Matrix organised in [slow][fast] order */
	double in[3]			/* Input values */
);

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

/* Cusp map - used for vector clipping in Lab like spaces */
struct _icxCuspMap {
	double Lmax[3];	/* Maximum L* value found */
	double Lmin[3];	/* Minimum L* value found */
	int res;		/* Resolution of hue map */
	double *L;		/* L* value of cusp at hue angle */
	double *C;		/* C* value of cusp at hue angle */

	/* Expand cusp map with given point */
	void (*expand)(struct _icxCuspMap *p, double lab[3]);  

	/* Return the corresponding cusp location, given the source point */
	void (*getCusp)(struct _icxCuspMap *p,double cuspLCh[3], double srcLab[3]);  

	/* We're done with CuspMap */
	void (*del)(struct _icxCuspMap *p);  

}; typedef struct _icxCuspMap icxCuspMap;


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

#include "xcal.h"

#endif /* XICC_H */



































