summaryrefslogtreecommitdiff
path: root/icc
diff options
context:
space:
mode:
Diffstat (limited to 'icc')
-rw-r--r--icc/ClayRGB1998.icmbin584 -> 640 bytes
-rw-r--r--icc/EBU3213_PAL.icmbin9120 -> 9176 bytes
-rw-r--r--icc/Jamfile9
-rw-r--r--icc/Makefile9
-rw-r--r--icc/ProPhoto.icmbin2892 -> 2948 bytes
-rw-r--r--icc/ProPhotoLin.icmbin2900 -> 2956 bytes
-rw-r--r--icc/Rec2020.icmbin9064 -> 9120 bytes
-rw-r--r--icc/Rec709.icmbin2920 -> 2976 bytes
-rw-r--r--icc/SMPTE431_P3.icmbin872 -> 928 bytes
-rw-r--r--icc/SMPTE_RP145_NTSC.icmbin9100 -> 9156 bytes
-rw-r--r--icc/icc.c987
-rw-r--r--icc/icc.h153
-rw-r--r--icc/iccstd.c7
-rw-r--r--icc/icctest.c2
-rw-r--r--icc/lab2lab.icmbin500 -> 556 bytes
-rw-r--r--icc/log.txt12
-rw-r--r--icc/mcheck.c250
-rw-r--r--icc/mkDispProf.c65
-rw-r--r--icc/sRGB.icmbin3212 -> 3268 bytes
19 files changed, 841 insertions, 653 deletions
diff --git a/icc/ClayRGB1998.icm b/icc/ClayRGB1998.icm
index 1c3a02e..4c8ecb3 100644
--- a/icc/ClayRGB1998.icm
+++ b/icc/ClayRGB1998.icm
Binary files differ
diff --git a/icc/EBU3213_PAL.icm b/icc/EBU3213_PAL.icm
index 54cfed7..b0e67bc 100644
--- a/icc/EBU3213_PAL.icm
+++ b/icc/EBU3213_PAL.icm
Binary files differ
diff --git a/icc/Jamfile b/icc/Jamfile
index 9f27848..4bedbba 100644
--- a/icc/Jamfile
+++ b/icc/Jamfile
@@ -45,6 +45,12 @@ MainsFromSources mkDispProf.c ;
if $(BUILD_JUNK) {
+ HDRS += ../plot ;
+ LINKLIBS += ../plot/libvrml ;
+
+ #Monotonic behaviour checker
+ MainsFromSources mcheck.c ;
+
# MainsFromSources tt.c ;
MainsFromSources mksRGB.c ;
@@ -64,9 +70,6 @@ if $(BUILD_JUNK) {
# check CIEDE2000
MainsFromSources testDE2K.c ;
-
- #Monotonic behaviour checker
- MainsFromSources mcheck.c ;
}
diff --git a/icc/Makefile b/icc/Makefile
index dbb9992..85f19be 100644
--- a/icc/Makefile
+++ b/icc/Makefile
@@ -28,7 +28,7 @@ CCFLAGS = $(CCFLAGSDEF) $(CCOPTFLAG) $(CCDEFINES)
STDHDRS = $(STDHDRSDEF)
LINKFLAGS = $(LINKFLAGSDEF) $(LINKDEBUGFLAG)
-all:: libicc$(SUFLIB) icctest$(SUFEXE) lutest$(SUFEXE) icclu$(SUFEXE) iccdump$(SUFEXE) iccrw$(SUFEXE)
+all:: libicc$(SUFLIB) icctest$(SUFEXE) lutest$(SUFEXE) icclu$(SUFEXE) iccdump$(SUFEXE) iccrw$(SUFEXE) mkDispProf$(SUFEXE)
icc$(SUFOBJ): icc.c icc.h
@@ -79,4 +79,11 @@ iccrw$(SUFEXE): iccrw$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
$(LINK) $(LINKOF)iccrw$(SUFEXE) iccrw$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+mkDispProf$(SUFOBJ): mkDispProf.c icc.h
+ $(CC) $(CCOF)mkDispProf$(SUFOBJ) mkDispProf.c
+
+mkDispProf$(SUFEXE): mkDispProf$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)mkDispProf$(SUFEXE) mkDispProf$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
diff --git a/icc/ProPhoto.icm b/icc/ProPhoto.icm
index 3ed16cb..cb6ee56 100644
--- a/icc/ProPhoto.icm
+++ b/icc/ProPhoto.icm
Binary files differ
diff --git a/icc/ProPhotoLin.icm b/icc/ProPhotoLin.icm
index 579b903..28369aa 100644
--- a/icc/ProPhotoLin.icm
+++ b/icc/ProPhotoLin.icm
Binary files differ
diff --git a/icc/Rec2020.icm b/icc/Rec2020.icm
index 09d5ccf..0decaf6 100644
--- a/icc/Rec2020.icm
+++ b/icc/Rec2020.icm
Binary files differ
diff --git a/icc/Rec709.icm b/icc/Rec709.icm
index 46140bd..abf0a63 100644
--- a/icc/Rec709.icm
+++ b/icc/Rec709.icm
Binary files differ
diff --git a/icc/SMPTE431_P3.icm b/icc/SMPTE431_P3.icm
index f3861be..8055849 100644
--- a/icc/SMPTE431_P3.icm
+++ b/icc/SMPTE431_P3.icm
Binary files differ
diff --git a/icc/SMPTE_RP145_NTSC.icm b/icc/SMPTE_RP145_NTSC.icm
index a6ce7f1..7fc78fb 100644
--- a/icc/SMPTE_RP145_NTSC.icm
+++ b/icc/SMPTE_RP145_NTSC.icm
Binary files differ
diff --git a/icc/icc.c b/icc/icc.c
index 7dfe519..87ce500 100644
--- a/icc/icc.c
+++ b/icc/icc.c
@@ -373,13 +373,13 @@ const char *format,
int rv;
va_list args;
icmFileMem *p = (icmFileMem *)pp;
- int len;
+ int alen, len;
va_start(args, format);
rv = 1;
- len = 100; /* Initial allocation for printf */
- icmFileMem_filemem_resize(p, p->cur + len);
+ alen = 100; /* Initial allocation for printf */
+ icmFileMem_filemem_resize(p, p->cur + alen);
/* We have to use the available printf functions to resize the buffer if needed. */
for (;rv != 0;) {
@@ -391,15 +391,15 @@ const char *format,
break;
if (len > -1) /* vsnprintf returned needed size-1 */
- len = len+2; /* (In case vsnprintf returned 1 less than it needs) */
+ alen = len+2; /* (In case vsnprintf returned 1 less than it needs) */
else
- len *= 2; /* We just have to guess */
+ alen *= 2; /* We just have to guess */
/* Attempt to resize */
- icmFileMem_filemem_resize(p, p->cur + len);
+ icmFileMem_filemem_resize(p, p->cur + alen);
/* If resize failed */
- if ((p->aend - p->cur) < len) {
+ if ((p->aend - p->cur) < alen) {
rv = 0;
break;
}
@@ -710,12 +710,17 @@ static int write_S15Fixed16Number(double d, char *p) {
return 0;
}
+/* Round a number to the same quantization as a S15Fixed16 */
static double round_S15Fixed16Number(double d) {
- d = floor(d * 65536.0 + 0.5); /* Beware! (int)(d + 0.5) doesn't work! */
+ d = floor(d * 65536.0 + 0.5); /* Beware! (int)(d + 0.5) doesn't work for -ve nummbets ! */
d = d/65536.0;
return d;
}
+/* Macro version */
+#define RND_S15FIXED16(xxx) ((xxx) > 0.0 ? (int)((xxx) * 65536.0 + 0.5)/65536.0 \
+ : (int)((xxx) * 65536.0 - 0.5)/65536.0)
+
/* Device coordinate as 8 bit value range 0.0 - 1.0 */
static double read_DCS8Number(char *p) {
unsigned int rv;
@@ -774,7 +779,6 @@ static void Lut_L2LutV2_16(double *out, double *in);
static void Lut_Lut2LV4_16(double *out, double *in);
static void Lut_L2LutV4_16(double *out, double *in);
-//~~~~888888
/* read a PCS number. PCS can be profile PCS, profile version Lab, */
/* or a specific type of Lab, depending on the value of csig: */
/* icmSigPCSData, icSigXYZData, icmSigLab8Data, icSigLabData, */
@@ -1397,6 +1401,8 @@ static const char *string_TagSignature(icTagSignature sig) {
return "BToA2 Multidimentional Transform";
case icSigCalibrationDateTimeTag:
return "Calibration Date & Time";
+ case icSigChromaticAdaptationTag:
+ return "Chromatic Adaptation";
case icSigCharTargetTag:
return "Characterization Target";
case icSigCopyrightTag:
@@ -1467,6 +1473,11 @@ static const char *string_TagSignature(icTagSignature sig) {
return "Viewing Condition Description";
case icSigViewingConditionsTag:
return "Viewing Condition Paramaters";
+
+ /* ArgyllCMS private tag: */
+ case icmSigAbsToRelTransSpace:
+ return "Absolute to Media Relative Transformation Space matrix";
+
default:
sprintf(buf,"Unrecognized - %s",tag2str(sig));
return buf;
@@ -3071,7 +3082,7 @@ static void icmU16Fixed16Array_dump(
if (verb >= 2) {
unsigned int i;
for (i = 0; i < p->size; i++)
- op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ op->gprintf(op," %lu: %.8f\n",i,p->data[i]);
}
}
@@ -3265,7 +3276,7 @@ static void icmS15Fixed16Array_dump(
if (verb >= 2) {
unsigned int i;
for (i = 0; i < p->size; i++)
- op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ op->gprintf(op," %lu: %.8f\n",i,p->data[i]);
}
}
@@ -3350,7 +3361,7 @@ static int read_XYZNumber(icmXYZNumber *p, char *d) {
static char *string_XYZNumber(icmXYZNumber *p) {
static char buf[40];
- sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z);
+ sprintf(buf,"%.8f, %.8f, %.8f", p->X, p->Y, p->Z);
return buf;
}
@@ -3363,7 +3374,7 @@ static char *string_XYZNumber_and_Lab(icmXYZNumber *p) {
lab[1] = p->Y;
lab[2] = p->Z;
icmXYZ2Lab(&icmD50, lab, lab);
- snprintf(buf,sizeof(buf),"%f, %f, %f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
+ snprintf(buf,sizeof(buf),"%.8f, %.8f, %.8f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
return buf;
}
@@ -3772,6 +3783,8 @@ static int icmTable_lookup_bwd(
/* Do a reverse lookup through the curve */
/* Return 0 on success, 1 if clipping occured, 2 on other error */
+/* (Note that clipping means mathematical clipping, and is not */
+/* set just because a device value is out of gamut. */
static int icmCurve_lookup_bwd(
icmCurve *p,
double *out,
@@ -3950,7 +3963,7 @@ static int icmCurve_write(
return icp->errc = 1;
}
if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) {
- sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]);
+ sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%.8f) failed",p->data[0]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -3962,7 +3975,7 @@ static int icmCurve_write(
}
for (i = 0; i < p->size; i++, bp += 2) {
if ((rv = write_DCS16Number(p->data[i],bp)) != 0) {
- sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]);
+ sprintf(icp->err,"icmCurve_write: write_UInt16umber(%.8f) failed",p->data[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -3995,13 +4008,13 @@ static void icmCurve_dump(
if (p->flag == icmCurveLin) {
op->gprintf(op," Curve is linear\n");
} else if (p->flag == icmCurveGamma) {
- op->gprintf(op," Curve is gamma of %f\n",p->data[0]);
+ op->gprintf(op," Curve is gamma of %.8f\n",p->data[0]);
} else {
op->gprintf(op," No. elements = %lu\n",p->size);
if (verb >= 2) {
unsigned int i;
for (i = 0; i < p->size; i++)
- op->gprintf(op," %3lu: %f\n",i,p->data[i]);
+ op->gprintf(op," %3lu: %.8f\n",i,p->data[i]);
}
}
}
@@ -4979,7 +4992,7 @@ double *in /* Input array[inputChan] */
return 0;
}
-/* Convert normalized numbers though this Luts input tables. */
+/* Convert normalized numbers though this Luts per channel input tables. */
/* Return 0 on success, 1 if clipping occured, 2 on other error */
static int icmLut_lookup_input(
icmLut *p, /* Pointer to Lut object */
@@ -5212,140 +5225,7 @@ double *in /* Input array[outputChan] */
return rv;
}
-#ifdef NEVER // ~~~99 development code
-
-/* Convert normalized numbers though this Luts multi-dimensional table */
-/* using optimised simplex interpolation. */
-/* This version optimses the simplex split axis depending on the input */
-/* colorspace. */
-static int icmLut_lookup_clut_osx(
-/* Return 0 on success, 1 if clipping occured, 2 on other error */
-icmLut *p, /* Pointer to Lut object */
-double *out, /* Output array[inputChan] */
-double *in /* Input array[outputChan] */
-) {
- int rv = 0;
- double *gp; /* Pointer to grid cube base */
- double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
- int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
- char xflip[MAX_CHAN]; /* Optimised simplex axis flip flags */
-
- /* Compute base index into grid and coordinate offsets */
- {
- unsigned int e;
- double clutPoints_1 = (double)(p->clutPoints-1);
- int clutPoints_2 = p->clutPoints-2;
- gp = p->clutTable; /* Base of grid array */
-
- for (e = 0; e < p->inputChan; e++) {
- unsigned int x;
- double val;
-// ~~~999
-#ifdef NEVER
- xflip[e] = p->finfo[e].bthff;
- if (in[e] >= p->finfo[e].fth)
- xflip[e] = p->finfo[e].athff;
-#else
-
- xflip[e] = 0;
- if (e == 0)
- xflip[e] = 1;
-#endif
- val = in[e] * clutPoints_1;
- if (val < 0.0) {
- val = 0.0;
- rv |= 1;
- } else if (val > clutPoints_1) {
- val = clutPoints_1;
- rv |= 1;
- }
- x = (unsigned int)floor(val); /* Grid coordinate */
- if (x > clutPoints_2)
- x = clutPoints_2;
- co[e] = val - (double)x; /* 1.0 - weight */
- gp += x * p->dinc[e]; /* Add index offset for base of cube */
- if (xflip[e]) { /* Reverse sense of direction for this axis */
- co[e] = 1.0 - co[e];
- gp += p->dinc[e];
- }
- }
- }
-//printf("*");fflush(stdout);
-#ifdef NEVER
- /* Do selection sort on coordinates, smallest to largest. */
- {
- int e, f;
- for (e = 0; e < p->inputChan; e++)
- si[e] = e; /* Initial unsorted indexes */
- for (e = 0; e < (p->inputChan-1); e++) {
- double cosn;
- cosn = co[si[e]]; /* Current smallest value */
- for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
- int tt;
- tt = si[f];
- if (cosn > co[tt]) {
- si[f] = si[e]; /* Exchange */
- si[e] = tt;
- cosn = co[tt];
- }
- }
- }
- }
-#else
- /* Do insertion sort on coordinates, smallest to largest. */
- {
- int f, vf;
- unsigned int e;
- double v;
- for (e = 0; e < p->inputChan; e++)
- si[e] = e; /* Initial unsorted indexes */
-
- for (e = 1; e < p->inputChan; e++) {
- f = e;
- v = co[si[f]];
- vf = f;
- while (f > 0 && co[si[f-1]] > v) {
- si[f] = si[f-1];
- f--;
- }
- si[f] = vf;
- }
- }
-#endif
- /* Now compute the weightings, simplex vertices and output values */
- {
- unsigned int e, f;
- double w; /* Current vertex weight */
-
- w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
- for (f = 0; f < p->outputChan; f++)
- out[f] = w * gp[f];
-
- for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
- w = co[si[e]] - co[si[e-1]];
- if (xflip[e])
- gp -= p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
- else
- gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
- for (f = 0; f < p->outputChan; f++)
- out[f] += w * gp[f];
- }
-
- w = co[si[0]];
- if (xflip[0])
- gp -= p->dinc[si[0]]; /* Far corner from base of cell */
- else
- gp += p->dinc[si[0]]; /* Far corner from base of cell */
- for (f = 0; f < p->outputChan; f++)
- out[f] += w * gp[f];
- }
- return rv;
-}
-
-#endif /* NEVER */ // ~~~99 development code
-
-
-/* Convert normalized numbers though this Luts output tables. */
+/* Convert normalized numbers though this Luts per channel output tables. */
/* Return 0 on success, 1 if clipping occured, 2 on other error */
static int icmLut_lookup_output(
icmLut *p, /* Pointer to Lut object */
@@ -5509,7 +5389,6 @@ double *in /* Input array[outputChan] */
double *gp; /* Pointer to grid cube base */
double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
- double cout[MAX_CHAN]; /* Current output value */
/* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
/* This method is more appropriate for XYZ/RGB/CMYK input spaces, */
@@ -5562,6 +5441,7 @@ double *in /* Input array[outputChan] */
{
unsigned int e, f;
double w, ww = 0.0; /* Current vertex weight, sum of weights squared */
+ double cout[MAX_CHAN]; /* Current output value */
double *ogp = gp; /* Pointer to grid cube base */
w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
@@ -6461,8 +6341,8 @@ int icmSetMultiLutTables(
} /* Next pass */
} /* Next table */
- free(clutTable1);
- free(clutTable3);
+ icp->al->free(icp->al, clutTable1);
+ icp->al->free(icp->al, clutTable3);
}
/* Create the 1D output table entry values */
@@ -6815,7 +6695,7 @@ static int icmLut_write(
} else {
for (i = 0; i < size; i++, bp += 2) {
if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) {
- sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]);
+ sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%.8f) failed",p->inputTable[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -6835,7 +6715,7 @@ static int icmLut_write(
} else {
for (i = 0; i < size; i++, bp += 2) {
if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) {
- sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]);
+ sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%.8f) failed",p->clutTable[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -6855,7 +6735,7 @@ static int icmLut_write(
} else {
for (i = 0; i < size; i++, bp += 2) {
if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) {
- sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]);
+ sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%.8f) failed",p->outputTable[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -6893,9 +6773,9 @@ static void icmLut_dump(
op->gprintf(op," CLUT resolution = %u\n",p->clutPoints);
op->gprintf(op," Input Table entries = %u\n",p->inputEnt);
op->gprintf(op," Output Table entries = %u\n",p->outputEnt);
- op->gprintf(op," XYZ matrix = %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
- op->gprintf(op," %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
- op->gprintf(op," %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
+ op->gprintf(op," XYZ matrix = %.8f, %.8f, %.8f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
+ op->gprintf(op," %.8f, %.8f, %.8f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
+ op->gprintf(op," %.8f, %.8f, %.8f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
if (verb >= 2) {
unsigned int i, j, size;
@@ -7819,7 +7699,7 @@ static void icmNamedColor_dump(
if (p->ttype == icSigNamedColor2Type) {
switch(icp->header->pcs) {
case icSigXYZData:
- op->gprintf(op," XYZ = %f, %f, %f\n",
+ op->gprintf(op," XYZ = %.8f, %.8f, %.8f\n",
vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
break;
case icSigLabData:
@@ -7836,7 +7716,7 @@ static void icmNamedColor_dump(
for (n = 0; n < p->nDeviceCoords; n++) {
if (n > 0)
op->gprintf(op,", ");
- op->gprintf(op,"%f",vp->deviceCoords[n]);
+ op->gprintf(op,"%.8f",vp->deviceCoords[n]);
}
op->gprintf(op,"\n");
}
@@ -8188,7 +8068,7 @@ static void icmColorantTable_dump(
switch(pcs) {
case icSigXYZData:
- op->gprintf(op," XYZ = %f, %f, %f\n",
+ op->gprintf(op," XYZ = %.8f, %.8f, %.8f\n",
vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
break;
case icSigLabData:
@@ -8214,7 +8094,8 @@ static int icmColorantTable_allocate(
if (p->count != p->_count) {
unsigned int i;
if (ovr_mul(p->count, sizeof(icmColorantTableVal))) {
- sprintf(icp->err,"icmColorantTable_alloc: count overflow (%d of %lu bytes)",p->count,sizeof(icmColorantTableVal));
+ sprintf(icp->err,"icmColorantTable_alloc: count overflow (%d of %lu bytes)",
+ p->count,(unsigned long)sizeof(icmColorantTableVal));
return icp->errc = 1;
}
if (p->data != NULL)
@@ -9788,7 +9669,7 @@ static int icmUcrBg_write(
}
} else {
if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) {
- sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]);
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%.8f) failed",p->UCRcurve[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -9812,7 +9693,7 @@ static int icmUcrBg_write(
}
} else {
if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) {
- sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]);
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%.8f) failed",p->BGcurve[i]);
icp->al->free(icp->al, buf);
return icp->errc = rv;
}
@@ -10302,15 +10183,15 @@ static void icmVideoCardGamma_dump(
}
} else if (p->tagType == icmVideoCardGammaFormulaType) {
op->gprintf(op,"VideoCardGammaFormula:\n");
- op->gprintf(op," red gamma = %f\n", p->u.formula.redGamma);
- op->gprintf(op," red min = %f\n", p->u.formula.redMin);
- op->gprintf(op," red max = %f\n", p->u.formula.redMax);
- op->gprintf(op," green gamma = %f\n", p->u.formula.greenGamma);
- op->gprintf(op," green min = %f\n", p->u.formula.greenMin);
- op->gprintf(op," green max = %f\n", p->u.formula.greenMax);
- op->gprintf(op," blue gamma = %f\n", p->u.formula.blueGamma);
- op->gprintf(op," blue min = %f\n", p->u.formula.blueMin);
- op->gprintf(op," blue max = %f\n", p->u.formula.blueMax);
+ op->gprintf(op," red gamma = %.8f\n", p->u.formula.redGamma);
+ op->gprintf(op," red min = %.8f\n", p->u.formula.redMin);
+ op->gprintf(op," red max = %.8f\n", p->u.formula.redMax);
+ op->gprintf(op," green gamma = %.8f\n", p->u.formula.greenGamma);
+ op->gprintf(op," green min = %.8f\n", p->u.formula.greenMin);
+ op->gprintf(op," green max = %.8f\n", p->u.formula.greenMax);
+ op->gprintf(op," blue gamma = %.8f\n", p->u.formula.blueGamma);
+ op->gprintf(op," blue min = %.8f\n", p->u.formula.blueMin);
+ op->gprintf(op," blue max = %.8f\n", p->u.formula.blueMax);
} else {
op->gprintf(op," Unknown tag format\n");
}
@@ -11364,6 +11245,7 @@ static struct {
{icSigBToA1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
{icSigBToA2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
{icSigCalibrationDateTimeTag, {icSigDateTimeType,icMaxEnumType}},
+ {icSigChromaticAdaptationTag, {icSigS15Fixed16ArrayType,icMaxEnumType}},
{icSigCharTargetTag, {icSigTextType,icMaxEnumType}},
{icSigColorantTableTag, {icSigColorantTableType,icmSigAltColorantTableType,
icMaxEnumType}},
@@ -11403,6 +11285,9 @@ static struct {
{icSigVideoCardGammaTag, {icSigVideoCardGammaType,icMaxEnumType}},
{icSigViewingCondDescTag, {icSigTextDescriptionType,icMaxEnumType}},
{icSigViewingConditionsTag, {icSigViewingConditionsType,icMaxEnumType}},
+
+ {icmSigAbsToRelTransSpace, {icSigS15Fixed16ArrayType,icMaxEnumType}},
+
{icMaxEnumTag, {icMaxEnumType}}
};
@@ -11550,13 +11435,13 @@ static struct {
{icSigNamedColorClass, -200, icMaxEnumData, icMaxEnumData,
{icSigProfileDescriptionTag,
- icSigNamedColor2Tag,
+ icSigNamedColorTag, /* Not strictly V3.4 */
icSigMediaWhitePointTag,
icSigCopyrightTag, icMaxEnumTag}},
{icSigNamedColorClass, -100, icMaxEnumData, icMaxEnumData,
{icSigProfileDescriptionTag,
- icSigNamedColorTag, /* Not strictly V3.4 */
+ icSigNamedColor2Tag,
icSigMediaWhitePointTag,
icSigCopyrightTag, icMaxEnumTag}},
@@ -11652,7 +11537,7 @@ static int check_icc_legal(
for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) {
if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) { /* Not present! */
#ifdef NEVER
- printf("icc_check_legal: deviceClass %s is missing required tag %s", tag2str(sig), tag2str(tagchecktable[i].tags[j]));
+ printf("icc_check_legal: deviceClass %s is missing required tag %s\n", tag2str(sig), tag2str(tagchecktable[i].tags[j]));
#endif
if (tagchecktable[i].chans == -200
|| tagchecktable[i].chans == -dchans) { /* But can try next table */
@@ -11778,7 +11663,7 @@ static int icc_read_x(
|| p->data[i].size > (maxoff - minoff)
|| (p->data[i].offset + p->data[i].size) < p->data[i].offset /* Overflow */
|| (p->data[i].offset + p->data[i].size) > p->header->size) {
- sprintf(p->err,"icc_read: tag %d is out of range of the nominated file size",i);
+ sprintf(p->err,"icc_read: tag %d sig %s offset %d size %d is out of range of the nominated file size %d",i,tag2str(p->data[i].sig),p->data[i].offset,p->data[i].size,maxoff);
p->al->free(p->al, p->data);
p->data = NULL;
return p->errc = 1;
@@ -11799,6 +11684,82 @@ static int icc_read_x(
}
} /* p->count > 0 */
+ /* Check if there is an ArgyllCMS 'arts' tag, and setup the wpchtmx[][] matrix from it. */
+ {
+ icmS15Fixed16Array *artsTag;
+
+ if ((artsTag = (icmS15Fixed16Array *)p->read_tag(p, icmSigAbsToRelTransSpace)) != NULL
+ && artsTag->ttype == icSigS15Fixed16ArrayType
+ && artsTag->size >= 9) {
+
+ p->wpchtmx[0][0] = artsTag->data[0];
+ p->wpchtmx[0][1] = artsTag->data[1];
+ p->wpchtmx[0][2] = artsTag->data[2];
+ p->wpchtmx[1][0] = artsTag->data[3];
+ p->wpchtmx[1][1] = artsTag->data[4];
+ p->wpchtmx[1][2] = artsTag->data[5];
+ p->wpchtmx[2][0] = artsTag->data[6];
+ p->wpchtmx[2][1] = artsTag->data[7];
+ p->wpchtmx[2][2] = artsTag->data[8];
+
+ icmInverse3x3(p->iwpchtmx, p->wpchtmx);
+
+ p->useArts = 1; /* Save it if it was in profile */
+
+ } else {
+ /* If an ArgyllCMS created profile, or if it's a Display profile, */
+ /* use Bradford. This makes sRGB and AdobeRGB etc. work correctly */
+ /* for absolute colorimetic. Note that for display profiles that set */
+ /* the WP to D50 and store their chromatic transform in the 'chad' tag, */
+ /* (i.e. some V2 profiles and all V4 profiles) this will have no effect */
+ /* on the Media Relative WP Transformation since D50 -> D50, and */
+ /* the 'chad' tag will be used to set the internal MediaWhite value */
+ /* and transform matrix. */
+ if (p->header->creator == str2tag("argl")
+ || p->header->deviceClass == icSigDisplayClass) {
+
+ icmCpy3x3(p->wpchtmx, icmBradford);
+ icmInverse3x3(p->iwpchtmx, p->wpchtmx);
+
+ /* Default to ICC standard Wrong Von Kries */
+ /* for non-ArgyllCMS, non-Display profiles. */
+ } else {
+ icmCpy3x3(p->wpchtmx, icmWrongVonKries);
+ icmCpy3x3(p->iwpchtmx, icmWrongVonKries);
+ }
+
+ p->useArts = 0; /* Don't save it if it wasn't in profile */
+ }
+
+ p->autoWpchtmx = 0; /* It's been set on reading - don't set automatically */
+ }
+
+ /* If this is a Display profile, check if there is a 'chad' tag, and read it */
+ /* in if it exists. We will use this latter. */
+ {
+ icmS15Fixed16Array *chadTag;
+
+ if (p->header->deviceClass == icSigDisplayClass
+ && (chadTag = (icmS15Fixed16Array *)p->read_tag(p, icSigChromaticAdaptationTag)) != NULL
+ && chadTag->ttype == icSigS15Fixed16ArrayType
+ && chadTag->size == 9) {
+
+ p->chadmx[0][0] = chadTag->data[0];
+ p->chadmx[0][1] = chadTag->data[1];
+ p->chadmx[0][2] = chadTag->data[2];
+ p->chadmx[1][0] = chadTag->data[3];
+ p->chadmx[1][1] = chadTag->data[4];
+ p->chadmx[1][2] = chadTag->data[5];
+ p->chadmx[2][0] = chadTag->data[6];
+ p->chadmx[2][1] = chadTag->data[7];
+ p->chadmx[2][2] = chadTag->data[8];
+
+ p->chadValid = 1;
+
+ p->useChad = 1; /* Use it when writing */
+ }
+ }
+
return er;
}
@@ -11946,6 +11907,8 @@ static unsigned int icc_get_size(
return size; /* Total size needed, or UINT_MAX if overflow */
}
+void quantize3x3S15Fixed16(double targ[3], double mat[3][3], double in[3]);
+
/* Write the contents of the object. Return 0 on sucess, error code on failure */
/* NOTE: fp ownership is taken even if the function fails. */
static int icc_write_x(
@@ -11965,19 +11928,121 @@ static int icc_write_x(
p->del_fp = 1;
p->of = of; /* Offset of ICC profile */
- for (i = 0; i < ALIGN_SIZE; i++)
- pbuf[i] = 0;
+ /* Compute the total size and tag element data offsets */
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_write: No header defined");
+ return p->errc = 1;
+ }
+
+ /* If we're using the ArgyllCMS 'arts' tag to record the chromatic */
+ /* adapation cone matrix used for the Media Relative WP Transformation, */
+ /* create it and set it from the wpchtmx[][] matrix. */
+ /* Don't write it if there is to 'wtpt' tag (i.e. it's a device link) */
+ if (p->useArts
+ && p->find_tag(p, icSigMediaWhitePointTag) == 0) {
+ icmS15Fixed16Array *artsTag;
+
+ /* Make sure no 'arts' tag currently exists */
+ if (p->delete_tag(p, icmSigAbsToRelTransSpace) != 0
+ && p->errc != 2) {
+ sprintf(p->err,"icc_write: Deleting existing 'arts' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Add one */
+ if ((artsTag = (icmS15Fixed16Array *)p->add_tag(p, icmSigAbsToRelTransSpace,
+ icSigS15Fixed16ArrayType)) == NULL) {
+ sprintf(p->err,"icc_write: Adding 'arts' tag failed");
+ return p->errc = 1;
+ }
+ artsTag->size = 9;
+ if ((rv = artsTag->allocate((icmBase *)artsTag) ) != 0) {
+ sprintf(p->err,"icc_write: Allocating 'arts' tag failed");
+ return p->errc = 1;
+ }
+
+ /* The cone matrix is assumed to be arranged conventionaly for matrix */
+ /* times vector multiplication. */
+ /* Consistent with ICC usage, the dimension corresponding to the matrix */
+ /* rows varies least rapidly while the one corresponding to the matrix */
+ /* columns varies most rapidly. */
+ artsTag->data[0] = p->wpchtmx[0][0];
+ artsTag->data[1] = p->wpchtmx[0][1];
+ artsTag->data[2] = p->wpchtmx[0][2];
+ artsTag->data[3] = p->wpchtmx[1][0];
+ artsTag->data[4] = p->wpchtmx[1][1];
+ artsTag->data[5] = p->wpchtmx[1][2];
+ artsTag->data[6] = p->wpchtmx[2][0];
+ artsTag->data[7] = p->wpchtmx[2][1];
+ artsTag->data[8] = p->wpchtmx[2][2];
+ }
+
+ /* If this is a Display profile, and we have been told to save it in */
+ /* ICCV4 style, then set the media white point tag to D50 and save */
+ /* the chromatic adapation matrix to the 'chad' tag. */
+ {
+ icmXYZArray *whitePointTag;
+ icmS15Fixed16Array *chadTag;
+
+ if (p->header->deviceClass == icSigDisplayClass
+ && p->useChad
+ && (whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType
+ && whitePointTag->size >= 1) {
+
+ /* If we've set this profile, not just read it, */
+ /* compute the fromAbs/chad matrix from media white point and cone matrix */
+ if (!p->chadValid) {
+ double wp[3];
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, icmD50, whitePointTag->data[0], p->chadmx);
+
+ /* Optimally quantize chad matrix to preserver white point */
+ icmXYZ2Ary(wp, whitePointTag->data[0]);
+ quantize3x3S15Fixed16(icmD50_ary3, p->chadmx, wp);
+ }
+
+ /* Make sure no 'chad' tag currently exists */
+ if (p->delete_tag(p, icSigChromaticAdaptationTag) != 0
+ && p->errc != 2) {
+ sprintf(p->err,"icc_write: Deleting existing 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Add one */
+ if ((chadTag = (icmS15Fixed16Array *)p->add_tag(p, icSigChromaticAdaptationTag,
+ icSigS15Fixed16ArrayType)) == NULL) {
+ sprintf(p->err,"icc_write: Adding 'chad' tag failed");
+ return p->errc = 1;
+ }
+ chadTag->size = 9;
+ if ((rv = chadTag->allocate((icmBase *)chadTag) ) != 0) {
+ sprintf(p->err,"icc_write: Allocating 'chad' tag failed");
+ return p->errc = 1;
+ }
+
+ /* Save in ICC matrix order */
+ chadTag->data[0] = p->chadmx[0][0];
+ chadTag->data[1] = p->chadmx[0][1];
+ chadTag->data[2] = p->chadmx[0][2];
+ chadTag->data[3] = p->chadmx[1][0];
+ chadTag->data[4] = p->chadmx[1][1];
+ chadTag->data[5] = p->chadmx[1][2];
+ chadTag->data[6] = p->chadmx[2][0];
+ chadTag->data[7] = p->chadmx[2][1];
+ chadTag->data[8] = p->chadmx[2][2];
+
+ /* Set the media white point to D50 */
+ whitePointTag->data[0] = icmD50;
+ }
+ }
/* Check that the right tags etc. are present for a legal ICC profile */
if ((rv = check_icc_legal(p)) != 0) {
return rv;
}
- /* Compute the total size and tag element data offsets */
- if (p->header == NULL) {
- sprintf(p->err,"icc_write: No header defined");
- return p->errc = 1;
- }
+ for (i = 0; i < ALIGN_SIZE; i++)
+ pbuf[i] = 0;
size = sat_add(size, p->header->get_size(p->header));
/* Assume header is aligned */
@@ -12201,6 +12266,7 @@ static int icc_write(
/* Returns NULL if error - icc->errc will contain */
/* 2 on system error, */
/* 3 if unknown tag */
+/* 4 if duplicate tag */
/* NOTE: that we prevent tag duplication */
/* NOTE: to create a tag type icmSigUnknownType, set ttype to icmSigUnknownType, */
/* and set the actual tag type in icmSigUnknownType->uttype */
@@ -12250,7 +12316,7 @@ static icmBase *icc_add_tag(
for (j = 0; j < p->count; j++) {
if (p->data[j].sig == sig) {
sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
- p->errc = 1;
+ p->errc = 4;
return NULL;
}
}
@@ -12458,6 +12524,7 @@ static icmBase *icc_read_tag_ix(
if (typetable[j].ttype == icMaxEnumType) {
if (!alow_unk) {
+ sprintf(p->err,"icc_read_tag_ix: found unknown tag");
p->errc = 2;
return NULL;
}
@@ -12631,7 +12698,7 @@ static int icc_unread_tag(
/* Delete the tag, and free the underlying tag type, */
/* if this was the last reference to it. */
-/* Note this finds the first tag with a matching signature */
+/* Note this finds the first tag with a matching signature. */
/* Returns non-zero on error: */
/* tag not found - icc->errc will contain 2 */
static int icc_delete_tag_ix(
@@ -13108,11 +13175,11 @@ static struct {
ICC V2 Lab encoding should be used in all PCS encodings in
a icSigLut16Type or icSigNamedColor2Type tag, and can be used
- for Lab encoding in device spaces for these tags.
+ for device space Lab encoding for these tags.
ICC V4 Lab encoding should be used in all PCS encodings in
- all other situations, and can be used for Lab encoding in
- device spaces for all other situtaions.
+ all other situations, and can be used for device space Lab encoding
+ for all other situtaions.
[ Since the ICC spec. doesn't cover device spaces labeled as Lab,
these are ripe for mis-matches between different implementations.]
@@ -14426,40 +14493,59 @@ extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *
}
/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* NOTE :- that these values are for the 1931 standard observer */
+/* NOTE :- that these values are for the 1931 standard observer. */
+/* Since they are an arbitrary 4 decimal place accuracy, we round */
+/* them to be exactly the same as ICC header encoded values, */
+/* to avoid any slight discrepancy with PCS white from profiles. */
/* available D50 Illuminant */
icmXYZNumber icmD50 = { /* Profile illuminant - D50 */
- 0.9642, 1.0000, 0.8249
+ RND_S15FIXED16(0.9642),
+ RND_S15FIXED16(1.0000),
+ RND_S15FIXED16(0.8249)
};
icmXYZNumber icmD50_100 = { /* Profile illuminant - D50, scaled to 100 */
- 96.42, 100.00, 82.49
+ RND_S15FIXED16(0.9642) * 100.0,
+ RND_S15FIXED16(1.0000) * 100.0,
+ RND_S15FIXED16(0.8249) * 100.0
};
double icmD50_ary3[3] = { /* Profile illuminant - D50 */
- 0.9642, 1.0000, 0.8249
+ RND_S15FIXED16(0.9642),
+ RND_S15FIXED16(1.0000),
+ RND_S15FIXED16(0.8249)
};
double icmD50_100_ary3[3] = { /* Profile illuminant - D50, scaled to 100 */
- 96.42, 100.00, 82.49
+ RND_S15FIXED16(0.9642) * 100.0,
+ RND_S15FIXED16(1.0000) * 100.0,
+ RND_S15FIXED16(0.8249) * 100.0
};
/* available D65 Illuminant */
icmXYZNumber icmD65 = { /* Profile illuminant - D65 */
- 0.9505, 1.0000, 1.0890
+ RND_S15FIXED16(0.9505),
+ RND_S15FIXED16(1.0000),
+ RND_S15FIXED16(1.0890)
};
icmXYZNumber icmD65_100 = { /* Profile illuminant - D65, scaled to 100 */
- 95.05, 100.00, 108.90
+ RND_S15FIXED16(0.9505) * 100.0,
+ RND_S15FIXED16(1.0000) * 100.0,
+ RND_S15FIXED16(1.0890) * 100.0
};
double icmD65_ary3[3] = { /* Profile illuminant - D65 */
- 0.9505, 1.0000, 1.0890
+ RND_S15FIXED16(0.9505),
+ RND_S15FIXED16(1.0000),
+ RND_S15FIXED16(1.0890)
};
double icmD65_100_ary3[3] = { /* Profile illuminant - D65, scaled to 100 */
- 95.05, 100.00, 108.90
+ RND_S15FIXED16(0.9505) * 100.0,
+ RND_S15FIXED16(1.0000) * 100.0,
+ RND_S15FIXED16(1.0890) * 100.0
};
@@ -14468,6 +14554,20 @@ icmXYZNumber icmBlack = {
0.0000, 0.0000, 0.0000
};
+/* The Standard ("wrong Von-Kries") chromatic transform matrix */
+double icmWrongVonKries[3][3] = {
+ { 1.0000, 0.0000, 0.0000 },
+ { 0.0000, 1.0000, 0.0000 },
+ { 0.0000, 0.0000, 1.0000 }
+};
+
+/* The Bradford chromatic transform matrix */
+double icmBradford[3][3] = {
+ { RND_S15FIXED16( 0.8951), RND_S15FIXED16( 0.2664), RND_S15FIXED16(-0.1614) },
+ { RND_S15FIXED16(-0.7502), RND_S15FIXED16( 1.7135), RND_S15FIXED16( 0.0367) },
+ { RND_S15FIXED16( 0.0389), RND_S15FIXED16(-0.0685), RND_S15FIXED16( 1.0296) }
+};
+
/* Return the normal Delta E given two Lab values */
double icmLabDE(double *Lab0, double *Lab1) {
double rv = 0.0, tt;
@@ -14659,6 +14759,7 @@ double icmCIE2Ksq(double *Lab0, double *Lab1) {
L = 0.5 * (Lab0[0] + Lab1[0]);
C = 0.5 * (C1 + C2);
+
if (C1 < 1e-9 || C2 < 1e-9) {
h = h1 + h2;
} else {
@@ -14671,22 +14772,25 @@ double icmCIE2Ksq(double *Lab0, double *Lab1) {
}
h *= 0.5;
}
+
T = 1.0 - 0.17 * cos(DEG2RAD(h-30.0)) + 0.24 * cos(DEG2RAD(2.0 * h))
+ 0.32 * cos(DEG2RAD(3.0 * h + 6.0)) - 0.2 * cos(DEG2RAD(4.0 * h - 63.0));
- hh = (h - 275.0)/25.0;
- ddeg = 30.0 * exp(-hh * hh);
- C7 = pow(C,7.0);
- RC = 2.0 * sqrt(C7/(C7 + 6103515625.0));
L50sq = (L - 50.0) * (L - 50.0);
+
SL = 1.0 + (0.015 * L50sq)/sqrt(20.0 + L50sq);
SC = 1.0 + 0.045 * C;
SH = 1.0 + 0.015 * C * T;
- RT = -sin(DEG2RAD(2 * ddeg)) * RC;
dLsq = dL/SL;
dCsq = dC/SC;
dHsq = dH/SH;
+ hh = (h - 275.0)/25.0;
+ ddeg = 30.0 * exp(-hh * hh);
+ C7 = pow(C, 7.0);
+ RC = 2.0 * sqrt(C7/(C7 + 6103515625.0));
+ RT = -sin(DEG2RAD(2 * ddeg)) * RC;
+
RCH = RT * dCsq * dHsq;
dLsq *= dLsq;
@@ -14719,35 +14823,23 @@ ICCLIB_API double icmXYZCIE2K(icmXYZNumber *w, double *in0, double *in1) {
/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* Chromatic adaptation transform utility */
+/* Independent chromatic adaptation transform utility. */
/* Return a 3x3 chromatic adaptation matrix */
/* Use icmMulBy3x3(dst, mat, src) */
/* NOTE that to transform primaries they */
/* must be mat[XYZ][RGB] format! */
void icmChromAdaptMatrix(
- int flags, /* Use Bradford, Transform given matrix flags */
+ int flags, /* Use Bradford flag, Transform given matrix flag */
icmXYZNumber d_wp, /* Destination white point */
icmXYZNumber s_wp, /* Source white point */
double mat[3][3] /* Destination matrix */
) {
double dst[3], src[3]; /* Source & destination white points */
double vkmat[3][3]; /* Von Kries matrix */
-#ifdef NEVER
- static double bradford[3][3] = { /* Linear cone space matrix */
- { 1.0, 0.0, 0.0 },
- { 0.0, 1.0, 0.0 },
- { 0.0, 0.0, 1.0 }
- };
-#endif /* NEVER */
- static double bradford[3][3] = { /* Bradford cone space matrix */
- { 0.8951, 0.2664, -0.1614 },
- { -0.7502, 1.7135, 0.0367 },
- { 0.0389, -0.0685, 1.0296 }
- };
static int inited = 0; /* Compute inverse bradford once */
static double ibradford[3][3]; /* Inverse Bradford */
- /* Set initial matrix to unity */
+ /* Set initial matrix to unity if creating from scratch */
if (!(flags & ICM_CAM_MULMATRIX)) {
icmSetUnity3x3(mat);
}
@@ -14756,8 +14848,8 @@ void icmChromAdaptMatrix(
icmXYZ2Ary(dst, d_wp);
if (flags & ICM_CAM_BRADFORD) {
- icmMulBy3x3(src, bradford, src);
- icmMulBy3x3(dst, bradford, dst);
+ icmMulBy3x3(src, icmBradford, src);
+ icmMulBy3x3(dst, icmBradford, dst);
}
/* Setup the Von Kries white point adaptation matrix */
@@ -14770,7 +14862,7 @@ void icmChromAdaptMatrix(
/* Transform to Bradford space if requested */
if (flags & ICM_CAM_BRADFORD) {
- icmMul3x3(mat, bradford);
+ icmMul3x3(mat, icmBradford);
}
/* Apply chromatic adaptation */
@@ -14779,7 +14871,7 @@ void icmChromAdaptMatrix(
/* Transform from Bradford space */
if (flags & ICM_CAM_BRADFORD) {
if (inited == 0) {
- icmInverse3x3(ibradford, bradford);
+ icmInverse3x3(ibradford, icmBradford);
inited = 1;
}
icmMul3x3(mat, ibradford);
@@ -14788,68 +14880,237 @@ void icmChromAdaptMatrix(
/* We're done */
}
+/* Setup the wpchtmx appropriately for creating profile */
+static void icc_setup_wpchtmx(icc *p) {
+ int useBradford = 1; /* Default use Bradford */
+
+ if (!p->autoWpchtmx)
+ return; /* Reading profile has set wpchtmx[][] */
+
+ /* If we should use ICC standard Wrong Von Kries for white point chromatic adapation */
+ if (p->header->deviceClass == icSigOutputClass
+ && p->useLinWpchtmx) {
+ useBradford = 0;
+ }
+
+ if (useBradford) {
+ icmCpy3x3(p->wpchtmx, icmBradford);
+ icmInverse3x3(p->iwpchtmx, p->wpchtmx);
+ } else {
+ icmCpy3x3(p->wpchtmx, icmWrongVonKries);
+ icmCpy3x3(p->iwpchtmx, icmWrongVonKries);
+ }
+
+ /* This is set for this profile class now */
+ p->wpchtmx_class = p->header->deviceClass;
+}
+
+/* icc Chromatic adaptation transform utility using */
+/* the current Absolute to Media Relative Transformation Space wpchtmx. */
+/* Return a 3x3 chromatic adaptation matrix */
+/* Use icmMulBy3x3(dst, mat, src) */
+/* NOTE that to transform primaries they */
+/* must be mat[XYZ][RGB] format! */
+/* NOTE that this resets the chadValid flag (i.e. we assume that if */
+/* this method gets called, that we are discarding any 'chad' tag */
+/* and creating our own chromatic adapation) */
+static void icc_chromAdaptMatrix(
+ icc *p,
+ int flags, /* Transform given matrix flag */
+ icmXYZNumber d_wp, /* Destination white point */
+ icmXYZNumber s_wp, /* Source white point */
+ double mat[3][3] /* Destination matrix */
+) {
+ double dst[3], src[3]; /* Source & destination white points */
+ double vkmat[3][3]; /* Von Kries matrix */
+
+ if (p->header->deviceClass == icMaxEnumClass) {
+ fprintf(stderr,"icc_chromAdaptMatrix called with no deviceClass!\n");
+ }
+
+ /* See if the profile type has changed, re-evaluate wpchtmx */
+ if (p->wpchtmx_class != p->header->deviceClass) {
+ icc_setup_wpchtmx(p);
+ }
+
+ /* Set initial matrix to unity if creating from scratch */
+ if (!(flags & ICM_CAM_MULMATRIX)) {
+ icmSetUnity3x3(mat);
+ }
+
+ /* Take a copy of src/dst */
+ icmXYZ2Ary(src, s_wp);
+ icmXYZ2Ary(dst, d_wp);
+
+ /* Transform src/dst to cone space */
+ icmMulBy3x3(src, p->wpchtmx, src);
+ icmMulBy3x3(dst, p->wpchtmx, dst);
+
+ /* Transform incoming matrix cone space */
+ icmMul3x3(mat, p->wpchtmx);
+
+ /* Setup the Von Kries white point adaptation matrix */
+ vkmat[0][0] = dst[0]/src[0];
+ vkmat[1][1] = dst[1]/src[1];
+ vkmat[2][2] = dst[2]/src[2];
+ vkmat[0][1] = vkmat[0][2] = 0.0;
+ vkmat[1][0] = vkmat[1][2] = 0.0;
+ vkmat[2][0] = vkmat[2][1] = 0.0;
+
+ /* Apply chromatic adaptation */
+ icmMul3x3(mat, vkmat);
+
+ /* Transform from con space */
+ icmMul3x3(mat, p->iwpchtmx);
+
+ p->chadValid = 0; /* Don't use this now */
+
+ /* We're done */
+}
+
/* - - - - - - - - - - - - - - - - - - - - - - - - */
-/* RGB primaries device to RGB->XYZ transform matrix. */
+/* RGB XYZ primaries device to RGB->XYZ transform matrix. */
/* We assume that the device is perfectly additive, but that */
/* there may be a scale factor applied to the channels to */
/* match the white point at RGB = 1. */
-
+/* Use icmMulBy3x3(dst, mat, src) */
/* Return non-zero if matrix would be singular */
-int icmRGBprim2matrix(
- icmXYZNumber white, /* White point */
- icmXYZNumber red, /* Red colorant */
- icmXYZNumber green, /* Green colorant */
- icmXYZNumber blue, /* Blue colorant */
- double mat[3][3] /* Destination matrix[RGB][XYZ] */
+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] */
) {
double tmat[3][3];
double t[3];
/* Assemble the colorants into a matrix */
- tmat[0][0] = red.X;
- tmat[0][1] = green.X;
- tmat[0][2] = blue.X;
- tmat[1][0] = red.Y;
- tmat[1][1] = green.Y;
- tmat[1][2] = blue.Y;
- tmat[2][0] = red.Z;
- tmat[2][1] = green.Z;
- tmat[2][2] = blue.Z;
+ tmat[0][0] = red[0];
+ tmat[0][1] = green[0];
+ tmat[0][2] = blue[0];
+ tmat[1][0] = red[1];
+ tmat[1][1] = green[1];
+ tmat[1][2] = blue[1];
+ tmat[2][0] = red[2];
+ tmat[2][1] = green[2];
+ tmat[2][2] = blue[2];
/* Compute the inverse */
if (icmInverse3x3(mat, tmat))
return 1;
/* Compute scale vector that maps colorants to white point */
- t[0] = mat[0][0] * white.X
- + mat[0][1] * white.Y
- + mat[0][2] * white.Z;
- t[1] = mat[1][0] * white.X
- + mat[1][1] * white.Y
- + mat[1][2] * white.Z;
- t[2] = mat[2][0] * white.X
- + mat[2][1] * white.Y
- + mat[2][2] * white.Z;
+ t[0] = mat[0][0] * white[0]
+ + mat[0][1] * white[1]
+ + mat[0][2] * white[2];
+ t[1] = mat[1][0] * white[0]
+ + mat[1][1] * white[1]
+ + mat[1][2] * white[2];
+ t[2] = mat[2][0] * white[0]
+ + mat[2][1] * white[1]
+ + mat[2][2] * white[2];
/* Now formulate the transform matrix */
- mat[0][0] = red.X * t[0];
- mat[1][0] = green.X * t[1];
- mat[2][0] = blue.X * t[2];
- mat[0][1] = red.Y * t[0];
- mat[1][1] = green.Y * t[1];
- mat[2][1] = blue.Y * t[2];
- mat[0][2] = red.Z * t[0];
- mat[1][2] = green.Z * t[1];
- mat[2][2] = blue.Z * t[2];
+ mat[0][0] = red[0] * t[0];
+ mat[0][1] = green[0] * t[1];
+ mat[0][2] = blue[0] * t[2];
+ mat[1][0] = red[1] * t[0];
+ mat[1][1] = green[1] * t[1];
+ mat[1][2] = blue[1] * t[2];
+ mat[2][0] = red[2] * t[0];
+ mat[2][1] = green[2] * t[1];
+ mat[2][2] = blue[2] * t[2];
return 0;
}
+/* 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 */
+) {
+ double r[3], g[3], b[3];
+
+ icmYxy2XYZ(r, red);
+ icmYxy2XYZ(g, green);
+ icmYxy2XYZ(b, blue);
+ icmYxy2XYZ(wXYZ, white);
+
+ return icmRGBXYZprim2matrix(r, g, b, wXYZ, mat);
+}
+
/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* 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 quantize3x3S15Fixed16(
+ 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! */
+) {
+ int i, j;
+ double sum[3]; /* == target */
+ double tmp[3]; /* Uncorrected sum */
+
+ printf("In = %.8f %.8f %.8f\n",in[0], in[1], in[2]);
+ printf("Target = %.8f %.8f %.8f\n",targ[0], targ[1], targ[2]);
+
+ for (j = 0; j < 3; j++)
+ sum[j] = targ[j];
+
+ /* Pre-quantize the matrix, and then ensure that the */
+ /* sum of the product of the quantized values is the quantized */
+ /* sum by assigning the rounding error to the largest component. */
+ for (i = 0; i < 3; i++) {
+ int bix = 0;
+ double bval = -1e9;
+
+ /* locate the largest and quantize each matrix component */
+ for (j = 0; j < 3; j++) {
+ if (fabs(mat[i][j]) > bval) { /* Locate largest */
+ bix = j;
+ bval = fabs(mat[i][j]);
+ }
+ mat[i][j] = round_S15Fixed16Number(mat[i][j]);
+ }
+
+ /* Check the product of the uncorrected quantized values */
+ tmp[i] = 0.0;
+ for (j = 0; j < 3; j++)
+ tmp[i] += mat[i][j] * in[j];
+
+ /* Compute the value the largest has to be */
+ /* to ensure that sum of the quantized mat[][] times in[] is */
+ /* equal to the quantized sum. */
+ for (j = 0; j < 3; j++) {
+ if (j == bix)
+ continue;
+ sum[i] -= mat[i][j] * in[j];
+ }
+ mat[i][bix] = round_S15Fixed16Number(sum[i]/in[i]);
+
+ /* Check the product of the corrected quantized values */
+ sum[i] = 0.0;
+ for (j = 0; j < 3; j++)
+ sum[i] += mat[i][j] * in[j];
+ }
+ printf("Q Sum = %.8f %.8f %.8f\n",tmp[0], tmp[1], tmp[2]);
+ printf("Q cor Sum = %.8f %.8f %.8f\n",sum[0], sum[1], sum[2]);
+}
+
/* Pre-round RGB device primary values to ensure that */
/* the sum of the quantized primaries is the same as */
/* the quantized sum. */
+/* [Note matrix is transposed compared to quantize3x3S15Fixed16() ] */
void quantizeRGBprimsS15Fixed16(
double mat[3][3] /* matrix[RGB][XYZ] */
) {
@@ -14897,7 +15158,7 @@ void quantizeRGBprimsS15Fixed16(
// for (j = 0; j < 3; j++)
// sum[i] += mat[j][i];
}
-// printf("Q Sum = %f %f %f\n",sum[0], sum[1], sum[2]);
+// printf("Q cor Sum = %f %f %f\n",sum[0], sum[1], sum[2]);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -15062,19 +15323,20 @@ 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 */
+/* (This is for digital Rec709 and is very close to analog Rec709 60Hz.) */
/* [From the Rec709 specification] */
void icmRec709_RGBd_2_YPbPr(double out[3], double in[3]) {
double tt[3];
tt[0] = 0.2126 * in[0] + 0.7152 * in[1] + 0.0722 * in[2];
- tt[1] = 0.5389 * -0.2126 * in[0]
- + 0.5389 * -0.7152 * in[1]
- + 0.5389 * (1.0-0.0722) * in[2];
+ tt[1] = 1.0/1.8556 * -0.2126 * in[0]
+ + 1.0/1.8556 * -0.7152 * in[1]
+ + 1.0/1.8556 * (1.0-0.0722) * in[2];
- tt[2] = 0.6350 * (1.0-0.2126) * in[0]
- + 0.6350 * -0.7152 * in[1]
- + 0.6350 * -0.0722 * in[2];
+ tt[2] = 1.0/1.5748 * (1.0-0.2126) * in[0]
+ + 1.0/1.5748 * -0.7152 * in[1]
+ + 1.0/1.5748 * -0.0722 * in[2];
out[0] = tt[0];
out[1] = tt[1];
@@ -15083,13 +15345,14 @@ 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 */
+/* (This is for digital Rec709 and is very close to analog Rec709 60Hz.) */
/* [Inverse of above] */
void icmRec709_YPbPr_2_RGBd(double out[3], double in[3]) {
double tt[3];
- tt[0] = 1.000000000 * in[0] + 0.000000000 * in[1] + 1.574803150 * in[2];
- tt[1] = 1.000000000 * in[0] + -0.187327487 * in[1] + -0.468125209 * in[2];
- tt[2] = 1.000000000 * in[0] + 1.855631843 * in[1] + 0.000000000 * in[2];
+ tt[0] = 1.000000000 * in[0] + 0.000000000 * in[1] + 1.574800000 * in[2];
+ tt[1] = 1.000000000 * in[0] + -0.187324273 * in[1] + -0.468124273 * in[2];
+ tt[2] = 1.000000000 * in[0] + 1.855600000 * in[1] + 0.000000000 * in[2];
out[0] = tt[0];
out[1] = tt[1];
@@ -15098,19 +15361,20 @@ 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 */
+/* (This is for analog Rec709 50Hz) */
/* [From the Rec709 specification] */
void icmRec709_50_RGBd_2_YPbPr(double out[3], double in[3]) {
double tt[3];
tt[0] = 0.299 * in[0] + 0.587 * in[1] + 0.114 * in[2];
- tt[1] = 0.564 * -0.299 * in[0]
- + 0.564 * -0.587 * in[1]
+ tt[1] = 0.564 * -0.299 * in[0]
+ + 0.564 * -0.587 * in[1]
+ 0.564 * (1.0-0.114) * in[2];
tt[2] = 0.713 * (1.0-0.299) * in[0]
- + 0.713 * -0.587 * in[1]
- + 0.713 * -0.114 * in[2];
+ + 0.713 * -0.587 * in[1]
+ + 0.713 * -0.114 * in[2];
out[0] = tt[0];
out[1] = tt[1];
@@ -15119,6 +15383,7 @@ 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 */
+/* (This is for analog Rec709 50Hz) */
/* [Inverse of above] */
void icmRec709_50_YPbPr_2_RGBd(double out[3], double in[3]) {
double tt[3];
@@ -15141,13 +15406,13 @@ void icmRec2020_NCL_RGBd_2_YPbPr(double out[3], double in[3]) {
tt[0] = 0.2627 * in[0] + 0.6780 * in[1] + 0.0593 * in[2];
- tt[1] = 1/1.8814 * -0.2627 * in[0]
- + 1/1.8814 * -0.6780 * in[1]
+ tt[1] = 1/1.8814 * -0.2627 * in[0]
+ + 1/1.8814 * -0.6780 * in[1]
+ 1/1.8814 * (1.0-0.0593) * in[2];
tt[2] = 1/1.4746 * (1.0-0.2627) * in[0]
- + 1/1.4746 * -0.6780 * in[1]
- + 1/1.4746 * -0.0593 * in[2];
+ + 1/1.4746 * -0.6780 * in[1]
+ + 1/1.4746 * -0.0593 * in[2];
out[0] = tt[0];
out[1] = tt[1];
@@ -15913,12 +16178,44 @@ struct _icmLuBase *lup
lup->blackisassumed = 0; /* The black is from the tag */
}
- /* Create absolute <-> relative conversion matricies */
- icmChromAdaptMatrix(ICM_CAM_BRADFORD, lup->whitePoint, icmD50, lup->toAbs);
- icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, lup->whitePoint, lup->fromAbs);
- DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X, lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
- DBLLL(("toAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->toAbs[0][0], lup->toAbs[0][1], lup->toAbs[0][2], lup->toAbs[1][0], lup->toAbs[1][1], lup->toAbs[1][2], lup->toAbs[2][0], lup->toAbs[2][1], lup->toAbs[2][2]));
- DBLLL(("fromAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->fromAbs[0][0], lup->fromAbs[0][1], lup->fromAbs[0][2], lup->fromAbs[1][0], lup->fromAbs[1][1], lup->fromAbs[1][2], lup->fromAbs[2][0], lup->fromAbs[2][1], lup->fromAbs[2][2]));
+ /* If this is a Display profile, check if there is a 'chad' tag, and setup the */
+ /* white point and toAbs/fromAbs matricies from that, so as to implement an */
+ /* effective Absolute Colorimetric intent for such profiles. */
+ if (p->header->deviceClass == icSigDisplayClass
+ && p->chadValid) {
+ double wp[3];
+
+ icmCpy3x3(lup->fromAbs, p->chadmx);
+ icmInverse3x3(lup->toAbs, lup->fromAbs);
+
+ /* Compute absolute white point. We deliberately ignore what's in the white point tag */
+ /* and assume D50, since dealing with a non-D50 white point tag is contrary to ICCV4 */
+ /* and full of ambiguity (i.e. is it a separate "media" white different to the */
+ /* display white and not D50, or has the profile creator mistakenly put the display */
+ /* white in the white point tag ?) */
+ icmMulBy3x3(wp, lup->toAbs, icmD50_ary3);
+ icmAry2XYZ(lup->whitePoint, wp);
+
+ DBLLL(("toAbs and fromAbs created from 'chad' tag\n"));
+ DBLLL(("computed wp %.8f %.8f %.8f\n", lup->whitePoint.X,
+ lup->whitePoint.Y, lup->whitePoint.Z));
+
+ } else {
+ /* Create absolute <-> relative conversion matricies */
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, lup->whitePoint, icmD50, lup->toAbs);
+ p->chromAdaptMatrix(p, ICM_CAM_NONE, icmD50, lup->whitePoint, lup->fromAbs);
+ DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X,
+ lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
+ }
+
+ DBLLL(("toAbs = %f %f %f\n %f %f %f\n %f %f %f\n",
+ lup->toAbs[0][0], lup->toAbs[0][1], lup->toAbs[0][2],
+ lup->toAbs[1][0], lup->toAbs[1][1], lup->toAbs[1][2],
+ lup->toAbs[2][0], lup->toAbs[2][1], lup->toAbs[2][2]));
+ DBLLL(("fromAbs = %f %f %f\n %f %f %f\n %f %f %f\n",
+ lup->fromAbs[0][0], lup->fromAbs[0][1], lup->fromAbs[0][2],
+ lup->fromAbs[1][0], lup->fromAbs[1][1], lup->fromAbs[1][2],
+ lup->fromAbs[2][0], lup->fromAbs[2][1], lup->fromAbs[2][2]));
return 0;
}
@@ -16925,6 +17222,8 @@ static int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) {
/* If Bwd Lut, take care of Absolute color space and effective input space */
if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->e_inSpace == icSigLabData
+ || p->e_inSpace == icSigXYZData)
&& (p->intent == icAbsoluteColorimetric
|| p->intent == icmAbsolutePerceptual
|| p->intent == icmAbsoluteSaturation)) {
@@ -17022,6 +17321,8 @@ static int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) {
/* If Fwd Lut, take care of Absolute color space */
/* and convert from native to effective out PCS */
if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->outSpace == icSigLabData
+ || p->outSpace == icSigXYZData)
&& (p->intent == icAbsoluteColorimetric
|| p->intent == icmAbsolutePerceptual
|| p->intent == icmAbsoluteSaturation)) {
@@ -17253,6 +17554,8 @@ static int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) {
/* and convert from effective to native inverse output PCS */
/* OutSpace must be PCS: XYZ or Lab */
if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->e_outSpace == icSigLabData
+ || p->e_outSpace == icSigXYZData)
&& (p->intent == icAbsoluteColorimetric
|| p->intent == icmAbsolutePerceptual
|| p->intent == icmAbsoluteSaturation)) {
@@ -17385,6 +17688,8 @@ static int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) {
/* If Bwd Lut, take care of Absolute color space, and */
/* convert from native to effective input space */
if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->inSpace == icSigLabData
+ || p->inSpace == icSigXYZData)
&& (p->intent == icAbsoluteColorimetric
|| p->intent == icmAbsolutePerceptual
|| p->intent == icmAbsoluteSaturation)) {
@@ -17667,9 +17972,6 @@ icc_new_icmLuLut(
return NULL;
}
-// ~~~999
-#ifndef NEVER
- /* Standard code */
/* Determine appropriate clut lookup algorithm */
{
int use_sx; /* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */
@@ -17795,64 +18097,6 @@ icc_new_icmLuLut(
p->lut->tune_value = icmLut_tune_value_nl;
}
}
-#else /* Development code */
- /* Determine appropriate clut lookup algorithm, */
- /* and set optimised simplex tables */
- {
- int lualg = 0; /* 0 = simplex, 1 = multi-linear, 2 = optimised simlpex */
- icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
- int inn, outn; /* in and out number of Lut components */
-
- p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn, NULL);
-
- /* Determine which type of Lut lookup algorithm is likely to give */
- /* minimal interpolation errors. */
- /* To use the optimised simplex, we should ideally determine */
- /* the simplex cell orientation that makes the simplex split diagonal */
- /* always point towards the white or black points. */
- switch(ins) {
-
- case icSigXYZData: /* This seems to be appropriate ? */
- case icSigRgbData:
- case icSigGrayData:
- case icSigCmykData:
- case icSigCmyData:
- case icSigMch6Data:
- lualg = 0; /* Simplex interpolation is appropriate */
- break;
-
- case icSigLabData:
-// ~~~~9999 this isn't right! need to lookup Lab 50,0,0 through input curves then */
-/* quantize to clut nodes to figure threshold for axis flips */
- p->lut->finfo[0].fth = 0.5; p->lut->finfo[0].bthff = 0; p->lut->finfo[0].athff = 1;
- p->lut->finfo[1].fth = 0.5; p->lut->finfo[1].bthff = 1; p->lut->finfo[1].athff = 0;
- p->lut->finfo[2].fth = 0.5; p->lut->finfo[2].bthff = 1; p->lut->finfo[2].athff = 0;
- lualg = 2;
- break;
-
- /* !!! Should switch to optimised simplex for these too !!! */
- case icSigLuvData:
- case icSigYCbCrData:
- case icSigYxyData:
- case icSigHlsData:
- case icSigHsvData:
- lualg = 1; /* Multi-linear is best as a default for these ? */
- break;
-
- default:
- lualg = 0; /* Simplex is best if we known nothing. */
- break;
- }
-
- if (lualg == 2) {
- p->lookup_clut = icmLut_lookup_clut_osx;
- } else if (lualg == 1) {
- p->lookup_clut = p->lut->lookup_clut_nl;
- } else {
- p->lookup_clut = p->lut->lookup_clut_sx;
- }
- }
-#endif
return (icmLuBase *)p;
}
@@ -18591,6 +18835,7 @@ icmAlloc *al /* Memory allocator */
p->get_tac = icm_get_tac;
p->get_luobj = icc_get_luobj;
p->new_clutluobj = icc_new_icmLuLut;
+ p->chromAdaptMatrix = icc_chromAdaptMatrix;
#if defined(__IBMC__) && defined(_M_IX86)
_control87(EM_UNDERFLOW, EM_UNDERFLOW);
@@ -18609,10 +18854,10 @@ icmAlloc *al /* Memory allocator */
p->header->renderingIntent = icMaxEnumIntent; /* Rendering intent - must be set ! */
/* Values that should be set before writing */
- p->header->manufacturer = -1; /* Dev manufacturer - should be set ! */
- p->header->model = -1; /* Dev model number - should be set ! */
- p->header->attributes.l = 0; /* ICC Device attributes - should set ! */
- p->header->flags = 0; /* Embedding flags - should be set ! */
+ p->header->manufacturer = icmSigUnknownType;/* Dev manufacturer - should be set ! */
+ p->header->model = icmSigUnknownType; /* Dev model number - should be set ! */
+ p->header->attributes.l = 0; /* ICC Device attributes - should set ! */
+ p->header->flags = 0; /* Embedding flags - should be set ! */
/* Values that may be set before writing */
p->header->attributes.h = 0; /* Dev Device attributes - may be set ! */
@@ -18624,13 +18869,53 @@ icmAlloc *al /* Memory allocator */
p->header->minv = 2;
p->header->bfv = 0;
setcur_DateTimeNumber(&p->header->date);/* Creation Date */
+#ifdef NT
p->header->platform = icSigMicrosoft; /* Primary Platform */
+#endif
+#ifdef __APPLE__
+ p->header->platform = icSigMacintosh;
+#endif
+#if defined(UNIX) && !defined(__APPLE__)
+ p->header->platform = icmSig_nix;
+#endif
p->header->illuminant = icmD50; /* Profile illuminant - D50 */
/* Values that will be created automatically */
for (i = 0; i < 16; i++)
p->header->id[i] = 0;
+ p->autoWpchtmx = 1; /* Auto on create */
+
+ /* Should we use ICC standard Wrong Von Kries for */
+ /* white point chromatic adapation for output class ? */
+ if (getenv("ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP") != NULL)
+ p->useLinWpchtmx = 1; /* Use Wrong Von Kries */
+ else
+ p->useLinWpchtmx = 0; /* Use Bradford by default */
+ p->wpchtmx_class = icMaxEnumClass; /* Not set yet */
+
+ /* Default to saving ArgyllCMS private 'arts' tag (if appropriate type of */
+ /* profile) to make white point chromatic adapation explicit. */
+ p->useArts = 1;
+
+ /* Should we create a V4 style Display profile with D50 media white point */
+ /* tag and 'chad' tag ? */
+ if (getenv("ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD") != NULL)
+ p->useChad = 1; /* Mark Media WP as D50 and put absolute to relative */
+ /* transform matrix in 'chad' tag. */
+ else
+ p->useChad = 0; /* No by default - use Bradford and store real Media WP */
+
+ /* Set a default wpchtmx in case the profile being read or written */
+ /* doesn't use a white point (i.e., it's a device link) */
+ if (!p->useLinWpchtmx) {
+ icmCpy3x3(p->wpchtmx, icmBradford);
+ icmInverse3x3(p->iwpchtmx, p->wpchtmx);
+ } else {
+ icmCpy3x3(p->wpchtmx, icmWrongVonKries);
+ icmCpy3x3(p->iwpchtmx, icmWrongVonKries);
+ }
+
return p;
}
@@ -18677,7 +18962,7 @@ char *icmPdv(int di, double *p) {
for (e = 0; e < di; e++) {
if (e > 0)
*bp++ = ' ';
- sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
}
return buf[ix];
}
@@ -18700,7 +18985,7 @@ char *icmPfv(int di, float *p) {
for (e = 0; e < di; e++) {
if (e > 0)
*bp++ = ' ';
- sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
}
return buf[ix];
}
diff --git a/icc/icc.h b/icc/icc.h
index ba66581..8f90d26 100644
--- a/icc/icc.h
+++ b/icc/icc.h
@@ -30,8 +30,8 @@
/* Version of icclib release */
-#define ICCLIB_VERSION 0x020017
-#define ICCLIB_VERSION_STR "2.17"
+#define ICCLIB_VERSION 0x020020
+#define ICCLIB_VERSION_STR "2.20"
#undef ENABLE_V4 /* V4 is not fully implemented */
@@ -61,19 +61,22 @@
# define ICCLIB_API /* empty */
#endif
+#if UINT_MAX < 0xffffffff
+# error "icclib: integer size is too small, must be at least 32 bit"
+#endif
+
/* =========================================================== */
/* Platform specific primitive defines. */
/* This really needs checking for each different platform. */
/* Using C99 and MSC covers a lot of cases, */
/* and the fallback default is pretty reliable with modern compilers and machines. */
+/* Note that MSWin is LLP64 == 32 bit long, while OS X/Linux is LP64 == 64 bit long. */
+/* so long shouldn't really be used in any code.... */
+/* (duplicated in icc.h) */
-/* Note that the code assume that int is at least 32 bits, */
-/* and avoid using long as it is uncertain whether this is */
-/* the same size as an int or larger, opening the scope */
-/* for oveflow errors. */
-
-#if UINT_MAX < 0xffffffff
-# error "icclib: integer size is too small, must be at least 32 bit"
+/* Use __LP64__ as cross platform 64 bit pointer #define */
+#if !defined(__LP64__) && defined(_WIN64)
+# define __LP64__ 1
#endif
#ifndef ORD32 /* If not defined elsewhere */
@@ -93,13 +96,15 @@
#define PNTR intptr_t
-/* printf format precision specifier */
-#define PF64PREC "ll"
+#define PF64PREC "ll" /* printf format precision specifier */
+#define CF64PREC "LL" /* Constant precision specifier */
-/* Constant precision specifier */
-#define CF64PREC "LL"
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
#else /* !__STDC_VERSION__ */
+
#ifdef _MSC_VER
#define INR8 __int8 /* 8 bit signed */
@@ -115,16 +120,17 @@
#define vsnprintf _vsnprintf
-/* printf format precision specifier */
-#define PF64PREC "I64"
+#define PF64PREC "I64" /* printf format precision specifier */
+#define CF64PREC "LL" /* Constant precision specifier */
-/* Constant precision specifier */
-#define CF64PREC "LL"
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
#else /* !_MSC_VER */
/* The following works on a lot of modern systems, including */
-/* LP64 model 64 bit modes */
+/* LLP64 and LP64 models, but won't work with ILP64 which needs int32 */
#define INR8 signed char /* 8 bit signed */
#define INR16 signed short /* 16 bit signed */
@@ -134,19 +140,28 @@
#define ORD32 unsigned int /* 32 bit unsigned */
#ifdef __GNUC__
-#define INR64 long long /* 64 bit signed - not used in icclib */
-#define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
+# ifdef __LP64__ /* long long could be 128 bit */
+# define INR64 long /* 64 bit signed - not used in icclib */
+# define ORD64 unsigned long /* 64 bit unsigned - not used in icclib */
+# define PF64PREC "l" /* printf format precision specifier */
+# define CF64PREC "L" /* Constant precision specifier */
+# else
+# define INR64 long long /* 64 bit signed - not used in icclib */
+# define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
+# define PF64PREC "ll" /* printf format precision specifier */
+# define CF64PREC "LL" /* Constant precision specifier */
+# endif /* !__LP64__ */
+#endif /* __GNUC__ */
-/* printf format precision specifier */
-#define PF64PREC "ll"
+#define PNTR unsigned long
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
#endif
-#define PNTR unsigned long
-
#endif /* !_MSC_VER */
#endif /* !__STDC_VERSION__ */
-#endif /* !defined(ORD32) */
+#endif /* !ORD32 */
/* =========================================================== */
#include "iccV42.h" /* ICC Version 4.2 definitions. */
@@ -321,6 +336,15 @@ icmFile *new_icmFileMem_d(void *base, size_t length);
typedef int icmSig; /* Otherwise un-enumerated 4 byte signature */
+/* ArgyllCMS Private tagSignature: */
+/* Absolute to Media Relative Transformation Space matrix. */
+/* Uses the icSigS15Fixed16ArrayType */
+/* (Unit matrix for default ICC, Bradford matrix for Argll default) */
+#define icmSigAbsToRelTransSpace ((icTagSignature) icmMakeTag('a','r','t','s'))
+
+/* Non-standard Platform Signature for Linux and similiar */
+#define icmSig_nix ((icPlatformSignature) icmMakeTag('*','n','i','x'))
+
/* Non-standard Color Space Signatures - will be incompatible outside icclib! */
/* A monochrome CIE L* space */
@@ -353,10 +377,6 @@ typedef int icmSig; /* Otherwise un-enumerated 4 byte signature */
/* Pseudo PCS colospace to signal V4 16 bit L */
#define icmSigLV4Data ((icColorSpaceSignature) icmMakeTag('L',' ',' ','4'))
-/* Non-standard Platform Signature */
-#define icmSig_nix ((icPlatformSignature) icmMakeTag('*','n','i','x'))
-
-
/* Alias for icSigColorantTableType found in LOGO profiles (Byte swapped clrt !) */
#define icmSigAltColorantTableType ((icTagTypeSignature)icmMakeTag('t','r','l','c'))
@@ -1095,6 +1115,7 @@ struct _icmVideoCardGamma {
/* ------------------------------------------------- */
/* The Profile header */
+/* NOTE that the deviceClass should be set up before calling chromAdaptMatrix()! */
struct _icmHeader {
/* Private: */
@@ -1471,7 +1492,14 @@ struct _icc {
/* Returns 0 if deleted OK */
int (*check_id)(struct _icc *p, ORD8 *id); /* Returns 0 if ID is OK, 1 if not present etc. */
double (*get_tac)(struct _icc *p, double *chmax, /* Returns total ink limit and channel maximums */
- void (*calfunc)(void *cntx, double *out, double *in), void *cntx); /* optional cal. lookup */
+ void (*calfunc)(void *cntx, double *out, double *in), void *cntx);
+ /* optional cal. lookup */
+ void (*chromAdaptMatrix)(struct _icc *p, int flags, icmXYZNumber d_wp,
+ icmXYZNumber s_wp, double mat[3][3]);
+ /* Chromatic transform function that uses icc */
+ /* Absolute to Media Relative Transformation Space matrix */
+ /* Set header->deviceClass before calling this! */
+
/* Get a particular color conversion function */
icmLuBase * (*get_luobj) (struct _icc *p,
@@ -1503,6 +1531,26 @@ struct _icc {
int allowclutPoints256; /* Non standard - allow 256 res cLUT */
+ int autoWpchtmx; /* Whether to automatically set wpchtmx[][] based on */
+ /* the header and the state of the env override */
+ /* ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP. */
+ /* Default true, set false on reading a profile. */
+ int useLinWpchtmx; /* Force Wrong Von Kries for output class (default false) */
+ icProfileClassSignature wpchtmx_class; /* Class of profile wpchtmx was set for */
+ double wpchtmx[3][3]; /* Absolute to Media Relative Transformation Space matrix */
+ double iwpchtmx[3][3]; /* Inverse of wpchtmx[][] */
+ /* (Default is Bradford matrix) */
+ int useArts; /* Save ArgyllCMS private 'arts' tag (default yes) */
+ /* (This creates 'arts' tag on writing) */
+
+ int chadValid; /* nz if 'chad' tag has been read and chadmx is valid */
+ double chadmx[3][3]; /* 'chad' tag matrix if read */
+ int useChad; /* Create 'chad' tag for Display profile (default no) */
+ /* Override with ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD */
+ /* (This set media white point tag to D50 and */
+ /* creates 'chad' tag on writing) */
+
+
/* Private: ? */
icmAlloc *al; /* Heap allocator */
int del_al; /* NZ if heap allocator should be deleted */
@@ -1923,19 +1971,24 @@ extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *
/* 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 */
+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 */
+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];
/* 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[]);
@@ -1990,22 +2043,38 @@ int icmClipXYZ(double out[3], double in[3]);
/* - - - - - - - - - - - - - - - - - - - - - - - */
-/* RGB primaries to device to RGB->XYZ transform matrix */
+/* 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 */
-int icmRGBprim2matrix(
- icmXYZNumber white, /* White point */
- icmXYZNumber red, /* Red colorant */
- icmXYZNumber green, /* Green colorant */
- icmXYZNumber blue, /* Blue colorant */
- double mat[3][3] /* Destination matrix[RGB[XYZ] */
+/* 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] */
+#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 */
+#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! */
diff --git a/icc/iccstd.c b/icc/iccstd.c
index 742be4d..3f7966e 100644
--- a/icc/iccstd.c
+++ b/icc/iccstd.c
@@ -310,7 +310,6 @@ icmAlloc *al /* heap allocator, NULL for default */
) {
icmFileStd *p;
int del_al = 0;
- struct stat sbuf;
if (al == NULL) { /* None provided, create default */
if ((al = new_icmAllocStd()) == NULL)
@@ -334,8 +333,10 @@ icmAlloc *al /* heap allocator, NULL for default */
p->get_buf = icmFileStd_get_buf;
p->del = icmFileStd_delete;
- if (fstat(fileno(fp), &sbuf) == 0) {
- p->size = sbuf.st_size;
+ // fstat() is not so robust on MSWin.
+ if (fseek(fp, 0L, SEEK_END) == 0) {
+ p->size = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
} else {
p->size = 0;
}
diff --git a/icc/icctest.c b/icc/icctest.c
index e7534fb..f0b1280 100644
--- a/icc/icctest.c
+++ b/icc/icctest.c
@@ -160,7 +160,7 @@ main(
}
/*
- Would normally call icco->free(wr_icco);
+ Would normally call wr_icco->del(wr_icco);
but leave it, so that we can verify the read.
*/
diff --git a/icc/lab2lab.icm b/icc/lab2lab.icm
index 0b8a4b3..39a5911 100644
--- a/icc/lab2lab.icm
+++ b/icc/lab2lab.icm
Binary files differ
diff --git a/icc/log.txt b/icc/log.txt
index 7c4bd83..2e185dc 100644
--- a/icc/log.txt
+++ b/icc/log.txt
@@ -1,6 +1,18 @@
Change History: (See ArgyllCMS log.txt too)
+ 2.20
+ Add better cross compatibility with non-Argyll ICC profiles:
+ + Use "wrong Von Kries" media white point adapation for non-Argyll non-display profile
+ + Optionally create "wrong Von Kries" media white point adapation profiles
+ using the "ARGYLL_CREATE_WRONG_VON_KRIES_OUTPUT_CLASS_REL_WP" env. variable,
+ while maintaining ArgyllCMS compatibility using the 'arts' tag.
+ + Implement proper absolute colorimetric intent for ICCV2 Display profiles
+ that use the ICCV4 style of have a media white od D50 and storing the
+ media chromatic trasnform in the 'chad' tag.
+ + Optionally create such ICCV4 style V2 Display profiles by using the
+ "ARGYLL_CREATE_DISPLAY_PROFILE_WITH_CHAD" env. variable.
+
2.16
Clean up cLUT read code to make sanity checking
more explicit and remove redundant code.
diff --git a/icc/mcheck.c b/icc/mcheck.c
index 54811c3..a392f31 100644
--- a/icc/mcheck.c
+++ b/icc/mcheck.c
@@ -24,6 +24,7 @@
#include <fcntl.h>
#include <string.h>
#include <math.h>
+#include "vrml.h"
#include "icc.h"
void error(char *fmt, ...), warning(char *fmt, ...);
@@ -31,24 +32,18 @@ void error(char *fmt, ...), warning(char *fmt, ...);
void usage(void) {
fprintf(stderr,"Check device to PCS monotonicity of a CMYK ICC file, V%s\n",ICCLIB_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill\n");
- fprintf(stderr,"usage: kcheck [-v] [-w] infile\n");
+ fprintf(stderr,"usage: mcheck [-v] [-w] infile\n");
fprintf(stderr," -v verbose\n");
fprintf(stderr," -c Check just Cyan monotonicity\n");
fprintf(stderr," -m Check just Magenta monotonicity\n");
fprintf(stderr," -y Check just Yellow monotonicity\n");
fprintf(stderr," -k Check just Black monotonicity\n");
- fprintf(stderr," -w create VRML visualisation\n");
+ fprintf(stderr," -w create %s visualisation\n",vrml_format());
+ fprintf(stderr," -x use %s axes\n",vrml_format());
exit(1);
}
-#define MGR 50 /* Maximum grid resolution handled */
-
-
-FILE *start_vrml(char *name, int doaxes);
-void start_line_set(FILE *wrl);
-void add_vertex(FILE *wrl, double pp[3]);
-void make_lines(FILE *wrl, int ppset);
-void end_vrml(FILE *wrl);
+#define MGR 50 /* Maximum grid resolution handled */
int
main(
@@ -73,7 +68,7 @@ main(
icColorSpaceSignature ins, outs; /* Type of input and output spaces */
int inn; /* Number of input chanels */
icmLuAlgType alg;
- FILE *wrl;
+ vrml *wrl;
int dx[4]; /* Device index mapping */
int chan, cs, ce;
@@ -101,7 +96,7 @@ main(
if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
verb = 1;
}
- /* VRML */
+ /* VRML/X3D */
else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
dovrml = 1;
}
@@ -121,6 +116,9 @@ main(
else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
cchan = 3;
}
+ else if (argv[fa][1] == 'x') {
+ doaxes = 1;
+ }
else if (argv[fa][1] == '?')
usage();
else
@@ -136,7 +134,7 @@ main(
strcpy(out_name, in_name);
if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
xl = out_name + strlen(out_name);
- strcpy(xl,".wrl");
+ xl[0] = '\000'; /* Remove extension */
/* Open up the file for reading */
if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
@@ -177,8 +175,10 @@ main(
}
if (dovrml) {
- wrl = start_vrml(out_name, doaxes);
- start_line_set(wrl);
+ wrl = new_vrml(out_name, doaxes, vrml_lab);
+ if (wrl == NULL)
+ error("new_vrml for '%s%s' failed",out_name,vrml_ext());
+ wrl->start_line_set(wrl, 0);
}
/* For all the device chanels chosen */
@@ -237,7 +237,7 @@ main(
error ("%d, %s",rd_icco->errc,rd_icco->err);
// if (dovrml)
-// add_vertex(wrl, pcs[ck]);
+// wrl->add_vertex(wrl, 0, pcs[ck]);
}
/* Compute average vector direction */
@@ -276,7 +276,7 @@ main(
/* Display just the non mono threads */
if (nm && dovrml) {
for (j = 0; j < gres; j++)
- add_vertex(wrl, pcs[j]);
+ wrl->add_vertex(wrl, 0, pcs[j]);
}
if (verb) {
printf("."); fflush(stdout);
@@ -287,8 +287,8 @@ main(
}
if (dovrml) {
- make_lines(wrl, gres);
- end_vrml(wrl);
+ wrl->make_lines(wrl, 0, gres);
+ wrl->del(wrl);
}
/* Done with lookup object */
@@ -301,218 +301,6 @@ main(
}
/* ------------------------------------------------ */
-/* Some simple functions to do basix VRML work */
-
-#define GAMUT_LCENT 50.0
-static int npoints = 0;
-static int paloc = 0;
-static struct { double pp[3]; } *pary;
-
-static void Lab2RGB(double *out, double *in);
-
-FILE *start_vrml(char *name, int doaxes) {
- FILE *wrl;
- struct {
- double x, y, z;
- double wx, wy, wz;
- double r, g, b;
- } axes[5] = {
- { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
- { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
- { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
- { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
- { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
- };
- int i;
-
- if ((wrl = fopen(name,"w")) == NULL)
- error("Error opening VRML file '%s'\n",name);
-
- npoints = 0;
-
- fprintf(wrl,"#VRML V2.0 utf8\n");
- fprintf(wrl,"\n");
- fprintf(wrl,"# Created by the Argyll CMS\n");
- fprintf(wrl,"Transform {\n");
- fprintf(wrl,"children [\n");
- fprintf(wrl," NavigationInfo {\n");
- fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
- fprintf(wrl," } # We'll add our own light\n");
- fprintf(wrl,"\n");
- fprintf(wrl," DirectionalLight {\n");
- fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
- fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
- fprintf(wrl," }\n");
- fprintf(wrl,"\n");
- fprintf(wrl," Viewpoint {\n");
- fprintf(wrl," position 0 0 340 # Position we view from\n");
- fprintf(wrl," }\n");
- fprintf(wrl,"\n");
- if (doaxes != 0) {
- fprintf(wrl,"# Lab axes as boxes:\n");
- for (i = 0; i < 5; i++) {
- fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
- fprintf(wrl,"\tchildren [\n");
- fprintf(wrl,"\t\tShape{\n");
- fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
- axes[i].wx, axes[i].wy, axes[i].wz);
- fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
- fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
- fprintf(wrl,"\t\t}\n");
- fprintf(wrl,"\t]\n");
- fprintf(wrl,"}\n");
- }
- fprintf(wrl,"\n");
- }
-
- return wrl;
-}
-
-void
-start_line_set(FILE *wrl) {
-
- fprintf(wrl,"\n");
- fprintf(wrl,"Shape {\n");
- fprintf(wrl," geometry IndexedLineSet { \n");
- fprintf(wrl," coord Coordinate { \n");
- fprintf(wrl," point [\n");
-}
-
-void add_vertex(FILE *wrl, double pp[3]) {
-
- fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
-
- if (paloc < (npoints+1)) {
- paloc = (paloc + 10) * 2;
- if (pary == NULL)
- pary = malloc(paloc * 3 * sizeof(double));
- else
- pary = realloc(pary, paloc * 3 * sizeof(double));
-
- if (pary == NULL)
- error ("Malloc failed");
- }
- pary[npoints].pp[0] = pp[0];
- pary[npoints].pp[1] = pp[1];
- pary[npoints].pp[2] = pp[2];
- npoints++;
-}
-
-
-void make_lines(FILE *wrl, int ppset) {
- int i, j;
-
- fprintf(wrl," ]\n");
- fprintf(wrl," }\n");
- fprintf(wrl," coordIndex [\n");
-
- for (i = 0; i < npoints;) {
- for (j = 0; j < ppset; j++, i++) {
- fprintf(wrl,"%d, ", i);
- }
- fprintf(wrl,"-1,\n");
- }
- fprintf(wrl," ]\n");
-
- /* Color */
- fprintf(wrl," colorPerVertex TRUE\n");
- fprintf(wrl," color Color {\n");
- fprintf(wrl," color [ # RGB colors of each vertex\n");
-
- for (i = 0; i < npoints; i++) {
- double rgb[3], Lab[3];
- Lab[0] = pary[i].pp[0];
- Lab[1] = pary[i].pp[1];
- Lab[2] = pary[i].pp[2];
- Lab2RGB(rgb, Lab);
- fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
- }
- fprintf(wrl," ] \n");
- fprintf(wrl," }\n");
- /* End color */
-
- fprintf(wrl," }\n");
- fprintf(wrl,"} # end shape\n");
-
-}
-
-void end_vrml(FILE *wrl) {
-
- fprintf(wrl,"\n");
- fprintf(wrl," ] # end of children for world\n");
- fprintf(wrl,"}\n");
-
- if (fclose(wrl) != 0)
- error("Error closing VRML file\n");
-}
-
-
-/* Convert a gamut Lab value to an RGB value for display purposes */
-static void
-Lab2RGB(double *out, double *in) {
- double L = in[0], a = in[1], b = in[2];
- double x,y,z,fx,fy,fz;
- double R, G, B;
-
- /* Scale so that black is visible */
- L = L * (100 - 40.0)/100.0 + 40.0;
-
- /* First convert to XYZ using D50 white point */
- if (L > 8.0) {
- fy = (L + 16.0)/116.0;
- y = pow(fy,3.0);
- } else {
- y = L/903.2963058;
- fy = 7.787036979 * y + 16.0/116.0;
- }
-
- fx = a/500.0 + fy;
- if (fx > 24.0/116.0)
- x = pow(fx,3.0);
- else
- x = (fx - 16.0/116.0)/7.787036979;
-
- fz = fy - b/200.0;
- if (fz > 24.0/116.0)
- z = pow(fz,3.0);
- else
- z = (fz - 16.0/116.0)/7.787036979;
-
- x *= 0.9642; /* Multiply by white point, D50 */
- y *= 1.0;
- z *= 0.8249;
-
- /* Now convert to sRGB values */
- R = x * 3.2410 + y * -1.5374 + z * -0.4986;
- G = x * -0.9692 + y * 1.8760 + z * 0.0416;
- B = x * 0.0556 + y * -0.2040 + z * 1.0570;
-
- if (R < 0.0)
- R = 0.0;
- else if (R > 1.0)
- R = 1.0;
-
- if (G < 0.0)
- G = 0.0;
- else if (G > 1.0)
- G = 1.0;
-
- if (B < 0.0)
- B = 0.0;
- else if (B > 1.0)
- B = 1.0;
-
- R = pow(R, 1.0/2.2);
- G = pow(G, 1.0/2.2);
- B = pow(B, 1.0/2.2);
-
- out[0] = R;
- out[1] = G;
- out[2] = B;
-}
-
-
-/* ------------------------------------------------ */
/* Basic printf type error() and warning() routines */
void
diff --git a/icc/mkDispProf.c b/icc/mkDispProf.c
index bc70154..6878aad 100644
--- a/icc/mkDispProf.c
+++ b/icc/mkDispProf.c
@@ -176,7 +176,7 @@ char *argv[]
/* Setup the primaries */
{
/* Compute primaries as XYZ */
- icmXYZNumber wrgb[4] = { /* Primaries in Yxy from the standard */
+ double wrgb[4][3] = { /* Primaries in Yxy from the standard */
{ 1.0, 0.3127, 0.3290 }, /* White */
{ 1.0, 0.6400, 0.3300 }, /* Red */
{ 1.0, 0.3000, 0.6000 }, /* Green */
@@ -185,28 +185,49 @@ char *argv[]
double mat[3][3];
int i;
- /* Convert Yxy to XYZ */
- for (i = 0; i < 4; i++) {
- double v[3];
+ /* Convert yxy to normalised 3x3 matrix */
+ icmRGBYxyprim2matrix(wrgb[1], wrgb[2], wrgb[3], wrgb[0], mat, wrgb[0]);
+ icmTranspose3x3(mat, mat);
- icmXYZ2Ary(v, wrgb[i]);
- icmYxy2XYZ(v, v);
- icmAry2XYZ(wrgb[i], v);
- }
-
- /* Convert XYZ to normalised 3x3 matrix */
- icmRGBprim2matrix(wrgb[0], wrgb[1], wrgb[2], wrgb[3], mat);
-
-#ifdef NEVER /* Dump XYZ of matrix */
+#ifdef NEVER /* Dump XYZ */
printf("sRGB: XYZ\n");
- printf("{ %f, %f, %f }, /* Red */\n"
- "{ %f, %f, %f }, /* Green */\n"
- "{ %f, %f, %f }, /* Blue */\n"
+ printf("{ %f, %f, %f }, /* Red */\n"
+ "{ %f, %f, %f }, /* Green */\n"
+ "{ %f, %f, %f }, /* Blue */\n"
"{ %f, %f, %f } /* White */\n",
mat[0][0], mat[0][1], mat[0][2],
mat[1][0], mat[1][1], mat[1][2],
mat[2][0], mat[2][1], mat[2][2],
- wrgb[0].X, wrgb[0].Y, wrgb[0].Z);
+ wrgb[0][0], wrgb[0][1], wrgb[0][2]);
+#endif
+
+#ifdef NEVER /* Dump xyz */
+{
+ double mat2[4][3];
+ double tt;
+
+ for (i = 0; i < 3; i++) {
+
+ tt = mat[i][0] + mat[i][1] + mat[i][2];
+ mat2[i][0] = mat[i][0] / tt;
+ mat2[i][1] = mat[i][1] / tt;
+ mat2[i][2] = mat[i][2] / tt;
+ }
+ tt = wrgb[0][0] + wrgb[0][1] + wrgb[0][2];
+ mat2[i][0] = wrgb[0][0] / tt;
+ mat2[i][1] = wrgb[0][1] / tt;
+ mat2[i][2] = wrgb[0][2] / tt;
+
+ printf("sRGB: xyz\n");
+ printf("{ %f, %f, %f }, /* Red */\n"
+ "{ %f, %f, %f }, /* Green */\n"
+ "{ %f, %f, %f }, /* Blue */\n"
+ "{ %f, %f, %f } /* White */\n",
+ mat2[0][0], mat2[0][1], mat2[0][2],
+ mat2[1][0], mat2[1][1], mat2[1][2],
+ mat2[2][0], mat2[2][1], mat2[2][2],
+ mat2[3][0], mat2[3][1], mat2[3][2]);
+}
#endif
/* White Point Tag: */
@@ -219,9 +240,9 @@ char *argv[]
wo->size = 1;
wo->allocate((icmBase *)wo); /* Allocate space */
- wo->data[0].X = wrgb[0].X;
- wo->data[0].Y = wrgb[0].Y;
- wo->data[0].Z = wrgb[0].Z;
+ wo->data[0].X = wrgb[0][0];
+ wo->data[0].Y = wrgb[0][1];
+ wo->data[0].Z = wrgb[0][2];
}
/* Black Point Tag: */
{
@@ -239,12 +260,14 @@ char *argv[]
}
/* Red, Green and Blue Colorant Tags: */
{
+ icmXYZNumber white;
icmXYZArray *wor, *wog, *wob;
double fromAbs[3][3];
double d50m[3][3];
/* Convert to D50 adapated */
- icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, wrgb[0], fromAbs);
+ icmAry2XYZ(white, wrgb[0]);
+ wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_NONE, icmD50, white, fromAbs);
icmMulBy3x3(d50m[0], fromAbs, mat[0]);
icmMulBy3x3(d50m[1], fromAbs, mat[1]);
icmMulBy3x3(d50m[2], fromAbs, mat[2]);
diff --git a/icc/sRGB.icm b/icc/sRGB.icm
index 5491330..9d33a4b 100644
--- a/icc/sRGB.icm
+++ b/icc/sRGB.icm
Binary files differ