Files
2026-08-20 20:28:40 +01:00

860 lines
32 KiB
C

#ifndef ICC_UTIL_H
#define ICC_UTIL_H
/*
* International Color Consortium Format Library (icclib)
* Utility functions used by icclib and other code.
*
* Author: Graeme W. Gill
* Date: 1999/11/29
* Version: 3.0.0
*
* Copyright 1997 - 2022 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
* see the License4.txt file in this directory for licensing details.
*/
/*
* The distinction between "core" and "utility" functions is somewhat
* arbitrary.
*/
/* 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 <limits.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Set a 3 vector to the same value */
#define icmSet3(d_ary, s_val) ((d_ary)[0] = (s_val), (d_ary)[1] = (s_val), \
(d_ary)[2] = (s_val))
/* Set a 3 vector to 3 values */
#define icmInit3(d_ary, s1, s2, s3) ((d_ary)[0] = (s1), (d_ary)[1] = (s2), \
(d_ary)[2] = (s3))
/* Some 2 vector macros: */
#define icmSet2(d_ary, s_val) ((d_ary)[0] = (s_val), (d_ary)[1] = (s_val))
#define icmCpy2(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1])
#define icmAdd2(d_ary, s1_ary, s2_ary) ((d_ary)[0] = (s1_ary)[0] + (s2_ary)[0], \
(d_ary)[1] = (s1_ary)[1] + (s2_ary)[1])
#define icmSub2(d_ary, s1_ary, s2_ary) ((d_ary)[0] = (s1_ary)[0] - (s2_ary)[0], \
(d_ary)[1] = (s1_ary)[1] - (s2_ary)[1])
/* Copy a 3 vector */
#define icmCpy3(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
(d_ary)[2] = (s_ary)[2])
/* Copy a 4 vector */
#define icmCpy4(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
(d_ary)[2] = (s_ary)[2], (d_ary)[3] = (s_ary)[3])
/* - - - - - - - - - - - - - - */
/* Clamp a 3 vector to be +ve */
void icmClamp3(double out[3], double in[3]);
/* Invert (negate) a 3 vector */
void icmInv3(double out[3], double in[3]);
/* Add two 3 vectors */
void icmAdd3(double out[3], double in1[3], double in2[3]);
#define ICMADD3(o, i, j) ((o)[0] = (i)[0] + (j)[0], (o)[1] = (i)[1] + (j)[1], (o)[2] = (i)[2] + (j)[2])
/* Subtract two 3 vectors, out = in1 - in2 */
void icmSub3(double out[3], double in1[3], double in2[3]);
#define ICMSUB3(o, i, j) ((o)[0] = (i)[0] - (j)[0], (o)[1] = (i)[1] - (j)[1], (o)[2] = (i)[2] - (j)[2])
/* Divide two 3 vectors, out = in1/in2 */
void icmDiv3(double out[3], double in1[3], double in2[3]);
#define ICMDIV3(o, i, j) ((o)[0] = (i)[0]/(j)[0], (o)[1] = (i)[1]/(j)[1], (o)[2] = (i)[2]/(j)[2])
/* Multiply two 3 vectors, out = in1 * in2 */
void icmMul3(double out[3], double in1[3], double in2[3]);
#define ICMMUL3(o, i, j) ((o)[0] = (i)[0] * (j)[0], (o)[1] = (i)[1] * (j)[1], (o)[2] = (i)[2] * (j)[2])
/* Take (signed) values to power */
void icmPow3(double out[3], double in[3], double p);
/* Square values */
void icmSqr3(double out[3], double in[3]);
/* Square root of values */
void icmSqrt3(double out[3], double in[3]);
/* Take absolute of a 3 vector */
void icmAbs3(double out[3], double in[3]);
/* Compute sum of the vectors components */
#define icmSum3(vv) ((vv)[0] + (vv)[1] + (vv)[2])
/* Compute the dot product of two 3 vectors */
double icmDot3(double in1[3], double in2[3]);
#define ICMDOT3(o, i, j) ((o) = (i)[0] * (j)[0] + (i)[1] * (j)[1] + (i)[2] * (j)[2])
/* Compute the cross product of two 3D vectors, out = in1 x in2 */
void icmCross3(double out[3], double in1[3], double in2[3]);
/* Compute the norm squared (length squared) of a 3 vector */
double icmNorm3sq(double in[3]);
#define ICMNORM3SQ(i) ((i)[0] * (i)[0] + (i)[1] * (i)[1] + (i)[2] * (i)[2])
/* Compute the norm (length) of a 3 vector */
double icmNorm3(double in[3]);
#define ICMNORM3(i) sqrt((i)[0] * (i)[0] + (i)[1] * (i)[1] + (i)[2] * (i)[2])
/* Scale a 3 vector by the given ratio */
void icmScale3(double out[3], double in[3], double rat);
#define ICMSCALE3(o, i, j) ((o)[0] = (i)[0] * (j), (o)[1] = (i)[1] * (j), (o)[2] = (i)[2] * (j))
/* Scale a 3 vector by the given ratio and add it */
/* i.e. out = in2 + in1 * rat */
void icmScaleAdd3(double out[3], double in2[3], double in1[3], double rat);
/* Compute a blend between in0 and in1 for bl 0..1 */
void icmBlend3(double out[3], double in0[3], double in1[3], double bf);
/* Clip a vector to the range 0.0 .. 1.0 */
void icmClip3(double out[3], double in[3]);
/* Clip a vector to the range 0.0 .. 1.0 */
/* and return nz if clipping occured */
int icmClip3sig(double out[3], double in[3]);
/* Clip a vector to the range 0.0 .. 1.0 */
/* and return any clipping margine over the limits. */
double icmClip3marg(double out[3], double in[3]);
/* Normalise a 3 vector to the given length. Return nz if not normalisable */
int icmNormalize3(double out[3], double in[3], double len);
/* Compute the norm squared (length squared) of a vector defined by two points */
double icmNorm33sq(double in1[3], double in0[3]);
/* Compute the norm (length) of of a vector defined by two points */
double icmNorm33(double in1[3], double in0[3]);
/* Scale a vector from 0->1 by the given ratio. in0[] is the origin. */
void icmScale33(double out[3], double in1[3], double in0[3], double rat);
/* Normalise a vector from 0->1 to the given length. */
/* The new location of in1[] is returned in out[], in0[] is the origin. */
/* Return nz if not normalisable */
int icmNormalize33(double out[3], double in1[3], double in0[3], double len);
/* Dump a 3x3 matrix to a stream */
void icmDump3x3(FILE *fp, char *id, char *pfx, double a[3][3]);
/* Set a 3x3 matrix to a value */
void icmSetVal3x3(double mat[3][3], double val);
/* Set a 3x3 matrix to unity */
void icmSetUnity3x3(double mat[3][3]);
/* Copy a 3x3 transform matrix */
void icmCpy3x3(double out[3][3], double mat[3][3]);
/* Add a 3x3 transform matrix to another */
void icmAdd3x3(double dst[3][3], double src1[3][3], double src2[3][3]);
/* Scale each element of a 3x3 transform matrix */
void icmScale3x3(double dst[3][3], double src[3][3], double scale);
/* Multiply 3 vector by 3x3 transform matrix */
/* Organization is mat[out][in] */
void icmMulBy3x3(double out[3], double mat[3][3], double in[3]);
/* Tensor product. Multiply two 3 vectors to form a 3x3 matrix */
/* src1[] forms the colums, and src2[] forms the rows in the result */
void icmTensMul3(double dst[3][3], double src1[3], double src2[3]);
/* Multiply one 3x3 with another */
/* dst = src * dst */
void icmMul3x3(double dst[3][3], double src[3][3]);
/* Multiply one 3x3 with another #2 */
/* dst = src1 * src2 */
void icmMul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
/* Compute the determinant of a 3x3 matrix */
double icmDet3x3(double in[3][3]);
/* Invert a 3x3 transform matrix. Return 1 if error. */
int icmInverse3x3(double out[3][3], double in[3][3]);
/* Transpose a 3x3 matrix */
void icmTranspose3x3(double out[3][3], double in[3][3]);
/* Given two 3D points, create a matrix that rotates */
/* and scales one onto the other about the origin 0,0,0. */
/* Use icmMulBy3x3() to apply this to other points */
void icmRotMat(double mat[3][3], double src[3], double targ[3]);
/* Copy a 3x4 transform matrix */
void icmCpy3x4(double out[3][4], double mat[3][4]);
/* Multiply 3 array by 3x4 transform matrix */
void icmMul3By3x4(double out[3], double mat[3][4], double in[3]);
/* Given two 3D vectors, create a matrix that translates, */
/* rotates and scales one onto the other. */
/* Use icmMul3By3x4 to apply this to other points */
void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], double t0[3]);
/* Compute the intersection of a vector and a plane */
/* return nz if there is no intersection */
int icmVecPlaneIsect(double isect[3], double pl_const, double pl_norm[3], double ve_1[3], double ve_0[3]);
/* Compute the closest point on a line to a point. */
/* Return closest points and parameter values if not NULL. */
int icmLinePointClosest(double ca[3], double *pa,
double la0[3], double la1[3], double pp[3]);
/* Compute the closest points between two lines a and b. */
/* Return closest points and parameter values if not NULL. */
/* Return nz if they are parallel. */
int icmLineLineClosest(double ca[3], double cb[3], double *pa, double *pb,
double la0[3], double la1[3], double lb0[3], double lb1[3]);
/* Given 3 3D points, compute a plane equation. */
/* The normal will be right handed given the order of the points */
/* The plane equation will be the 3 normal components and the constant. */
/* Return nz if any points are cooincident or co-linear */
int icmPlaneEqn3(double eq[4], double p0[3], double p1[3], double p2[3]);
/* Given a 3D point and a plane equation, return the signed */
/* distance from the plane */
double icmPlaneDist3(double eq[4], double p[3]);
/* - - - - - - - - - - - - - - - - - - - - - - - */
/* Multiply 4 vector by 4x4 transform matrix */
/* Organization is mat[out][in] */
void icmMulBy4x4(double out[4], double mat[4][4], double in[4]);
/* Transpose a 4x4 matrix */
void icmTranspose4x4(double out[4][4], double in[4][4]);
/* Clip a vector to the range 0.0 .. 1.0 */
/* and return any clipping margine over the limit */
double icmClip4marg(double out[4], double in[4]);
/* - - - - - - - - - - - - - - - - - - - - - - - */
#define icmNorm2(i) sqrt((i)[0] * (i)[0] + (i)[1] * (i)[1])
#define icmNorm2sq(i) ((i)[0] * (i)[0] + (i)[1] * (i)[1])
/* Compute the norm (length) of of a vector defined by two points */
double icmNorm22(double in1[2], double in0[2]);
/* Compute the norm (length) squared of of a vector defined by two points */
double icmNorm22sq(double in1[2], double in0[2]);
/* Compute the dot product of two 2 vectors */
double icmDot2(double in1[2], double in2[2]);
#define ICMDOT2(o, i, j) ((o) = (i)[0] * (j)[0] + (i)[1] * (j)[1])
/* Compute the dot product of two 2 vectors defined by 4 points */
/* 1->2 and 3->4 */
double icmDot22(double in1[2], double in2[2], double in3[2], double in4[2]);
/* Normalise a 2 vector to the given length. Return nz if not normalisable */
int icmNormalize2(double out[2], double in[2], double len);
/* Return an orthogonal vector */
void icmOrthog2(double out[2], double in[2]);
/* Given 2 2D points, compute a plane equation. */
/* The normal will be right handed given the order of the points */
/* The plane equation will be the 2 normal components and the constant. */
/* Return nz if any points are cooincident or co-linear */
int icmPlaneEqn2(double eq[3], double p0[2], double p1[2]);
/* Given a 2D point and a plane equation, return the signed */
/* distance from the plane */
double icmPlaneDist2(double eq[3], double p[2]);
/* Return the closest point on an implicit line to a point. */
/* Also return the absolute distance */
double icmImpLinePointClosest2(double cp[2], double eq[3], double pp[2]);
/* Return the point of intersection of two implicit lines . */
/* Return nz if there is no intersection (lines are parallel) */
int icmImpLineIntersect2(double res[2], double eq1[3], double eq2[3]);
/* Compute the closest point on a line to a point. */
/* Return closest point and parameter value if not NULL. */
/* Return nz if the line length is zero */
int icmLinePointClosest2(double cp[2], double *pa,
double la0[2], double la1[2], double pp[2]);
/* Given two infinite 2D lines define by two pairs of points, compute the intersection. */
/* Return nz if there is no intersection (lines are parallel) */
int icmLineIntersect2(double res[2], double p1[2], double p2[2], double p3[2], double p4[2]);
/* Given two finite 2D lines define by 4 points, compute their paramaterized intersection. */
/* res[] and/or aprm[] may be NULL. Param is prop. from p1 -> p2, p3 -> p4 */
/* Return 2 if there is no intersection (lines are parallel) */
/* Return 1 lines do not cross within their length */
int icmParmLineIntersect2(double ares[2], double aprm[2], double p1[2], double p2[2], double p3[2], double p4[2]);
/* Set a 2x2 matrix to unity */
void icmSetUnity2x2(double mat[2][2]);
/* Invert a 2x2 transform matrix. Return 1 if error. */
int icmInverse2x2(double out[2][2], double in[2][2]);
/* Compute a blend between in0 and in1 for bl 0..1 */
void icmBlend2(double out[2], double in0[2], double in1[2], double bf);
/* Scale a 2 vector by the given ratio */
void icmScale2(double out[2], double in[2], double rat);
/* Scale a 2 vector by the given ratio and add it */
void icmScaleAdd2(double out[2], double in2[3], double in1[2], double rat);
/* Convert orientation 0 = right, 1 = down, 2 = left, 3 = right */
/* into rotation matrix */
static void icmOr2mat(double mat[2][2], int or);
/* Convert an angle in radians into rotation matrix (0 = right) */
void icmRad2mat(double mat[2][2], double rad);
/* Convert an angle in degrees (0 = right) into rotation matrix */
void icmDeg2mat(double mat[2][2], double a);
/* Convert a vector into a rotation matrix */
void icmVec2mat(double mat[2][2], double dx, double dy);
/* Multiply 2 array by 2x2 transform matrix */
void icmMulBy2x2(double out[2], double mat[2][2], double in[2]);
/* - - - - - - - - - - - - - - */
/* General vector functions */
/* Set a vector to a single value */
void icmSetN(double *dst, double src, int len);
/* Copy a vector */
//void icmCpyN(double *dst, double *src, int len);
#define icmCpyN(dst, src, len) memmove((char *)(dst), (char *)(src), (len) * sizeof(double))
/* Clip a vector to the range 0.0 .. 1.0 */
void icmClipN(double out[3], double in[3], unsigned int len);
/* Clip a vector to the range 0.0 .. 1.0 */
/* and return any clipping margine over the limit */
double icmClipNmarg(double *out, double *in, unsigned int len);
/* Return the magnitude (norm) of the difference between two vectors */
double icmDiffN(double *s1, double *s2, int len);
/* ----------------------------------------------- */
/* Structure to hold pseudo-hilbert counter info */
struct _psh {
int di; /* Dimensionality */
unsigned int res[MAX_CHAN]; /* Resolution per coordinate */
unsigned int bits[MAX_CHAN]; /* Bits per coordinate */
unsigned int xbits; /* Max of bits[] */
unsigned int tbits; /* Total bits */
unsigned int tmask; /* Total 2^tbits count mask */
unsigned int count; /* Usable count */
unsigned int ix; /* Current binary index */
int diag; /* nz if generating singe diagnostic index */
}; typedef struct _psh psh;
/* Initialise a pseudo-hilbert grid counter, return total usable count. */
extern ICCLIB_API unsigned psh_init(psh *p, int di, unsigned int res, int co[]);
/* Same as above but with variable res per axis. */
extern ICCLIB_API unsigned psh_initN(psh *p, int di, unsigned int res[], int co[]);
/* Diagnostic init - psh returns the value in co[] and then terminates */
extern ICCLIB_API unsigned psh_init_diag(psh *p, int di, 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[]);
/* - - - - - - - - - - - - - - */
/* 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)
/* Simple macro to transfer an XYZ number to an XYZ number */
#define icmXYZ2XYZ(d_xyz, s_xyz) ((d_xyz).X = (s_xyz).X, (d_xyz).Y = (s_xyz).Y, \
(d_xyz).Z = (s_xyz).Z)
/* Simple macro to transfer an 3array to 3array */
/* Hmm. Same as icmCpy3 */
#define icmAry2Ary(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
(d_ary)[2] = (s_ary)[2])
/* CIE Y (range 0 .. 1) to perceptual CIE 1976 L* (range 0 .. 100) */
double icmY2L(double val);
/* Perceptual CIE 1976 L* (range 0 .. 100) to CIE Y (range 0 .. 1) */
double icmL2Y(double val);
/* 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);
/* CIE XYZ to perceptual Lpt */
extern ICCLIB_API void icmXYZ2Lpt(icmXYZNumber *w, double *out, double *in);
/* Perceptual Lpt to CIE XYZ */
extern ICCLIB_API void icmLpt2XYZ(icmXYZNumber *w, double *out, double *in);
/* LCh to Lab (general) */
extern ICCLIB_API void icmLCh2Lab(double *out, double *in);
/* Lab to LCh (general) */
extern ICCLIB_API void icmLab2LCh(double *out, double *in);
/* CIE XYZ to perceptual Luv */
extern ICCLIB_API void icmXYZ2Luv(icmXYZNumber *w, double *out, double *in);
/* Perceptual Luv to CIE XYZ */
extern ICCLIB_API void icmLuv2XYZ(icmXYZNumber *w, double *out, double *in);
/* XYZ to Yxy */
extern ICCLIB_API void icmXYZ2Yxy(double *out, double *in);
/* Yxy to XYZ */
extern ICCLIB_API void icmYxy2XYZ(double *out, double *in);
/* XYZ to xy */
extern ICCLIB_API void icmXYZ2xy(double *out, double *in);
/* Y & xy to XYZ */
extern ICCLIB_API void icmY_xy2XYZ(double *out, double *xy, double Y);
/* CIE XYZ to perceptual CIE 1976 UCS diagram Yu'v'*/
/* (Yu'v' is a better linear chromaticity space than Yxy) */
extern ICCLIB_API void icmXYZ21976UCS(double *out, double *in);
/* Perceptual CIE 1976 UCS diagram Yu'v' to CIE XYZ */
extern ICCLIB_API void icm1976UCS2XYZ(double *out, double *in);
/* CIE XYZ to perceptual CIE 1976 UCS diagram u'v'*/
/* (u'v' is a better linear chromaticity space than xy) */
extern ICCLIB_API void icmXYZ21976UCSuv(double *out, double *in);
/* CIE 1976 UCS diagram Y & u'v' to XYZ */
extern ICCLIB_API void icm1976UCSY_uv2XYZ(double *out, double *uv, double Y);
/* Aliases for above */
#define icmXYZ2Yuv icmXYZ21976UCS
#define icmYuv2XYZ icm1976UCS2XYZ
#define icmXYZ2uv icmXYZ21976UCSuv
#define icmY_uv2XYZ icm1976UCSY_uv2XYZ
/* CIE XYZ to perceptual CIE 1960 UCS */
/* (This was obsoleted by the 1976UCS, but is still used */
/* in computing color temperatures.) */
extern ICCLIB_API void icmXYZ21960UCS(double *out, double *in);
/* Perceptual CIE 1960 UCS to CIE XYZ */
extern ICCLIB_API void icm1960UCS2XYZ(double *out, double *in);
/* CIE XYZ to perceptual CIE 1964 WUV (U*V*W*) */
/* (This is obsolete but still used in computing CRI) */
extern ICCLIB_API void icmXYZ21964WUV(icmXYZNumber *w, double *out, double *in);
/* Perceptual CIE 1964 WUV (U*V*W*) to CIE XYZ */
extern ICCLIB_API void icm1964WUV2XYZ(icmXYZNumber *w, double *out, double *in);
/* CIE CIE1960 UCS to perceptual CIE 1964 WUV (U*V*W*) */
extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *in);
/* NOTE :- that these values are for the 1931 standard observer */
/* The standard D50 illuminant value */
extern icmXYZNumber icmD50;
extern icmXYZNumber icmD50_100; /* Scaled to 100 */
extern double icmD50_ary3[3]; /* As an array */
extern double icmD50_100_ary3[3]; /* Scaled to 100 as an array */
/* The standard D65 illuminant value */
extern icmXYZNumber icmD65;
extern icmXYZNumber icmD65_100; /* Scaled to 100 */
extern double icmD65_ary3[3]; /* As an array */
extern double icmD65_100_ary3[3]; /* Scaled to 100 as an array */
/* The default black value */
extern icmXYZNumber icmBlack;
/* The Standard ("wrong Von-Kries") chromatic transform matrix */
extern double icmWrongVonKries[3][3];
/* The Bradford chromatic transform matrix */
extern double icmBradford[3][3];
/* ----------------------------------------------- */
/* - - - - - - - - - - - - - - - - - - - - - - - */
/* Return the normal Delta E given two Lab values */
extern ICCLIB_API double icmLabDE(double *in0, double *in1);
/* Return the normal Delta E squared, given two Lab values */
extern ICCLIB_API double icmLabDEsq(double *in0, double *in1);
/* Return the normal Delta E squared given two XYZ values */
extern ICCLIB_API double icmXYZLabDEsq(icmXYZNumber *w, double *in0, double *in1);
/* Return the normal Delta E given two XYZ values */
extern ICCLIB_API double icmXYZLabDE(icmXYZNumber *w, double *in0, double *in1);
/* Return the normal Delta E squared given two XYZ values */
extern ICCLIB_API double icmXYZLptDEsq(icmXYZNumber *w, double *in0, double *in1);
/* Return the normal Delta E given two XYZ values */
extern ICCLIB_API double icmXYZLptDE(icmXYZNumber *w, double *in0, double *in1);
/* Return the CIE94 Delta E color difference measure for two Lab values */
extern ICCLIB_API double icmCIE94(double *in0, double *in1);
/* Return the CIE94 Delta E color difference measure squared, for two Lab values */
extern ICCLIB_API double icmCIE94sq(double *in0, double *in1);
/* Return the CIE94 Delta E color difference measure for two XYZ values */
extern ICCLIB_API double icmXYZCIE94(icmXYZNumber *w, double *in0, double *in1);
/* Return the CIEDE2000 Delta E color difference measure for two Lab values */
extern ICCLIB_API double icmCIE2K(double *in0, double *in1);
/* Return the CIEDE2000 Delta E color difference measure squared, for two Lab values */
extern ICCLIB_API double icmCIE2Ksq(double *in0, double *in1);
/* Return the CIEDE2000 Delta E color difference measure for two XYZ values */
extern ICCLIB_API double icmXYZCIE2K(icmXYZNumber *w, double *in0, double *in1);
/* - - - - - - - - - - - - - - - - - - - - - - - */
/* Clip Lab, while maintaining hue angle. */
/* Return nz if clipping occured */
int icmClipLab(double out[3], double in[3]);
/* Clip XYZ, while maintaining hue angle */
/* Return nz if clipping occured */
int icmClipXYZ(double out[3], double in[3]);
/* - - - - - - - - - - - - - - - - - - - - - - - */
/* RGB XYZ primaries to device to RGB->XYZ transform matrix */
/* Return non-zero if matrix would be singular */
/* Use icmMulBy3x3(dst, mat, src) */
int icmRGBXYZprim2matrix(
double red[3], /* Red colorant */
double green[3], /* Green colorant */
double blue[3], /* Blue colorant */
double white[3], /* White point */
double mat[3][3] /* Destination matrix[RGB][XYZ] */
);
/* RGB Yxy primaries to device to RGB->XYZ transform matrix */
/* Return non-zero if matrix would be singular */
/* Use icmMulBy3x3(dst, mat, src) */
int icmRGBYxyprim2matrix(
double red[3], /* Red colorant */
double green[3], /* Green colorant */
double blue[3], /* Blue colorant */
double white[3], /* White point */
double mat[3][3], /* Return matrix[RGB][XYZ] */
double wXYZ[3] /* Return white XYZ */
);
/* Chromatic Adaption transform utility */
/* Return a 3x3 chromatic adaption matrix */
/* Use icmMulBy3x3(dst, mat, src) */
/* [ use icc->chromAdaptMatrix() to use the profiles cone space matrix rather */
/* than specify a CAM ] */
#define ICM_CAM_NONE 0x0000 /* No flags */
#define ICM_CAM_BRADFORD 0x0001 /* Use Bradford sharpened response space */
#define ICM_CAM_MULMATRIX 0x0002 /* Transform the given matrix rather than */
/* create a transform from scratch. */
/* NOTE that to transform primaries they */
/* must be mat[XYZ][RGB] format! */
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 */
);
/* Pre-round RGB device primary values to ensure that */
/* the sum of the quantized primaries is the same as */
/* the quantized sum. */
void quantizeRGBprimsS15Fixed16(
double mat[3][3] /* matrix[RGB][XYZ] */
);
/* Pre-round a 3x3 matrix to ensure that the product of */
/* the matrix and the input value is the same as */
/* the quantized matrix product. This is used to improve accuracy */
/* of 'chad' tag in computing absolute white point. */
void icmQuantize3x3S15Fixed16(
double targ[3], /* Target of product */
double mat[3][3], /* matrix[][] to be quantized */
double in[3] /* Input of product - must not be 0.0! */
);
/* - - - - - - - - - - - - - - */
/* Video functions */
/* Convert Lut table index/value to YCbCr */
void icmLut2YCbCr(double *out, double *in);
/* Convert YCbCr to Lut table index/value */
void icmYCbCr2Lut(double *out, double *in);
/* Convert Rec601 RGB' into YPbPr, (== "full range YCbCr") */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
void icmRec601_RGBd_2_YPbPr(double out[3], double in[3]);
/* Convert Rec601 YPbPr to RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
void icmRec601_YPbPr_2_RGBd(double out[3], double in[3]);
/* Convert Rec709 1150/60/2:1 RGB' into YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
void icmRec709_RGBd_2_YPbPr(double out[3], double in[3]);
/* Convert Rec709 1150/60/2:1 YPbPr to RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
void icmRec709_YPbPr_2_RGBd(double out[3], double in[3]);
/* Convert Rec709 1250/50/2:1 RGB' into YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
void icmRec709_50_RGBd_2_YPbPr(double out[3], double in[3]);
/* Convert Rec709 1250/50/2:1 YPbPr to RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
void icmRec709_50_YPbPr_2_RGBd(double out[3], double in[3]);
/* Convert Rec2020 RGB' into Non-constant liminance YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
void icmRec2020_NCL_RGBd_2_YPbPr(double out[3], double in[3]);
/* Convert Rec2020 Non-constant liminance YPbPr into RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
void icmRec2020_NCL_YPbPr_2_RGBd(double out[3], double in[3]);
/* Convert Rec2020 RGB' into Constant liminance YPbPr, or "full range YCbCr" */
/* where input 0..1, output 0..1, -0.5 .. 0.5, -0.5 .. 0.5 */
void icmRec2020_CL_RGBd_2_YPbPr(double out[3], double in[3]);
/* Convert Rec2020 Constant liminance YPbPr into RGB' (== "full range YCbCr") */
/* where input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, output 0.0 .. 1 */
void icmRec2020_CL_YPbPr_2_RGBd(double out[3], double in[3]);
/* Convert Rec601/709/2020 YPbPr to YCbCr range. */
/* input 0..1, -0.5 .. 0.5, -0.5 .. 0.5, */
/* output 16/255 .. 235/255, 16/255 .. 240/255, 16/255 .. 240/255 */
void icmRecXXX_YPbPr_2_YCbCr(double out[3], double in[3]);
/* Convert Rec601/709/2020 YCbCr to YPbPr range. */
/* input 16/255 .. 235/255, 16/255 .. 240/255, 16/255 .. 240/255 */
/* output 0..1, -0.5 .. 0.5, -0.5 .. 0.5, */
void icmRecXXX_YCbCr_2_YPbPr(double out[3], double in[3]);
/* Convert full range RGB to Video range 16..235 RGB */
void icmRGB_2_VidRGB(double out[3], double in[3]);
/* Convert Video range 16..235 RGB to full range RGB */
void icmVidRGB_2_RGB(double out[3], double in[3]);
/* ---------------------------------------------------------- */
/* PS 3.14-2009, Digital Imaging and Communications in Medicine */
/* (DICOM) Part 14: Grayscale Standard Display Function */
/* JND index value 1..1023 to L 0.05 .. 3993.404 cd/m^2 */
double icmDICOM_fwd(double jnd);
/* L 0.05 .. 3993.404 cd/m^2 to JND index value 1..1023 */
double icmDICOM_bwd(double L);
/* ---------------------------------------------------------- */
/* Some utility functions */
/* Convert an angle in radians into chromatic RGB values */
/* in a simple geometric fashion with 0 = Red */
void icmRad2RGB(double rgb[3], double ang);
/* ---------------------------------------------------------- */
/* UTF conversion functions with checking. */
/* Heavily modified from Unicode, Inc. code, Author: Mark E. Davis, 1994. */
/* see corresponding icc.c for full credits and copyright */
/* Error and warning codes from conversions */
typedef enum {
icmUTF_ok = 0x00000, /* ok */
icmUTF_emb_nul = 0x00001, /* embedded nul */
/* UTF-16 errors */
icmUTF_no_nul = 0x00002, /* no nul terminator */
icmUTF_unex_nul = 0x00004, /* unexpected nul terminator */
icmUTF_prem_nul = 0x00008, /* nul before end */
icmUTF_bad_surr = 0x00010, /* badly formed surrogate pair */
icmUTF_unn_bom = 0x00020, /* unecessary Byte Order Mark */
icmUTF_odd_bytes = 0x00040, /* length is odd number of bytes */
/* UTF-8 errors */
icmUTF_unex_cont = 0x00080, /* unexpected continuation byte */
icmUTF_tmany_cont = 0x00100, /* too many continuation bytes */
icmUTF_short_cont = 0x00200, /* continuation bytes are cut short */
icmUTF_overlong = 0x00400, /* overlong encoding */
icmUTF_inv_cdpnt = 0x00800, /* invalid code point - UTF-16 surrogate */
icmUTF_ovr_cdpnt = 0x01000, /* invalid code point - greater than unicode maximum */
/* ASCII errors */
icmUTF_non_ascii = 0x02000, /* found non-ascii character in UTF-8 */
icmUTF_ascii_toolong = 0x04000, /* ASCII longer than fixed sized buffer */
/* ScriptCode errors */
icmUTF_sc_tooshort = 0x08000, /* ScriptCode size < 67 */
icmUTF_sc_toolong = 0x10000 /* ScriptCode size > 67 */
} icmUTFerr;
/* Serialisation */
size_t icmUTF16SntoUTF8(icmUTFerr *pillegal, icmUTF8 *out, icmFBuf *bin, size_t len, int nonul);
size_t icmUTF8toUTF16Sn(icmUTFerr *pillegal, icmFBuf *bout, icmUTF8 *in, size_t len, int nonul);
size_t icmASCIIZSntoUTF8(icmUTFerr *pillegal, icmUTF8 *out, icmFBuf *bin, size_t len, int fxlen);
size_t icmUTF8toASCIIZSn(icmUTFerr *pillegal, icmFBuf *bout, icmUTF8 *in, size_t len, int fxlen);
size_t icmSntoScriptCode(icmUTFerr *pillegal, icmUTF8 *out, icmFBuf *bin, size_t len);
size_t icmScriptCodetoSn(icmUTFerr *pillegal, icmFBuf *bout, ORD8 *in, size_t len);
/* General convert UTF16 to UTF8. */
/* Repairs UTF16 string to be legal UTF-8. */
/* Input is expected to be nul terminated. */
/* Output will be nul terminated. */
/* Return resulting size in bytes including nul. */
/* out pointer can be NULL to size buffer. */
/* pillegal can be NULL. */
size_t icmUTF16toUTF8(icmUTFerr *pillegal, icmUTF8 *out, icmUTF16 *in);
size_t icmUTF8toUTF16(icmUTFerr *pillegal, icmUTF16 *out, icmUTF8 *in);
/* Convert utf-8 to HTML escapes. illegal will have icmUTF_non_ascii set if any non-ASCII found. */
/* All output pointers may be NULL */
size_t icmUTF8toHTMLESC(icmUTFerr *pillegal, char *out, icmUTF8 *in);
/* Convert UTF-8 to ASCII. Out of range characters are replaced by '?'. */
/* illegal will have icmUTF_non_ascii set if any non-ASCII found. */
/* All output pointers may be NULL */
size_t icmUTF8toASCII(icmUTFerr *pillegal, char *out, icmUTF8 *in);
/* Convert icmUTFerr to a comma separated list of error descriptions. */
char *icmUTFerr2str(icmUTFerr err);
/* ---------------------------------------------------------- */
/* Print an int vector to a string. */
/* Returned static buffer is re-used every 5 calls. */
char *icmPiv(int di, int *p);
/* Print a double color vector to a string. */
/* Returned static buffer is re-used every 5 calls. */
char *icmPdv(int di, double *p);
/* Print a double color vector to a string with format. */
/* Returned static buffer is re-used every 5 calls. */
char *icmPdvf(int di, char *fmt, double *p);
/* Print a float color vector to a string. */
/* Returned static buffer is re-used every 5 calls. */
char *icmPfv(int di, float *p);
/* Print an XYZ */
/* Returned static buffer is re-used every 5 calls. */
char *icmPXYZ(icmXYZNumber *p);
/* Print an 0..1 range XYZ as a D50 Lab string */
/* Returned static buffer is re-used every 5 calls. */
char *icmPLab(double *p);
/* ---------------------------------------------------------- */
/* Cause a debug break or stack trace */
#ifndef DEBUG_BREAK
# ifdef NT
# define DEBUG_BREAK DebugBreak()
# else
# if defined(__APPLE__)
// extern void Debugger();
//# define DEBUG_BREAK Debugger() // deprecated ?
//extern void __debugbreak();
//# define DEBUG_BREAK __debugbreak()
# define DEBUG_BREAK *((volatile char *)0) = 0x55;
# else
# include <signal.h>
# if defined(SIGTRAP)
# define DEBUG_BREAK raise(SIGTRAP)
# else
# define DEBUG_BREAK raise(SIGABRT)
# endif
# endif
# endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* ICC_UTIL_H */