Issue 2718 DCP: added support for sRGB-gamma-encoded LUTs

This commit is contained in:
torger
2015-03-17 18:10:10 +01:00
parent 354df735e0
commit 7994c914dd
2 changed files with 38 additions and 2 deletions

View File

@@ -30,6 +30,24 @@ using namespace std;
using namespace rtengine;
using namespace rtexif;
// This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here
static float sRGBGammaForward (const float x) {
if (x <= 0.0031308)
return x * 12.92;
else if (x > 1.0)
return 1.0 + (x - 1.0) * (1.055*(1.0/2.4)); // linear extension
else
return 1.055 * pow (x, 1.0 / 2.4) - 0.055;
}
static float sRGBGammaInverse (const float y) {
if (y <= 0.0031308 * 12.92)
return y * (1.0 / 12.92);
else if (y > 1.0)
return 1.0 + (y - 1.0) / (1.055*(1.0/2.4));
else
return pow ((y + 0.055) * (1.0 / 1.055), 2.4);
}
static void Invert3x3(const double (*A)[3], double (*B)[3]) {
double a00 = A[0][0];
@@ -471,6 +489,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
const int TagProfileHueSatMapEncoding=51107, TagProfileLookTableEncoding=51108;
const int TagProfileToneCurve=50940;
aDeltas1=aDeltas2=aLookTable=NULL;
@@ -530,6 +549,9 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
if (tag!=NULL) {
LookInfo.iHueDivisions=tag->toInt(0); LookInfo.iSatDivisions=tag->toInt(4); LookInfo.iValDivisions=tag->toInt(8);
tag = tagDir->getTag(TagProfileLookTableEncoding);
LookInfo.sRGBGamma = tag != NULL && tag->toInt(0);
tag = tagDir->getTag(TagProfileLookTableData);
LookInfo.iArrayCount = tag->getCount()/3;
@@ -556,6 +578,9 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
if (tag!=NULL) {
DeltaInfo.iHueDivisions=tag->toInt(0); DeltaInfo.iSatDivisions=tag->toInt(4); DeltaInfo.iValDivisions=tag->toInt(8);
tag = tagDir->getTag(TagProfileLookTableEncoding);
DeltaInfo.sRGBGamma = tag != NULL && tag->toInt(0);
tag = tagDir->getTag(TagProfileHueSatMapData1);
DeltaInfo.iArrayCount = tag->getCount()/3;
@@ -665,6 +690,7 @@ void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, co
// Apply the HueSatMap. Ported from Adobes reference implementation
float hueShift, satScale, valScale;
float vsEncoded = vs;
if (ti.iValDivisions < 2) // Optimize most common case of "2.5D" table.
{
@@ -715,7 +741,8 @@ void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, co
float hScaled = hs * ti.pc.hScale;
float sScaled = ss * ti.pc.sScale;
float vScaled = vs * ti.pc.vScale;
if (ti.sRGBGamma) vsEncoded = sRGBGammaForward(vs);
float vScaled = vsEncoded * ti.pc.vScale;
int hIndex0 = (int) hScaled;
int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0);
@@ -788,7 +815,15 @@ void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, co
h += hueShift;
s *= satScale; // no clipping here, we are RT float :-)
v *= valScale;
if (ti.sRGBGamma) {
if (v == vs) {
v = sRGBGammaInverse(vsEncoded * valScale);
} else {
v = sRGBGammaInverse(sRGBGammaForward(v) * valScale);
}
} else {
v *= valScale;
}
}
struct ruvt {

View File

@@ -41,6 +41,7 @@ namespace rtengine {
{
int iHueDivisions, iSatDivisions, iValDivisions;
int iHueStep, iValStep, iArrayCount;
bool sRGBGamma;
struct
{
float hScale, sScale, vScale;