694 lines
23 KiB
C
694 lines
23 KiB
C
|
|
/*
|
|
* International Color Consortium Format Library (icclib)
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 2022/12/15
|
|
* Version: 3.0.0
|
|
*
|
|
* Copyright 1997 - 2023 Graeme W. Gill
|
|
*
|
|
* This material is licensed with an "MIT" free use license:-
|
|
* see the License4.txt file in this directory for licensing details.
|
|
*/
|
|
|
|
/* icmPe transform declarations */
|
|
/* This is #included in icc.h */
|
|
|
|
/* Sig (etype) of processing elements */
|
|
/* (Update icmPeSig2str() too) */
|
|
typedef enum {
|
|
icmSigPeNone = icmMakeTag(0,0,0,0), /* Not an icmPe */
|
|
icmSigPeCurveSet = icmMakeTag('P','e','c','s'), /* A set of N x 1d Curves */
|
|
icmSigPeCurve = icmMakeTag('P','e','c','u'), /* A linear/gamma/table curve */
|
|
icmSigPeMatrix = icmMakeTag('P','e','m','a'), /* An N x M + F matrix */
|
|
icmSigPeClut = icmMakeTag('P','e','c','l'), /* An N x M cLUT */
|
|
|
|
icmSigPeLut816 = icmMakeTag('P','e','l','8'),
|
|
|
|
icmSigPeContainer = icmMakeTag('P','e','c','r'), /* A sequence of other icmPe's */
|
|
icmSigPeInverter = icmMakeTag('P','e','i','v'), /* An inverter */
|
|
icmSigPeMono = icmMakeTag('P','e','m','o'), /* Mono conversion part of ShaperMono */
|
|
|
|
icmSigPeShaperMatrix = icmMakeTag('P','e','s','m'), /* A shaper/matrix sequence */
|
|
icmSigPeShaperMono = icmMakeTag('P','e','s','o'), /* A shaper/mono sequence */
|
|
|
|
/* Format conversions */
|
|
icmSigPeXYZ2Lab = icmMakeTag('P','e','x','l'),
|
|
icmSigPeAbs2Rel = icmMakeTag('P','e','a','r'),
|
|
icmSigPeXYZ2XYZ8 = icmMakeTag('P','e','x','1'),
|
|
icmSigPeXYZ2XYZ16 = icmMakeTag('P','e','x','2'),
|
|
icmSigPeLab2Lab8 = icmMakeTag('P','e','l','1'),
|
|
icmSigPeLab2LabV2 = icmMakeTag('P','e','l','2'),
|
|
icmSigPeGeneric2Norm = icmMakeTag('P','e','G','e'), /* Generic normalization */
|
|
icmSigPeGridAlign = icmMakeTag('P','e','G','a'), /* Grid align */
|
|
icmSigPeNOP = icmMakeTag('P','e','N','O'), /* A NOP */
|
|
|
|
icmPeMaxEnum = icMaxTagVal
|
|
} icmPeSignature;
|
|
|
|
/* See icmPeSig2str() for text */
|
|
|
|
/* Lookup return values */
|
|
typedef enum {
|
|
icmPe_lurv_OK = 0x00, /* Lookup is OK */
|
|
icmPe_lurv_clip = 0x01, /* Clipping warning */
|
|
icmPe_lurv_bwclp = 0x02, /* lookup_bwd on clipping PeCurveFmlaSeg */
|
|
icmPe_lurv_num = 0x04, /* Numerical limit reached warning */
|
|
icmPe_lurv_imp = 0x08, /* Not implemented error */
|
|
icmPe_lurv_cfg = 0x10, /* Configuration error */
|
|
|
|
icmPe_lurv_err = 0x18 /* Error mask */
|
|
} icmPe_lurv;
|
|
|
|
char *icmPe_lurv2str(icmPe_lurv err);
|
|
|
|
/* PE operation classification */
|
|
typedef enum { /* Dominant operation type */
|
|
icmPeOp_NOP = 0x0, /* No operation */
|
|
icmPeOp_perch = 0x1, /* A per-channel operation */
|
|
icmPeOp_matrix = 0x2, /* A matrix interchannel operation (maybe abs<->rel or Mono) */
|
|
icmPeOp_cLUT = 0x3, /* A cLUT interchannel operation */
|
|
icmPeOp_fmt = 0x4, /* PCS format transform (i.e. XYZ <->Lab) */
|
|
icmPeOp_complex = 0x5 /* A complex set of interchannel operations */
|
|
} icmPeOp;
|
|
|
|
char *icmPe_Op2str(icmPeOp op);
|
|
|
|
/* icmPe attributes. */
|
|
typedef struct {
|
|
char comp; /* nz if Compound element contains other Pe's (for trace) */
|
|
char inv; /* nz if element was created with inverted function (for trace) */
|
|
char norm; /* nz if normalization type operation */
|
|
icmPeOp op; /* Operation type */
|
|
char fwd; /* nz if fwd transform is implemented */
|
|
char bwd; /* nz if bwd transform is implemented */
|
|
} icmPeAttr;
|
|
|
|
char *icmPe_Attr2Str(icmPeAttr *attr);
|
|
|
|
#define ICM_PE_SETATTR(ATTR, COMP, INV, NORM, OP, FWD, BWD) \
|
|
ATTR.comp = COMP; \
|
|
ATTR.inv = INV; \
|
|
ATTR.norm = NORM; \
|
|
ATTR.op = OP; \
|
|
ATTR.fwd = FWD; \
|
|
ATTR.bwd = BWD; \
|
|
|
|
/* Processing Element base class definition */
|
|
/* This inherets from icmBase */
|
|
#define ICM_PE_MEMBERS(ECLASS) \
|
|
ICM_BASE_MEMBERS(ECLASS) \
|
|
unsigned int inputChan; /* No. of input channels */ \
|
|
unsigned int outputChan; /* No. of output channels */ \
|
|
icmPeAttr attr; /* attributes of transforms */ \
|
|
int isPeSeq; /* nz if is superclass of icmPeSeq */ \
|
|
\
|
|
int trace; /* Trace level, 1 = top, > 1 = recursion level */ \
|
|
\
|
|
/* Init anything that depends on the processing (i.e. attr, inverse comp etc.) */ \
|
|
/* Return nz on error */ \
|
|
int (*init) (ECLASS *p); \
|
|
\
|
|
/* Translate a value through the Pe, return any warning flags */ \
|
|
/* (Where are warning flags defined ? Clip ?, F.P. error ?) */ \
|
|
icmPe_lurv (*lookup_fwd) (ECLASS *p, double *out, double *in); /* Forwards */ \
|
|
icmPe_lurv (*lookup_bwd) (ECLASS *p, double *out, double *in); /* Backwards */ \
|
|
|
|
/* Processing Element Initialisation */
|
|
#define ICM_PE_INIT(ECLASS, ESIG) \
|
|
p->etype = ESIG; \
|
|
p->init = (int (*)(ECLASS *))icmPeDummy_init; \
|
|
|
|
/* Processing Element allocation and initialisation */
|
|
/* Returns NULL on error */
|
|
#define ICM_PE_ALLOCINIT(ECLASS, ESIG, TSIG) \
|
|
ICM_BASE_ALLOCINIT(ECLASS, TSIG) \
|
|
ICM_PE_INIT(ECLASS, ESIG) \
|
|
|
|
/* Non-serialisable init */
|
|
#define ICM_PE_NS_ALLOCINIT(ECLASS, ESIG) \
|
|
ICM_BASE_NS_ALLOCINIT(ECLASS) \
|
|
ICM_PE_INIT(ECLASS, ESIG) \
|
|
|
|
/* A Processing Element */
|
|
struct _icmPe {
|
|
ICM_PE_MEMBERS(struct _icmPe)
|
|
}; typedef struct _icmPe icmPe;
|
|
|
|
/* Structure for managing Pe's */
|
|
struct _icmPePrivStr {
|
|
int dup; /* Duplicate Pe flag */
|
|
icmPositionNumber pn; /* Offset and size of sub-tag */
|
|
}; typedef struct _icmPePrivStr icmPePrivStr;
|
|
|
|
/* ----------------------- */
|
|
/* A sequence of icmPe's */
|
|
|
|
/* Processing Element Sequence base class definition */
|
|
/* This inherets from icmPe */
|
|
#define ICM_PE_SEQ_MEMBERS(ECLASS) \
|
|
ICM_PE_MEMBERS(ECLASS) \
|
|
\
|
|
/* Private: */ \
|
|
unsigned int _count; /* Count currently allocated */ \
|
|
unsigned int nncount; /* Count of non-NULL pe's */ \
|
|
\
|
|
/* Public: */ \
|
|
unsigned int count; /* Count of processing elements */ \
|
|
icmPe **pe; /* Array of [count] processing elements */ \
|
|
|
|
|
|
/* Processing Element Sequenece allocation and initialisation. */
|
|
/* (It's assumed that the parent class provides all methods) */
|
|
/* Returns NULL on error */
|
|
#define ICM_PE_SEQ_ALLOCINIT(ECLASS, ESIG, TSIG) \
|
|
ICM_PE_ALLOCINIT(ECLASS, ESIG, TSIG) \
|
|
p->isPeSeq = 1; \
|
|
p->init = (int (*)(ECLASS *))icmPeSeq_init; \
|
|
p->lookup_fwd = (icmPe_lurv (*)(ECLASS *, double *, double *))icmPeSeq_lookup_fwd; \
|
|
p->lookup_bwd = (icmPe_lurv (*)(ECLASS *, double *, double *))icmPeSeq_lookup_bwd; \
|
|
|
|
/* Non-serialisable init */
|
|
#define ICM_PE_SEQ_NS_ALLOCINIT(ECLASS, ESIG) \
|
|
ICM_PE_NS_ALLOCINIT(ECLASS, ESIG) \
|
|
p->isPeSeq = 1; \
|
|
p->init = (int (*)(ECLASS *))icmPeSeq_init; \
|
|
p->lookup_fwd = (icmPe_lurv (*)(ECLASS *, double *, double *))icmPeSeq_lookup_fwd; \
|
|
p->lookup_bwd = (icmPe_lurv (*)(ECLASS *, double *, double *))icmPeSeq_lookup_bwd; \
|
|
|
|
/* A Processing Element Sequence */
|
|
struct _icmPeSeq {
|
|
ICM_PE_SEQ_MEMBERS(struct _icmPeSeq)
|
|
}; typedef struct _icmPeSeq icmPeSeq;
|
|
|
|
/* ================================================================================== */
|
|
|
|
/* ----------------------- */
|
|
/* A set of N x 1d Curves */
|
|
|
|
/* etype icmSigPeCurveSet */
|
|
/* ttype icmSig816Curves */
|
|
|
|
struct _icmPeCurveSet {
|
|
ICM_PE_MEMBERS(struct _icmPeCurveSet)
|
|
|
|
/* Private: */
|
|
icmPePrivStr pei[MAX_CHAN]; /* Management info. */
|
|
unsigned int bpv; /* Bytes per value (Lut1 only) */
|
|
|
|
/* Public: */
|
|
icmPe *pe[MAX_CHAN]; /* 1D curves */
|
|
|
|
}; typedef struct _icmPeCurveSet icmPeCurveSet;
|
|
|
|
|
|
/* A fake internal Sig 'l1vs' for icmLut8 and icmLut16 curves */
|
|
#define icmSig816Curves ((icTagTypeSignature)icmMakeTag('l','1','v','s'))
|
|
|
|
/* ----------------------- */
|
|
/* A linear/gamma/table (sample) curve */
|
|
|
|
/* etype icmSigPeCurve */
|
|
/* ttype icSigCurveType */
|
|
/* ttype icmSig816Curve */
|
|
|
|
/* icmPeCurve reverse lookup information */
|
|
typedef struct {
|
|
int inited; /* Flag */
|
|
double rmin, rmax; /* Range of reverse grid */
|
|
double qscale; /* Quantising scale factor */
|
|
int rsize; /* Number of reverse lists */
|
|
unsigned 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 int count; /* Copy of forward table size */
|
|
double *data; /* Copy of forward table data */
|
|
} icmRevTable;
|
|
|
|
typedef enum {
|
|
icmCurveUndef = -1, /* Undefined curve */
|
|
icmCurveLin = 0, /* Linear transfer curve */
|
|
icmCurveGamma = 1, /* Gamma power transfer curve */
|
|
icmCurveSpec = 2 /* Specified curve */
|
|
} icmCurveType;
|
|
|
|
struct _icmPeCurve {
|
|
ICM_PE_MEMBERS(struct _icmPeCurve)
|
|
|
|
/* Private: */
|
|
int inited; /* Flag */
|
|
unsigned int _count; /* Size currently allocated */
|
|
unsigned int bpv; /* Bytes per value (Lut1 only) */
|
|
icmRevTable rt; /* Reverse table information */
|
|
|
|
/* Public: */
|
|
icmCurveType ctype; /* Type of curve */
|
|
unsigned int count; /* Allocated and used size of the array */
|
|
double *data; /* Curve data scaled to range 0.0 - 1.0 */
|
|
/* or data[0] = gamma value */
|
|
/* or count == 0 for linear. */
|
|
|
|
}; typedef struct _icmPeCurve icmPeCurve;
|
|
|
|
typedef icmPeCurve icmCurve;
|
|
|
|
/* A fake internal Sig 'l1cv' for a icmLut8 and icmLut16 curve */
|
|
#define icmSig816Curve ((icTagTypeSignature)icmMakeTag('l','1','c','v'))
|
|
|
|
/* ----------------------- */
|
|
/* An N x M + F matrix */
|
|
|
|
/* etype icmSigPeMatrix */
|
|
/* ttype icmSig816Matrix */
|
|
|
|
struct _icmPeMatrix {
|
|
ICM_PE_MEMBERS(struct _icmPeMatrix)
|
|
|
|
/* Private: */
|
|
int inited; /* flag - if initiliase (imx, flags) */
|
|
int ivalid; /* flag - if imx is valid */
|
|
int mx_unity; /* flag - if mx[] is unity */
|
|
int ct_zero; /* flag - if ct[] is zero */
|
|
|
|
double imx[MAX_CHAN][MAX_CHAN]; /* [inn][outn] Inverse matrix values */
|
|
|
|
/* Public: */
|
|
|
|
double mx[MAX_CHAN][MAX_CHAN]; /* [outn][inn] Matrix values */
|
|
double ct[MAX_CHAN]; /* [outn] Constant values added after mx[][] multiply */
|
|
|
|
}; typedef struct _icmPeMatrix icmPeMatrix;
|
|
|
|
|
|
/* A fake internal Sig 'l1mx' for icmLut8 and icmLut16 Matrix */
|
|
#define icmSig816Matrix ((icTagTypeSignature)icmMakeTag('l','1','m','x'))
|
|
|
|
/* ----------------------- */
|
|
/* An N x M cLUT */
|
|
|
|
/* etype icmSigPeClut */
|
|
/* ttype icmSig816CLUT */
|
|
|
|
struct _icmLu4Base;
|
|
struct _icmLu4Space;
|
|
|
|
struct _icmPeClut {
|
|
ICM_PE_MEMBERS(struct _icmPeClut)
|
|
|
|
/* Private: */
|
|
unsigned int _clutsize; /* Current clut size in doubles */
|
|
int inited; /* flag - if initialised (dinc[]) */
|
|
unsigned int dinc[MAX_CHAN]; /* [inn] grid resolution values */
|
|
int dcube[1 << MAX_CHAN]; /* Hyper cube offsets (in doubles) */
|
|
int use_sx; /* flag - use simplex interpolation */
|
|
|
|
/* Public: */
|
|
unsigned int bpv; /* Bytes per value */
|
|
unsigned int clutPoints[MAX_CHAN]; /* [inn] grid resolution values */
|
|
/* (Must be all the same for icmLut) */
|
|
double *clutTable; /* clut values organized as: */
|
|
/* [inputChan 0: 0..clutPoints[0]-1].. */
|
|
/* [inputChan inn-1: 0..clutPoints[inn-1]-1] */
|
|
/* [outputChan: 0..outn-1] */
|
|
|
|
/* return the minimum and maximum values of the given channel in the clut */
|
|
void (*min_max) (struct _icmPeClut *p, double *minv, double *maxv, int chan);
|
|
|
|
/* Determine appropriate clut lookup algorithm */
|
|
void (*choose_alg) (struct _icmPeClut *p, struct _icmLu4Space *lu);
|
|
|
|
/* Return total ink limit and channel maximums. */
|
|
double (*get_tac) (
|
|
struct _icmPeClut *p,
|
|
double *chmax, /* device return channel sums. May be NULL */
|
|
icmPe *tail, /* lu tail transform from clut to device output */
|
|
void (*calfunc)(void *cntx, double *out, double *in), /* Optional calibration func. */
|
|
void *cntx
|
|
);
|
|
|
|
/* ~8 missing API's:
|
|
|
|
tune_value() cLut single value fine tune)
|
|
|
|
*/
|
|
|
|
}; typedef struct _icmPeClut icmPeClut;
|
|
|
|
|
|
/* A fake internal Sig 'l1L1' for icmLut8 and icmLut16 */
|
|
#define icmSig816CLUT ((icTagTypeSignature)icmMakeTag('l','1','L','U'))
|
|
|
|
/* ----------------------- */
|
|
|
|
/* Create an empty icmPe object. Return null on error */
|
|
/* Set ttype to the serialisation type of this Pe or its */
|
|
/* parent ttype if it doesn't use a sig in its serialisation. */
|
|
/* Use ttype = icmSigUnknownType if not a serialisable object. */
|
|
static icmPe *new_icmPe(struct _icc *icp, icTagTypeSignature ttype, icmPeSignature pesig);
|
|
|
|
/* =========================================================================== */
|
|
/* Client code populates data[i].pe etc using icc->new_pe(). */
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* Lut8Type and Lut16Type */
|
|
|
|
/* etype icmSigPeLut816 */
|
|
/* ttype icSigLut8Type */
|
|
/* ttype icSigLut16Type */
|
|
|
|
/* Indexes into underlying Pe's */
|
|
typedef enum {
|
|
icmLut816_ix_Matrix = 0,
|
|
icmLut816_ix_in = 1,
|
|
icmLut816_ix_CLUT = 2,
|
|
icmLut816_ix_out = 3
|
|
} icmLut1_ix;
|
|
|
|
struct _icmLut1 {
|
|
ICM_PE_SEQ_MEMBERS(struct _icmLut1)
|
|
|
|
/* Private: */
|
|
unsigned int bpv; /* Bytes per value for curves and cLUT */
|
|
|
|
/* Public: */
|
|
/* unsigned int inputChan; No. of input channels (in icpPeSeq) */
|
|
/* unsigned int outputChan; No. of output channels (in icpPeSeq) */
|
|
unsigned int inputEnt; /* Num of in-table entries (must be 256 for Lut8) */
|
|
unsigned int clutPoints; /* Num of grid points */
|
|
unsigned int outputEnt; /* Num of out-table entries (must be 256 for Lut8) */
|
|
|
|
/* Processing Element aliases: */
|
|
icmPeMatrix *pe_mx;
|
|
icmPeCurve **pe_ic;
|
|
icmPeClut *pe_cl;
|
|
icmPeCurve **pe_oc;
|
|
|
|
}; typedef struct _icmLut1 icmLut1;
|
|
|
|
typedef struct _icmLut1 icmLut8;
|
|
typedef struct _icmLut1 icmLut16;
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* A Pe that encodes an RGB shaper-matrix transform. */
|
|
/* This transform is always XYZ PCS. */
|
|
/* (This is not a serialisable tagtype) */
|
|
|
|
struct _icmShaperMatrix {
|
|
ICM_PE_SEQ_MEMBERS(struct _icmShaperMatrix)
|
|
|
|
/* icSigCurveType */
|
|
icmBase *redCurve, *greenCurve, *blueCurve;
|
|
icmXYZArray *redColrnt, *greenColrnt, *blueColrnt;
|
|
|
|
}; typedef struct _icmShaperMatrix icmShaperMatrix;
|
|
|
|
/* Create an empty object. Return null on error. */
|
|
/* Doesn't set icc error if tags not present. */
|
|
static icmPeSeq *new_icmShaperMatrix(
|
|
struct _icc *icp,
|
|
int invert /* If nz, setup inverse of shape-matrix */
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* A Pe that encodes an Monochrome shaper-mono transform. */
|
|
/* (This is not a serialisable tagtype) */
|
|
|
|
struct _icmShaperMono {
|
|
ICM_PE_SEQ_MEMBERS(struct _icmShaperMono)
|
|
|
|
/* icSigCurveType */
|
|
icmBase *grayCurve;
|
|
|
|
}; typedef struct _icmShaperMono icmShaperMono;
|
|
|
|
/* Create an empty object. Return null on error. */
|
|
/* Doesn't set icc error if tags not present. */
|
|
static icmPeSeq *new_icmShaperMono(
|
|
struct _icc *icp,
|
|
int invert /* If nz, setup inverse of shape-mono */
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* A Pe that implements the mono<->PCS conversion. */
|
|
/* (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeMono {
|
|
ICM_PE_MEMBERS(struct _icmPeMono)
|
|
}; typedef struct _icmPeMono icmPeMono;
|
|
|
|
/* Create the Pe */
|
|
static icmPe *new_icmPeMono(
|
|
struct _icc *icp
|
|
);
|
|
|
|
/* =========================================================== */
|
|
/* A Pe that inverts another Pe. */
|
|
/* (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeInverter {
|
|
ICM_PE_MEMBERS(struct _icmPeInverter)
|
|
|
|
icmPe *pe; /* Pe that's being inverted */
|
|
|
|
}; typedef struct _icmPeInverter icmPeInverter;
|
|
|
|
/* Make Pe appear to be its inverse. */
|
|
static icmPe *new_icmPeInverter(
|
|
struct _icc *icp,
|
|
icmPe *pe
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* XYZ <-> Lab Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeXYZ2Lab {
|
|
ICM_PE_MEMBERS(struct _icmPeXYZ2Lab)
|
|
struct _icmLu4Space *lu;
|
|
|
|
}; typedef struct _icmPeXYZ2Lab icmPeXYZ2Lab;
|
|
|
|
static icmPe *new_icmPeXYZ2Lab(
|
|
struct _icc *icp,
|
|
struct _icmLu4Space *lu, /* pcswht */
|
|
int invert /* Lab->XYZ */
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* XYZ abs <-> XYZ rel Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeAbs2Rel {
|
|
ICM_PE_MEMBERS(struct _icmPeAbs2Rel)
|
|
struct _icmLu4Space *lu;
|
|
}; typedef struct _icmPeAbs2Rel icmPeAbs2Rel;
|
|
|
|
static icmPe *new_icmPeAbs2Rel(
|
|
struct _icc *icp,
|
|
struct _icmLu4Space *lu, /* wp, toAbs, fromAbs */
|
|
int invert /* Lab->XYZ */
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* XYZ <-> XYZ8 Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeXYZ2XYZ8 {
|
|
ICM_PE_MEMBERS(struct _icmPeXYZ2XYZ8)
|
|
}; typedef struct _icmPeXYZ2XYZ8 icmPeXYZ2XYZ8;
|
|
|
|
static icmPe *new_icmPeXYZ2XYZ8(
|
|
struct _icc *icp,
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* XYZ <-> XYZ16 Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeXYZ2XYZ16 {
|
|
ICM_PE_MEMBERS(struct _icmPeXYZ2XYZ16)
|
|
}; typedef struct _icmPeXYZ2XYZ16 icmPeXYZ2XYZ16;
|
|
|
|
static icmPe *new_icmPeXYZ2XYZ16(
|
|
struct _icc *icp,
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* Lab <-> Lab8 Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeLab2Lab8 {
|
|
ICM_PE_MEMBERS(struct _icmPeLab2Lab8)
|
|
}; typedef struct _icmPeLab2Lab8 icmPeLab2Lab8;
|
|
|
|
static icmPe *new_icmPeLab2Lab8(
|
|
struct _icc *icp,
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* Lab <-> LabV2 Pe (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeLab2LabV2 {
|
|
ICM_PE_MEMBERS(struct _icmPeLab2LabV2)
|
|
}; typedef struct _icmPeLab2LabV2 icmPeLab2LabV2;
|
|
|
|
static icmPe *new_icmPeLab2LabV2(
|
|
struct _icc *icp,
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* Generic <-> Normalized Pe (This is not a serialisable tagtype) */
|
|
/* min/max difference is sanity limited to be at least 1e-4. */
|
|
/* NOTE that these conversions don't clip. */
|
|
|
|
struct _icmPeGeneric2Norm {
|
|
ICM_PE_MEMBERS(struct _icmPeGeneric2Norm)
|
|
double min[MAX_CHAN]; /* Full range min & max */
|
|
double max[MAX_CHAN];
|
|
double nmin[MAX_CHAN]; /* Normalize range min & max */
|
|
double nmax[MAX_CHAN];
|
|
char ident[50];
|
|
}; typedef struct _icmPeGeneric2Norm icmPeGeneric2Norm;
|
|
|
|
static icmPe *new_icmPeFullyGeneric2Norm(
|
|
struct _icc *icp,
|
|
unsigned int nchan,
|
|
double *min, double *max, /* Per channel range to be normalised */
|
|
double *nmin, double *nmax, /* Per channel range to normalize to (NULL = 0..1) */
|
|
char *ident, /* Encoding identifier */
|
|
int invert
|
|
);
|
|
|
|
static icmPe *new_icmPeGeneric2Norm(
|
|
struct _icc *icp,
|
|
unsigned int nchan,
|
|
double *min, double *max, /* Per channel range to be normalised */
|
|
char *ident, /* Encoding identifier */
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* A point to grid alignment transform. */
|
|
/* This creates a per channel transform that piecwize bends */
|
|
/* the input so as to land the given point on a grid point. */
|
|
/* The values are assumed in the range 0..1 */
|
|
|
|
struct _icmPeGridAlign {
|
|
ICM_PE_MEMBERS(struct _icmPeGridAlign)
|
|
double src[MAX_CHAN];
|
|
double dst[MAX_CHAN];
|
|
double fwdlow[MAX_CHAN];
|
|
double fwdhigh[MAX_CHAN];
|
|
double bwdlow[MAX_CHAN];
|
|
double bwdlowoff[MAX_CHAN];
|
|
double bwdhigh[MAX_CHAN];
|
|
double bwdhighoff[MAX_CHAN];
|
|
|
|
}; typedef struct _icmPeGridAlign icmPeGridAlign;
|
|
|
|
static icmPe *new_icmPeGridAlign(
|
|
struct _icc *icp,
|
|
unsigned int nchan,
|
|
double *point, /* Point to aim for, must be 0..1 */
|
|
unsigned int *clutPoints, /* Grid resolution for each channel */
|
|
int invert
|
|
);
|
|
|
|
/* ------------------------------------------------------------ */
|
|
/* A NOP (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeNOP {
|
|
ICM_PE_MEMBERS(struct _icmPeNOP)
|
|
}; typedef struct _icmPeNOP icmPeNOP;
|
|
|
|
static icmPe *new_icmPeNOP(
|
|
struct _icc *icp,
|
|
unsigned int nchan
|
|
);
|
|
|
|
/* ========================================================= */
|
|
/* A Processing Element Container (This is not a serialisable tagtype) */
|
|
|
|
struct _icmPeContainer {
|
|
ICM_PE_SEQ_MEMBERS(struct _icmPeContainer)
|
|
|
|
/* Added Pe's will have their reference counts incremented, */
|
|
/* so if we adding a new_PeXXX, we need to delete it after adding. */
|
|
/* Removed Pe's will have their reference counts decremented. */
|
|
/* All these will return an error code. */
|
|
|
|
/* Add a Pe to the end of the sequence */
|
|
int (*append) (struct _icmPeContainer *p, icmPe *pe);
|
|
|
|
/* Add a Pe to the start of the sequence */
|
|
int (*prepend) (struct _icmPeContainer *p, icmPe *pe);
|
|
|
|
/* Insert a Pe before the given index */
|
|
int (*insert) (struct _icmPeContainer *p, unsigned int ix, icmPe *pe);
|
|
|
|
/* Replace the Pe at the given index */
|
|
int (*replace) (struct _icmPeContainer *p, unsigned int ix, icmPe *pe);
|
|
|
|
/* Remove the Pe at the given index */
|
|
int (*remove) (struct _icmPeContainer *p, unsigned int ix);
|
|
|
|
/* Append Pe's from another icmPeContainer, */
|
|
/* starting at six and ending before eix. */
|
|
/* Any empty or attr == NOP are skipped. */
|
|
/* This will flatten any sub-icmPeSeq, resulting in a sequence */
|
|
/* of direct Pe's or direct Pe's inside an Inverter. */
|
|
int (*append_pes) (struct _icmPeContainer *p, struct _icmPeSeq *src, int six, int eix);
|
|
|
|
/* Various icmPeContainer/icmPeSeq characteristic analysis methods: */
|
|
/* These all assume that the icmPeContainer is in a flattened state. */
|
|
|
|
/* Find the largest per channel input lut resolution. */
|
|
/* res may be NULL */
|
|
/* Returns 0 if there is no per channel lut in the input sequence. */
|
|
unsigned int (*max_in_res)(struct _icmPeContainer *p, int res[MAX_CHAN]);
|
|
|
|
/* Find the largest cLUT clutPoints[] value. */
|
|
/* res may be NULL */
|
|
/* Returns 0 if there is no cLut transform in the sequence. */
|
|
unsigned int (*max_clut_res)(struct _icmPeContainer *p, int res[MAX_CHAN]);
|
|
|
|
/* Find the largest per channel output lut resolution. */
|
|
/* res may be NULL */
|
|
/* Returns 0 if there is no per channel lut in the output sequence. */
|
|
unsigned int (*max_out_res)(struct _icmPeContainer *p, int res[MAX_CHAN]);
|
|
|
|
/* Determine if the per channel input or output is likely to be */
|
|
/* in a linear light space. We do this by seeing if the first */
|
|
/* non-per channel or format element is a matrix or matrix like element. */
|
|
int (*linear_light_inout)(struct _icmPeContainer *p, int dir);
|
|
|
|
/* Return a pointer to the last icmPeLut and a Seq containing */
|
|
/* the transforms from the output of the Lut */
|
|
/* Return NULL if no icmPeLut */
|
|
/* Delete both objects when done */
|
|
icmPeClut *(*get_lut)(
|
|
struct _icmPeContainer *p,
|
|
struct _icmPeContainer **ptail /* If not NULL return tail process, NULL if none */
|
|
);
|
|
|
|
/* Return total ink limit and channel maximums. */
|
|
/* return -1.0 if this lu doesn't have an icmPeClut in it */
|
|
double (*get_tac) (
|
|
struct _icmPeContainer *p,
|
|
double *chmax, /* device return channel maximums. May be NULL */
|
|
void (*calfunc)(void *cntx, double *out, double *in), /* Optional calibration func. */
|
|
void *cntx
|
|
);
|
|
|
|
}; typedef struct _icmPeContainer icmPeContainer;
|
|
|
|
/* Create an empty object. Return null on error */
|
|
static icmPeContainer *new_icmPeContainer(
|
|
struct _icc *icp,
|
|
int dinch, /* Default number of input channels, 0 OK if will add non-NULL memb. Pe. */
|
|
int doutch /* Default number of output channels, 0 OK if will add non-NULL memb. Pe. */
|
|
);
|
|
|
|
|