860 lines
32 KiB
C
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 */
|
|
|