Issue 2718 DCP: added support for sRGB-gamma-encoded LUTs
This commit is contained in:
@@ -30,6 +30,24 @@ using namespace std;
|
|||||||
using namespace rtengine;
|
using namespace rtengine;
|
||||||
using namespace rtexif;
|
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]) {
|
static void Invert3x3(const double (*A)[3], double (*B)[3]) {
|
||||||
|
|
||||||
double a00 = A[0][0];
|
double a00 = A[0][0];
|
||||||
@@ -471,6 +489,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
|
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
|
||||||
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
|
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
|
||||||
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
|
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
|
||||||
|
const int TagProfileHueSatMapEncoding=51107, TagProfileLookTableEncoding=51108;
|
||||||
const int TagProfileToneCurve=50940;
|
const int TagProfileToneCurve=50940;
|
||||||
|
|
||||||
aDeltas1=aDeltas2=aLookTable=NULL;
|
aDeltas1=aDeltas2=aLookTable=NULL;
|
||||||
@@ -530,6 +549,9 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
if (tag!=NULL) {
|
if (tag!=NULL) {
|
||||||
LookInfo.iHueDivisions=tag->toInt(0); LookInfo.iSatDivisions=tag->toInt(4); LookInfo.iValDivisions=tag->toInt(8);
|
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);
|
tag = tagDir->getTag(TagProfileLookTableData);
|
||||||
LookInfo.iArrayCount = tag->getCount()/3;
|
LookInfo.iArrayCount = tag->getCount()/3;
|
||||||
|
|
||||||
@@ -556,6 +578,9 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
if (tag!=NULL) {
|
if (tag!=NULL) {
|
||||||
DeltaInfo.iHueDivisions=tag->toInt(0); DeltaInfo.iSatDivisions=tag->toInt(4); DeltaInfo.iValDivisions=tag->toInt(8);
|
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);
|
tag = tagDir->getTag(TagProfileHueSatMapData1);
|
||||||
DeltaInfo.iArrayCount = tag->getCount()/3;
|
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
|
// Apply the HueSatMap. Ported from Adobes reference implementation
|
||||||
float hueShift, satScale, valScale;
|
float hueShift, satScale, valScale;
|
||||||
|
float vsEncoded = vs;
|
||||||
|
|
||||||
if (ti.iValDivisions < 2) // Optimize most common case of "2.5D" table.
|
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 hScaled = hs * ti.pc.hScale;
|
||||||
float sScaled = ss * ti.pc.sScale;
|
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 hIndex0 = (int) hScaled;
|
||||||
int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0);
|
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;
|
h += hueShift;
|
||||||
s *= satScale; // no clipping here, we are RT float :-)
|
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 {
|
struct ruvt {
|
||||||
|
@@ -41,6 +41,7 @@ namespace rtengine {
|
|||||||
{
|
{
|
||||||
int iHueDivisions, iSatDivisions, iValDivisions;
|
int iHueDivisions, iSatDivisions, iValDivisions;
|
||||||
int iHueStep, iValStep, iArrayCount;
|
int iHueStep, iValStep, iArrayCount;
|
||||||
|
bool sRGBGamma;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
float hScale, sScale, vScale;
|
float hScale, sScale, vScale;
|
||||||
|
Reference in New Issue
Block a user