summaryrefslogtreecommitdiff
path: root/profile/profout.c
diff options
context:
space:
mode:
Diffstat (limited to 'profile/profout.c')
-rw-r--r--profile/profout.c156
1 files changed, 116 insertions, 40 deletions
diff --git a/profile/profout.c b/profile/profout.c
index d89ae4e..8c6fa0d 100644
--- a/profile/profout.c
+++ b/profile/profout.c
@@ -65,6 +65,7 @@
#undef IMP_MONO /* [Undef] Turn on development code */
+#define EMPH_DISP_BLACKPOINT /* [Define] Increase weight near diplay black point */
#define NO_B2A_PCS_CURVES /* [Define] PCS curves seem to make B2A less accurate. Why ? */
#define USE_CAM_CLIP_OPT /* [Define] Clip out of gamut in CAM space rather than PCS */
#define USE_LEASTSQUARES_APROX /* [Define] Use least squares fitting approximation in B2A */
@@ -73,7 +74,7 @@
#undef DISABLE_GAMUT_TAG /* [Undef] To disable gamut tag */
#undef WARN_CLUT_CLIPPING /* [Undef] Print warning if setting clut clips */
#undef COMPARE_INV_CLUT /* [Undef] Compare result of inv_clut with clut to diag inv probs */
-#define FILTER_B2ACLIP /* [Define] Filter clip area of B2A */
+#undef FILTER_B2ACLIP /* [Undef] Filter clip area of B2A (Causes reversal problems) */
#define FILTER_THR_DE 3.0 /* [5.0] Filtering threshold DE */
#define FILTER_MAX_DE 5.0 /* [10.0] Filtering DE to gamut surface at whit MAX_RAD starts */
#define FILTER_MAX_RAD 0.1 /* [0.1] Filtering maximum radius in grid */
@@ -185,7 +186,7 @@ typedef struct {
double swxyz[3]; /* Source white point in XYZ */
gamut *gam; /* Output gamut object for setting gamut Lut */
- int wantLab; /* 0 if want is XYZ PCS, 1 want is Lab PCS */
+ int wantLab; /* 0 if is XYZ PCS, 1 if is Lab PCS */
} out_b2a_callback;
/* Utility to handle abstract profile application to PCS. */
@@ -642,6 +643,7 @@ make_output_icc(
int gamdiag, /* Make gamut mapping diagnostic wrl plots */
int verify, /* nz to print verification */
int clipprims, /* Clip white, black and primaries */
+ double wpscale, /* >= 0.0 for media white point scale factor */
icxInk *oink, /* Ink limit/black generation setup (NULL if n/a) */
char *in_name, /* input .ti3 file name */
char *file_name, /* output icc name */
@@ -655,6 +657,7 @@ make_output_icc(
int fwacomp, /* FWA compensation requested */
double smooth, /* RSPL smoothing factor, -ve if raw */
double avgdev, /* reading Average Deviation as a proportion of the input range */
+ double demph, /* Emphasise dark region grid resolution in cLUT */
char *ipname, /* input icc profile - enables gamut map, NULL if none */
char *sgname, /* source image gamut - NULL if none */
char *absname[3], /* abstract profile name for each table */
@@ -737,7 +740,7 @@ make_output_icc(
int ti;
if ((ti = icg->find_kword(icg, 0, "LUMINANCE_XYZ_CDM2")) >= 0) {
- if (sscanf(icg->t[0].kdata[ti], " %*lf %lf %*lf ",&dispLuminance) != 1)
+ if (sscanf(icg->t[0].kdata[ti], " %*f %lf %*f ",&dispLuminance) != 1)
dispLuminance = 0.0;
}
@@ -1215,6 +1218,17 @@ make_output_icc(
cc = 0.0;
else if (cc > 1.0)
cc = 1.0;
+
+ if (cal->tvenc) {
+ cc = (cc * (235.0-16.0) + 16.0)/255.0;
+
+ /* For video encoding the extra bits of precision are created by bit shifting */
+ /* rather than scaling, so we need to scale the fp value to account for this. */
+ /* We assume the precision is the vcgt table size = 16 */
+ /* ~~99 ideally we should tag the fact that this is video encoded, so that */
+ /* the vcgt loaded can adjust for a different bit precision ~~~~ */
+ cc = (cc * 255 * (1 << (16 - 8)))/((1 << 16) - 1.0);
+ }
((unsigned short*)wo->u.table.data)[ncal * j + i] = (int)(cc * 65535.0 + 0.5);
}
}
@@ -1389,12 +1403,12 @@ make_output_icc(
wog->allocate((icmBase *)wog);
wob->allocate((icmBase *)wob);
- wor->data[0].X = 1.0; wor->data[0].Y = 0.0; wor->data[0].Z = 0.0;
- wog->data[0].X = 0.0; wog->data[0].Y = 1.0; wog->data[0].Z = 0.0;
- wob->data[0].X = 0.0; wob->data[0].Y = 0.0; wob->data[0].Z = 1.0;
+// wor->data[0].X = 1.0; wor->data[0].Y = 0.0; wor->data[0].Z = 0.0;
+// wog->data[0].X = 0.0; wog->data[0].Y = 1.0; wog->data[0].Z = 0.0;
+// wob->data[0].X = 0.0; wob->data[0].Y = 0.0; wob->data[0].Z = 1.0;
/* Setup deliberately wrong dummy values (channels rotated). */
- /* icxMatrix may override override these later */
+ /* icxMatrix may override these later */
wor->data[0].X = 0.143066; wor->data[0].Y = 0.060608; wor->data[0].Z = 0.714096;
wog->data[0].X = 0.436066; wog->data[0].Y = 0.222488; wog->data[0].Z = 0.013916;
wob->data[0].X = 0.385147; wob->data[0].Y = 0.716873; wob->data[0].Z = 0.097076;
@@ -1834,6 +1848,8 @@ make_output_icc(
}
+ isLab = wantLab; /* We now have what we want */
+
/* Normalize display values to Y = 1.0 if needed */
/* (re-norm spec derived, since observer may be different) */
if (isdisp && (isdnormed == 0 || spec != 0)) {
@@ -1878,6 +1894,51 @@ make_output_icc(
}
} /* End of reading in CGATs file */
+
+#ifdef EMPH_DISP_BLACKPOINT
+ /* Add extra weighting to sample points near black for additive display. */
+ /* Not sure what the justification is, apart from making the black */
+ /* point more accurately modelled. Does this reflect an underlying */
+ /* problem with rspl in perceptual space ? Or is it a reflection */
+ /* of the possible "scaled" viewing mode of additive display */
+ /* usage ? What about print and scan ?? */
+ if (isdisp && (imask == ICX_W || imask == ICX_RGB)) {
+ double minL = 1e6;;
+
+ /* Locate the lowest L* value */
+ for (i = 0; i < npat; i++) {
+ if (wantLab) {
+ if (tpat[i].v[0] < minL)
+ minL = tpat[i].v[0];
+ } else {
+ double lab[2];
+ icmXYZ2Lab(&icmD50, lab, tpat[i].v);
+ if (lab[0] < minL)
+ minL = lab[0];
+ }
+ }
+
+ /* Compute weighting factor */
+ /* (Hard to guess what numbers to put in here.. */
+ for (i = 0; i < npat; i++) {
+ double lab[3], L;
+ if (wantLab) {
+ L = tpat[i].v[0];
+ } else {
+ icmXYZ2Lab(&icmD50, lab, tpat[i].v);
+ L = lab[0];
+ }
+ L -= minL;
+ L /= 20.0; /* Just weight over 20 L* range */
+ if (L > 1.0)
+ continue;
+ L = 1.0 + 19.0 * pow(1.0 - L, 3.0);
+ tpat[i].w *= L;
+//printf("~1 pat %d %f %f %f weight %f\n", i,tpat[i].p[0], tpat[i].p[1], tpat[i].p[2], tpat[i].w);
+ }
+ }
+#endif /* EMPH_DISP_BLACKPOINT */
+
if (isLut) {
xicc *wr_xicc; /* extention object */
icxLuBase *AtoB; /* AtoB ixcLu */
@@ -1920,7 +1981,7 @@ make_output_icc(
ICX_2PASSSMTH |
#endif
flags,
- npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev,
+ npat, npat, tpat, NULL, dispLuminance, wpscale, smooth, avgdev, demph,
NULL, oink, cal, iquality)) == NULL)
error("%d, %s",wr_xicc->errc, wr_xicc->err);
@@ -2016,18 +2077,20 @@ make_output_icc(
vc->Lv = v->Lv;
if (v->Yf >= 0.0)
vc->Yf = v->Yf;
- if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] > 0.0 && v->Fxyz[2] >= 0.0) {
+ if (v->Yg >= 0.0)
+ vc->Yg = v->Yg;
+ if (v->Gxyz[0] >= 0.0 && v->Gxyz[1] > 0.0 && v->Gxyz[2] >= 0.0) {
/* Normalise XYZ to current media white */
- vc->Fxyz[0] = v->Fxyz[0]/v->Fxyz[1] * vc->Fxyz[1];
- vc->Fxyz[2] = v->Fxyz[2]/v->Fxyz[1] * vc->Fxyz[1];
+ vc->Gxyz[0] = v->Gxyz[0]/v->Gxyz[1] * vc->Gxyz[1];
+ vc->Gxyz[2] = v->Gxyz[2]/v->Gxyz[1] * vc->Gxyz[1];
}
- if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] >= 0.0 && v->Fxyz[2] < 0.0) {
+ if (v->Gxyz[0] >= 0.0 && v->Gxyz[1] >= 0.0 && v->Gxyz[2] < 0.0) {
/* Convert Yxy to XYZ */
- double x = v->Fxyz[0];
- double y = v->Fxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double x = v->Gxyz[0];
+ double y = v->Gxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
double z = 1.0 - x - y;
- vc->Fxyz[0] = x/y * vc->Fxyz[1];
- vc->Fxyz[2] = z/y * vc->Fxyz[1];
+ vc->Gxyz[0] = x/y * vc->Gxyz[1];
+ vc->Gxyz[2] = z/y * vc->Gxyz[1];
}
}
@@ -2182,31 +2245,40 @@ make_output_icc(
/* cx.ix and cx.ox for each intent, but that would be expensive!. */
if (sepsat && (pgmi->usecas & 0xff) != (sgmi->usecas & 0xff))
error("Can't handle percept and sat table intents with different CAM spaces");
- /* Default perceptual input gamut mapping space is absolute perceptual */
- intentp = noptop ? icAbsoluteColorimetric : icmAbsolutePerceptual;
- /* But override this for apperance space gamut mapping */
- if ((pgmi->usecas & 0xff) != 0x0) {
+ /* If apperance space perceptual table gamut mapping */
+ if ((pgmi->usecas & 0xff) >= 0x2) {
intentp = noptop ? icxAppearance : icxPerceptualAppearance;
+ } else {
+ if ((pgmi->usecas & 0xff) == 0x0)
+ intentp = noptop ? icRelativeColorimetric : icPerceptual;
+ else /* pgmi->usecas & 0xff == 0x1 */
+ intentp = noptop ? icAbsoluteColorimetric : icmAbsolutePerceptual;
}
+
if (sepsat) {
- /* Default saturation gamut mapping space is absolute saturation */
- intents = nostos ? icAbsoluteColorimetric : icmAbsoluteSaturation;
- /* But override this for apperance space gamut mapping */
- if ((sgmi->usecas & 0xff) != 0x0) {
+ /* If apperance space saturation table gamut mapping */
+ if ((sgmi->usecas & 0xff) >= 0x2) {
intents = nostos ? icxAppearance : icxSaturationAppearance;
+ } else {
+ if ((sgmi->usecas & 0xff) == 0x0)
+ intents = nostos ? icRelativeColorimetric : icSaturation;
+ else
+ intents = nostos ? icAbsoluteColorimetric : icmAbsoluteSaturation;
}
}
- /* Default output gamut mapping space is absolute colorimetric */
- intento = icAbsoluteColorimetric;
- /* But override this for apperance space gamut mapping */
- if ((pgmi->usecas & 0xff) != 0x0) {
+ if ((pgmi->usecas & 0xff) >= 0x2) {
intento = icxAppearance;
+ } else {
+ if ((pgmi->usecas & 0xff) == 0x0)
+ intento = icRelativeColorimetric;
+ else /* pgmi->usecas & 0xff == 0x1 */
+ intento = icAbsoluteColorimetric;
}
- if ((pgmi->usecas & 0xff) == 0x2) {
+ if ((pgmi->usecas & 0xff) == 0x3) { /* Abs. appearance */
double mxw;
intentp = intents = intento = icxAbsAppearance;
@@ -2274,7 +2346,7 @@ make_output_icc(
if (sgname != NULL) { /* Optional source gamut - ie. from an images */
int isJab = 0;
- if ((pgmi->usecas & 0xff) != 0)
+ if ((pgmi->usecas & 0xff) >= 0x2)
isJab = 1;
if (verb)
@@ -2628,14 +2700,16 @@ make_output_icc(
ICM_CLUT_SET_FILTER |
#endif
0,
- &cx, /* Context */
- cx.pcsspace, /* Input color space */
- devspace, /* Output color space */
- out_b2a_input, /* Input transform PCS->PCS' */
- NULL, NULL, /* Use default PCS range */
- out_b2a_clut, /* Lab' -> Device' transfer function */
- NULL, NULL, /* Use default Device' range */
- out_b2a_output) != 0) /* Output transfer function, Device'->Device */
+ &cx, /* Context */
+ cx.pcsspace, /* Input color space */
+ devspace, /* Output color space */
+ out_b2a_input, /* Input transform PCS->PCS' */
+ NULL, NULL, /* Use default PCS range */
+ out_b2a_clut, /* Lab' -> Device' transfer function */
+ NULL, NULL, /* Use default Device' range */
+ out_b2a_output, /* Output transfer function, Device'->Device */
+ NULL, NULL /* Use default APXLS range */
+ ) != 0)
error("Setting 16 bit PCS->Device Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
if (cx.verb) {
printf("\n");
@@ -2769,7 +2843,9 @@ make_output_icc(
NULL, NULL, /* Use default Lab' range */
PCSp_bdist, /* Lab' -> Boundary distance */
NULL, NULL, /* Use default Device' range */
- gamut_output) != 0) /* Boundary distance to out of gamut value */
+ gamut_output, /* Boundary distance to out of gamut value */
+ NULL, NULL
+ ) != 0)
error("Setting 16 bit PCS->Device Gamut Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
#endif /* !DEBUG_ONE */
if (cx.verb) {
@@ -2823,7 +2899,7 @@ make_output_icc(
wr_xicc, icmFwd, isdisp ? icmDefaultIntent : icRelativeColorimetric,
icmLuOrdRev,
flags, /* Compute white & black */
- npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev,
+ npat, npat, tpat, NULL, dispLuminance, wpscale, smooth, avgdev, demph,
NULL, oink, cal, iquality)) == NULL)
error("%d, %s",wr_xicc->errc, wr_xicc->err);