< prev index next >
src/java.desktop/share/native/liblcms/cmsps2.c
Print this page
*** 28,38 ****
// file:
//
//---------------------------------------------------------------------------------
//
// Little Color Management System
! // Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
--- 28,38 ----
// file:
//
//---------------------------------------------------------------------------------
//
// Little Color Management System
! // Copyright (c) 1998-2020 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
*** 105,116 ****
Matrix-shaper based
-------------------
! This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig
! of profile implementation. Since here there are no interpolation tables, I do
the conversion directly to XYZ
[ /CIEBasedABC
--- 105,116 ----
Matrix-shaper based
-------------------
! This is implemented both with /CIEBasedABC or /CIEBasedDEF depending on the
! profile implementation. Since here there are no interpolation tables, I do
the conversion directly to XYZ
[ /CIEBasedABC
*** 322,346 ****
{
return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
}
- // Convert to byte (using ICC2 notation)
- /*
- static
- cmsUInt8Number L2Byte(cmsUInt16Number w)
- {
- int ww = w + 0x0080;
-
- if (ww > 0xFFFF) return 0xFF;
-
- return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
- }
- */
-
// Write a cooked byte
-
static
void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
{
_cmsIOPrintf(m, "%02x", b);
_cmsPSActualColumn += 2;
--- 322,332 ----
*** 353,363 ****
}
// ----------------------------------------------------------------- PostScript generation
! // Removes offending Carriage returns
static
char* RemoveCR(const char* txt)
{
static char Buffer[2048];
char* pt;
--- 339,350 ----
}
// ----------------------------------------------------------------- PostScript generation
! // Removes offending carriage returns
!
static
char* RemoveCR(const char* txt)
{
static char Buffer[2048];
char* pt;
*** 451,475 ****
//
// Y = Yn*[ (L* + 16) / 116] ^ 3 if (L*) >= 6 / 29
// = Yn*( L* / 116) / 7.787 if (L*) < 6 / 29
//
- /*
- static
- void EmitL2Y(cmsIOHANDLER* m)
- {
- _cmsIOPrintf(m,
- "{ "
- "100 mul 16 add 116 div " // (L * 100 + 16) / 116
- "dup 6 29 div ge " // >= 6 / 29 ?
- "{ dup dup mul mul } " // yes, ^3 and done
- "{ 4 29 div sub 108 841 div mul } " // no, slope limiting
- "ifelse } bind ");
- }
- */
-
-
// Lab -> XYZ, see the discussion above
static
void EmitLab2XYZ(cmsIOHANDLER* m)
{
--- 438,447 ----
*** 486,501 ****
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
_cmsIOPrintf(m, "]\n");
}
// Outputs a table of words. It does use 16 bits
static
! void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
{
cmsUInt32Number i;
cmsFloat64Number gamma;
if (Table == NULL) return; // Error
--- 458,489 ----
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
_cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
_cmsIOPrintf(m, "]\n");
}
+ static
+ void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name)
+ {
+ _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name);
+ _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name);
+ }
+ static
+ void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth)
+ {
+ _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name);
+ if (depth > 1) {
+ // cycle topmost items on the stack to bring the previous definition to the front
+ _cmsIOPrintf(m, "%d -1 roll ", depth);
+ }
+ _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name);
+ }
// Outputs a table of words. It does use 16 bits
static
! void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
{
cmsUInt32Number i;
cmsFloat64Number gamma;
if (Table == NULL) return; // Error
*** 506,537 ****
if (cmsIsToneCurveLinear(Table)) return;
// Check if is really an exponential. If so, emit "exp"
gamma = cmsEstimateGamma(Table, 0.001);
if (gamma > 0) {
! _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
return;
}
! _cmsIOPrintf(m, "{ ");
! // Bounds check
! EmitRangeCheck(m);
! // Emit intepolation code
// PostScript code Stack
// =============== ========================
// v
! _cmsIOPrintf(m, " [");
! for (i=0; i < Table->nEntries; i++) {
! _cmsIOPrintf(m, "%d ", Table->Table16[i]);
! }
!
! _cmsIOPrintf(m, "] "); // v tab
_cmsIOPrintf(m, "dup "); // v tab tab
_cmsIOPrintf(m, "length 1 sub "); // v tab dom
_cmsIOPrintf(m, "3 -1 roll "); // tab dom v
_cmsIOPrintf(m, "mul "); // tab val2
_cmsIOPrintf(m, "dup "); // tab val2 val2
--- 494,530 ----
if (cmsIsToneCurveLinear(Table)) return;
// Check if is really an exponential. If so, emit "exp"
gamma = cmsEstimateGamma(Table, 0.001);
if (gamma > 0) {
! _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma);
return;
}
! EmitSafeGuardBegin(m, "lcms2gammatable");
! _cmsIOPrintf(m, "/lcms2gammatable [");
! for (i=0; i < Table->nEntries; i++) {
! if (i % 10 == 0)
! _cmsIOPrintf(m, "\n ");
! _cmsIOPrintf(m, "%d ", Table->Table16[i]);
! }
!
! _cmsIOPrintf(m, "] def\n");
!
! // Emit interpolation code
// PostScript code Stack
// =============== ========================
// v
! _cmsIOPrintf(m, "/%s {\n ", name);
! // Bounds check
! EmitRangeCheck(m);
+ _cmsIOPrintf(m, "\n //lcms2gammatable "); // v tab
_cmsIOPrintf(m, "dup "); // v tab tab
_cmsIOPrintf(m, "length 1 sub "); // v tab dom
_cmsIOPrintf(m, "3 -1 roll "); // tab dom v
_cmsIOPrintf(m, "mul "); // tab val2
_cmsIOPrintf(m, "dup "); // tab val2 val2
*** 539,549 ****
_cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0
_cmsIOPrintf(m, "exch "); // tab val2 cell0 val2
_cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1
_cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab
_cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1
! _cmsIOPrintf(m, "get "); // tab val2 cell0 y1
_cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab
_cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0
_cmsIOPrintf(m, "get "); // val2 y1 y0
_cmsIOPrintf(m, "dup "); // val2 y1 y0 y0
_cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0
--- 532,542 ----
_cmsIOPrintf(m, "floor cvi "); // tab val2 val2 cell0
_cmsIOPrintf(m, "exch "); // tab val2 cell0 val2
_cmsIOPrintf(m, "ceiling cvi "); // tab val2 cell0 cell1
_cmsIOPrintf(m, "3 index "); // tab val2 cell0 cell1 tab
_cmsIOPrintf(m, "exch "); // tab val2 cell0 tab cell1
! _cmsIOPrintf(m, "get\n "); // tab val2 cell0 y1
_cmsIOPrintf(m, "4 -1 roll "); // val2 cell0 y1 tab
_cmsIOPrintf(m, "3 -1 roll "); // val2 y1 tab cell0
_cmsIOPrintf(m, "get "); // val2 y1 y0
_cmsIOPrintf(m, "dup "); // val2 y1 y0 y0
_cmsIOPrintf(m, "3 1 roll "); // val2 y0 y1 y0
*** 552,564 ****
_cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2
_cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2)
_cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest
_cmsIOPrintf(m, "mul "); // y0 t1
_cmsIOPrintf(m, "add "); // y
! _cmsIOPrintf(m, "65535 div "); // result
! _cmsIOPrintf(m, " } bind ");
}
// Compare gamma table
--- 545,559 ----
_cmsIOPrintf(m, "dup "); // y0 (y1-y0) val2 val2
_cmsIOPrintf(m, "floor cvi "); // y0 (y1-y0) val2 floor(val2)
_cmsIOPrintf(m, "sub "); // y0 (y1-y0) rest
_cmsIOPrintf(m, "mul "); // y0 t1
_cmsIOPrintf(m, "add "); // y
! _cmsIOPrintf(m, "65535 div\n"); // result
!
! _cmsIOPrintf(m, "} bind def\n");
! EmitSafeGuardEnd(m, "lcms2gammatable", 1);
}
// Compare gamma table
*** 570,602 ****
// Does write a set of gamma curves
static
! void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
{
cmsUInt32Number i;
for( i=0; i < n; i++ )
{
if (g[i] == NULL) return; // Error
if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
! _cmsIOPrintf(m, "dup ");
}
else {
! Emit1Gamma(m, g[i]);
}
}
}
-
-
-
// Following code dumps a LUT onto memory stream
// This is the sampler. Intended to work in SAMPLER_INSPECT mode,
// that is, the callback will be called for each knot with
--- 565,597 ----
// Does write a set of gamma curves
static
! void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix)
{
cmsUInt32Number i;
+ static char buffer[2048];
for( i=0; i < n; i++ )
{
if (g[i] == NULL) return; // Error
if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
! _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
}
else {
! snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, i);
! buffer[sizeof(buffer)-1] = '\0';
! Emit1Gamma(m, g[i], buffer);
}
}
}
// Following code dumps a LUT onto memory stream
// This is the sampler. Intended to work in SAMPLER_INSPECT mode,
// that is, the callback will be called for each knot with
*** 609,619 ****
// Each row contains Pipeline values for all but first component. So, I
// detect row changing by keeping a copy of last value of first
// component. -1 is used to mark beginning of whole block.
static
! int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
cmsUInt32Number i;
--- 604,614 ----
// Each row contains Pipeline values for all but first component. So, I
// detect row changing by keeping a copy of last value of first
// component. -1 is used to mark beginning of whole block.
static
! int OutputValueSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
{
cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
cmsUInt32Number i;
*** 735,749 ****
{
_cmsIOPrintf(m, "[ /CIEBasedA\n");
_cmsIOPrintf(m, " <<\n");
! _cmsIOPrintf(m, "/DecodeA ");
!
! Emit1Gamma(m, Curve);
! _cmsIOPrintf(m, " \n");
_cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
_cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
EmitWhiteBlackD50(m, BlackPoint);
--- 730,744 ----
{
_cmsIOPrintf(m, "[ /CIEBasedA\n");
_cmsIOPrintf(m, " <<\n");
! EmitSafeGuardBegin(m, "lcms2gammaproc");
! Emit1Gamma(m, Curve, "lcms2gammaproc");
! _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n");
! EmitSafeGuardEnd(m, "lcms2gammaproc", 3);
_cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
_cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
EmitWhiteBlackD50(m, BlackPoint);
*** 763,777 ****
{
int i;
_cmsIOPrintf(m, "[ /CIEBasedABC\n");
_cmsIOPrintf(m, "<<\n");
- _cmsIOPrintf(m, "/DecodeABC [ ");
-
- EmitNGamma(m, 3, CurveSet);
_cmsIOPrintf(m, "]\n");
_cmsIOPrintf(m, "/MatrixABC [ " );
for( i=0; i < 3; i++ ) {
--- 758,780 ----
{
int i;
_cmsIOPrintf(m, "[ /CIEBasedABC\n");
_cmsIOPrintf(m, "<<\n");
+ EmitSafeGuardBegin(m, "lcms2gammaproc0");
+ EmitSafeGuardBegin(m, "lcms2gammaproc1");
+ EmitSafeGuardBegin(m, "lcms2gammaproc2");
+ EmitNGamma(m, 3, CurveSet, "lcms2gammaproc");
+ _cmsIOPrintf(m, "/DecodeABC [\n");
+ _cmsIOPrintf(m, " /lcms2gammaproc0 load\n");
+ _cmsIOPrintf(m, " /lcms2gammaproc1 load\n");
+ _cmsIOPrintf(m, " /lcms2gammaproc2 load\n");
_cmsIOPrintf(m, "]\n");
+ EmitSafeGuardEnd(m, "lcms2gammaproc2", 3);
+ EmitSafeGuardEnd(m, "lcms2gammaproc1", 3);
+ EmitSafeGuardEnd(m, "lcms2gammaproc0", 3);
_cmsIOPrintf(m, "/MatrixABC [ " );
for( i=0; i < 3; i++ ) {
*** 799,848 ****
static
int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
{
const char* PreMaj;
const char* PostMaj;
! const char* PreMin, *PostMin;
cmsStage* mpe;
! mpe = Pipeline ->Elements;
switch (cmsStageInputChannels(mpe)) {
case 3:
-
_cmsIOPrintf(m, "[ /CIEBasedDEF\n");
! PreMaj ="<";
! PostMaj= ">\n";
PreMin = PostMin = "";
break;
case 4:
_cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
PreMaj = "[";
PostMaj = "]\n";
PreMin = "<";
PostMin = ">\n";
break;
default:
return 0;
}
_cmsIOPrintf(m, "<<\n");
if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
! _cmsIOPrintf(m, "/DecodeDEF [ ");
! EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
_cmsIOPrintf(m, "]\n");
! mpe = mpe ->Next;
}
if (cmsStageType(mpe) == cmsSigCLutElemType) {
_cmsIOPrintf(m, "/Table ");
! WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
_cmsIOPrintf(m, "]\n");
}
EmitLab2XYZ(m);
EmitWhiteBlackD50(m, BlackPoint);
--- 802,870 ----
static
int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
{
const char* PreMaj;
const char* PostMaj;
! const char* PreMin, * PostMin;
cmsStage* mpe;
+ int i, numchans;
+ static char buffer[2048];
! mpe = Pipeline->Elements;
switch (cmsStageInputChannels(mpe)) {
case 3:
_cmsIOPrintf(m, "[ /CIEBasedDEF\n");
! PreMaj = "<";
! PostMaj = ">\n";
PreMin = PostMin = "";
break;
+
case 4:
_cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
PreMaj = "[";
PostMaj = "]\n";
PreMin = "<";
PostMin = ">\n";
break;
+
default:
return 0;
}
_cmsIOPrintf(m, "<<\n");
if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
! numchans = cmsStageOutputChannels(mpe);
! for (i = 0; i < numchans; ++i) {
! snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
! buffer[sizeof(buffer) - 1] = '\0';
! EmitSafeGuardBegin(m, buffer);
! }
! EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc");
! _cmsIOPrintf(m, "/DecodeDEF [\n");
! for (i = 0; i < numchans; ++i) {
! snprintf(buffer, sizeof(buffer), " /lcms2gammaproc%d load\n", i);
! buffer[sizeof(buffer) - 1] = '\0';
! _cmsIOPrintf(m, buffer);
! }
_cmsIOPrintf(m, "]\n");
+ for (i = numchans - 1; i >= 0; --i) {
+ snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
+ buffer[sizeof(buffer) - 1] = '\0';
+ EmitSafeGuardEnd(m, buffer, 3);
+ }
! mpe = mpe->Next;
}
if (cmsStageType(mpe) == cmsSigCLutElemType) {
_cmsIOPrintf(m, "/Table ");
! WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0);
_cmsIOPrintf(m, "]\n");
}
EmitLab2XYZ(m);
EmitWhiteBlackD50(m, BlackPoint);
*** 950,960 ****
}
break;
default:
! cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
return 0;
}
cmsDeleteTransform(xform);
--- 972,982 ----
}
break;
default:
! cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels are supported for CSA. This profile has %d channels.", nChannels);
return 0;
}
cmsDeleteTransform(xform);
*** 1266,1277 ****
"2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
"3 index 5 get 3 index 5 get exch sub div "
"exch pop exch pop exch pop exch pop } bind\n]\n");
}
-
-
}
static
void EmitXYZ2Lab(cmsIOHANDLER* m)
--- 1288,1297 ----
*** 1297,1307 ****
}
// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces
// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted
// space on 3D CLUT, but since space seems not to be a problem here, 33 points
! // would give a reasonable accurancy. Note also that CRD tables must operate in
// 8 bits.
static
int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
--- 1317,1327 ----
}
// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces
// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted
// space on 3D CLUT, but since space seems not to be a problem here, 33 points
! // would give a reasonable accuracy. Note also that CRD tables must operate in
// 8 bits.
static
int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
< prev index next >