diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index ebe2d8aee..775428a4e 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -17,7 +17,6 @@ * along with RawTherapee. If not, see . */ -#include #include #include "dcp.h" @@ -27,316 +26,14 @@ #include "improcfun.h" #include "rt_math.h" -using namespace std; using namespace rtengine; using namespace rtexif; namespace { -static const float adobe_camera_raw_default_curve[] = { - 0.00000f, 0.00078f, 0.00160f, 0.00242f, - 0.00314f, 0.00385f, 0.00460f, 0.00539f, - 0.00623f, 0.00712f, 0.00806f, 0.00906f, - 0.01012f, 0.01122f, 0.01238f, 0.01359f, - 0.01485f, 0.01616f, 0.01751f, 0.01890f, - 0.02033f, 0.02180f, 0.02331f, 0.02485f, - 0.02643f, 0.02804f, 0.02967f, 0.03134f, - 0.03303f, 0.03475f, 0.03648f, 0.03824f, - 0.04002f, 0.04181f, 0.04362f, 0.04545f, - 0.04730f, 0.04916f, 0.05103f, 0.05292f, - 0.05483f, 0.05675f, 0.05868f, 0.06063f, - 0.06259f, 0.06457f, 0.06655f, 0.06856f, - 0.07057f, 0.07259f, 0.07463f, 0.07668f, - 0.07874f, 0.08081f, 0.08290f, 0.08499f, - 0.08710f, 0.08921f, 0.09134f, 0.09348f, - 0.09563f, 0.09779f, 0.09996f, 0.10214f, - 0.10433f, 0.10652f, 0.10873f, 0.11095f, - 0.11318f, 0.11541f, 0.11766f, 0.11991f, - 0.12218f, 0.12445f, 0.12673f, 0.12902f, - 0.13132f, 0.13363f, 0.13595f, 0.13827f, - 0.14061f, 0.14295f, 0.14530f, 0.14765f, - 0.15002f, 0.15239f, 0.15477f, 0.15716f, - 0.15956f, 0.16197f, 0.16438f, 0.16680f, - 0.16923f, 0.17166f, 0.17410f, 0.17655f, - 0.17901f, 0.18148f, 0.18395f, 0.18643f, - 0.18891f, 0.19141f, 0.19391f, 0.19641f, - 0.19893f, 0.20145f, 0.20398f, 0.20651f, - 0.20905f, 0.21160f, 0.21416f, 0.21672f, - 0.21929f, 0.22185f, 0.22440f, 0.22696f, - 0.22950f, 0.23204f, 0.23458f, 0.23711f, - 0.23963f, 0.24215f, 0.24466f, 0.24717f, - 0.24967f, 0.25216f, 0.25465f, 0.25713f, - 0.25961f, 0.26208f, 0.26454f, 0.26700f, - 0.26945f, 0.27189f, 0.27433f, 0.27676f, - 0.27918f, 0.28160f, 0.28401f, 0.28641f, - 0.28881f, 0.29120f, 0.29358f, 0.29596f, - 0.29833f, 0.30069f, 0.30305f, 0.30540f, - 0.30774f, 0.31008f, 0.31241f, 0.31473f, - 0.31704f, 0.31935f, 0.32165f, 0.32395f, - 0.32623f, 0.32851f, 0.33079f, 0.33305f, - 0.33531f, 0.33756f, 0.33981f, 0.34205f, - 0.34428f, 0.34650f, 0.34872f, 0.35093f, - 0.35313f, 0.35532f, 0.35751f, 0.35969f, - 0.36187f, 0.36404f, 0.36620f, 0.36835f, - 0.37050f, 0.37264f, 0.37477f, 0.37689f, - 0.37901f, 0.38112f, 0.38323f, 0.38533f, - 0.38742f, 0.38950f, 0.39158f, 0.39365f, - 0.39571f, 0.39777f, 0.39982f, 0.40186f, - 0.40389f, 0.40592f, 0.40794f, 0.40996f, - 0.41197f, 0.41397f, 0.41596f, 0.41795f, - 0.41993f, 0.42191f, 0.42388f, 0.42584f, - 0.42779f, 0.42974f, 0.43168f, 0.43362f, - 0.43554f, 0.43747f, 0.43938f, 0.44129f, - 0.44319f, 0.44509f, 0.44698f, 0.44886f, - 0.45073f, 0.45260f, 0.45447f, 0.45632f, - 0.45817f, 0.46002f, 0.46186f, 0.46369f, - 0.46551f, 0.46733f, 0.46914f, 0.47095f, - 0.47275f, 0.47454f, 0.47633f, 0.47811f, - 0.47989f, 0.48166f, 0.48342f, 0.48518f, - 0.48693f, 0.48867f, 0.49041f, 0.49214f, - 0.49387f, 0.49559f, 0.49730f, 0.49901f, - 0.50072f, 0.50241f, 0.50410f, 0.50579f, - 0.50747f, 0.50914f, 0.51081f, 0.51247f, - 0.51413f, 0.51578f, 0.51742f, 0.51906f, - 0.52069f, 0.52232f, 0.52394f, 0.52556f, - 0.52717f, 0.52878f, 0.53038f, 0.53197f, - 0.53356f, 0.53514f, 0.53672f, 0.53829f, - 0.53986f, 0.54142f, 0.54297f, 0.54452f, - 0.54607f, 0.54761f, 0.54914f, 0.55067f, - 0.55220f, 0.55371f, 0.55523f, 0.55673f, - 0.55824f, 0.55973f, 0.56123f, 0.56271f, - 0.56420f, 0.56567f, 0.56715f, 0.56861f, - 0.57007f, 0.57153f, 0.57298f, 0.57443f, - 0.57587f, 0.57731f, 0.57874f, 0.58017f, - 0.58159f, 0.58301f, 0.58443f, 0.58583f, - 0.58724f, 0.58864f, 0.59003f, 0.59142f, - 0.59281f, 0.59419f, 0.59556f, 0.59694f, - 0.59830f, 0.59966f, 0.60102f, 0.60238f, - 0.60373f, 0.60507f, 0.60641f, 0.60775f, - 0.60908f, 0.61040f, 0.61173f, 0.61305f, - 0.61436f, 0.61567f, 0.61698f, 0.61828f, - 0.61957f, 0.62087f, 0.62216f, 0.62344f, - 0.62472f, 0.62600f, 0.62727f, 0.62854f, - 0.62980f, 0.63106f, 0.63232f, 0.63357f, - 0.63482f, 0.63606f, 0.63730f, 0.63854f, - 0.63977f, 0.64100f, 0.64222f, 0.64344f, - 0.64466f, 0.64587f, 0.64708f, 0.64829f, - 0.64949f, 0.65069f, 0.65188f, 0.65307f, - 0.65426f, 0.65544f, 0.65662f, 0.65779f, - 0.65897f, 0.66013f, 0.66130f, 0.66246f, - 0.66362f, 0.66477f, 0.66592f, 0.66707f, - 0.66821f, 0.66935f, 0.67048f, 0.67162f, - 0.67275f, 0.67387f, 0.67499f, 0.67611f, - 0.67723f, 0.67834f, 0.67945f, 0.68055f, - 0.68165f, 0.68275f, 0.68385f, 0.68494f, - 0.68603f, 0.68711f, 0.68819f, 0.68927f, - 0.69035f, 0.69142f, 0.69249f, 0.69355f, - 0.69461f, 0.69567f, 0.69673f, 0.69778f, - 0.69883f, 0.69988f, 0.70092f, 0.70196f, - 0.70300f, 0.70403f, 0.70506f, 0.70609f, - 0.70711f, 0.70813f, 0.70915f, 0.71017f, - 0.71118f, 0.71219f, 0.71319f, 0.71420f, - 0.71520f, 0.71620f, 0.71719f, 0.71818f, - 0.71917f, 0.72016f, 0.72114f, 0.72212f, - 0.72309f, 0.72407f, 0.72504f, 0.72601f, - 0.72697f, 0.72794f, 0.72890f, 0.72985f, - 0.73081f, 0.73176f, 0.73271f, 0.73365f, - 0.73460f, 0.73554f, 0.73647f, 0.73741f, - 0.73834f, 0.73927f, 0.74020f, 0.74112f, - 0.74204f, 0.74296f, 0.74388f, 0.74479f, - 0.74570f, 0.74661f, 0.74751f, 0.74842f, - 0.74932f, 0.75021f, 0.75111f, 0.75200f, - 0.75289f, 0.75378f, 0.75466f, 0.75555f, - 0.75643f, 0.75730f, 0.75818f, 0.75905f, - 0.75992f, 0.76079f, 0.76165f, 0.76251f, - 0.76337f, 0.76423f, 0.76508f, 0.76594f, - 0.76679f, 0.76763f, 0.76848f, 0.76932f, - 0.77016f, 0.77100f, 0.77183f, 0.77267f, - 0.77350f, 0.77432f, 0.77515f, 0.77597f, - 0.77680f, 0.77761f, 0.77843f, 0.77924f, - 0.78006f, 0.78087f, 0.78167f, 0.78248f, - 0.78328f, 0.78408f, 0.78488f, 0.78568f, - 0.78647f, 0.78726f, 0.78805f, 0.78884f, - 0.78962f, 0.79040f, 0.79118f, 0.79196f, - 0.79274f, 0.79351f, 0.79428f, 0.79505f, - 0.79582f, 0.79658f, 0.79735f, 0.79811f, - 0.79887f, 0.79962f, 0.80038f, 0.80113f, - 0.80188f, 0.80263f, 0.80337f, 0.80412f, - 0.80486f, 0.80560f, 0.80634f, 0.80707f, - 0.80780f, 0.80854f, 0.80926f, 0.80999f, - 0.81072f, 0.81144f, 0.81216f, 0.81288f, - 0.81360f, 0.81431f, 0.81503f, 0.81574f, - 0.81645f, 0.81715f, 0.81786f, 0.81856f, - 0.81926f, 0.81996f, 0.82066f, 0.82135f, - 0.82205f, 0.82274f, 0.82343f, 0.82412f, - 0.82480f, 0.82549f, 0.82617f, 0.82685f, - 0.82753f, 0.82820f, 0.82888f, 0.82955f, - 0.83022f, 0.83089f, 0.83155f, 0.83222f, - 0.83288f, 0.83354f, 0.83420f, 0.83486f, - 0.83552f, 0.83617f, 0.83682f, 0.83747f, - 0.83812f, 0.83877f, 0.83941f, 0.84005f, - 0.84069f, 0.84133f, 0.84197f, 0.84261f, - 0.84324f, 0.84387f, 0.84450f, 0.84513f, - 0.84576f, 0.84639f, 0.84701f, 0.84763f, - 0.84825f, 0.84887f, 0.84949f, 0.85010f, - 0.85071f, 0.85132f, 0.85193f, 0.85254f, - 0.85315f, 0.85375f, 0.85436f, 0.85496f, - 0.85556f, 0.85615f, 0.85675f, 0.85735f, - 0.85794f, 0.85853f, 0.85912f, 0.85971f, - 0.86029f, 0.86088f, 0.86146f, 0.86204f, - 0.86262f, 0.86320f, 0.86378f, 0.86435f, - 0.86493f, 0.86550f, 0.86607f, 0.86664f, - 0.86720f, 0.86777f, 0.86833f, 0.86889f, - 0.86945f, 0.87001f, 0.87057f, 0.87113f, - 0.87168f, 0.87223f, 0.87278f, 0.87333f, - 0.87388f, 0.87443f, 0.87497f, 0.87552f, - 0.87606f, 0.87660f, 0.87714f, 0.87768f, - 0.87821f, 0.87875f, 0.87928f, 0.87981f, - 0.88034f, 0.88087f, 0.88140f, 0.88192f, - 0.88244f, 0.88297f, 0.88349f, 0.88401f, - 0.88453f, 0.88504f, 0.88556f, 0.88607f, - 0.88658f, 0.88709f, 0.88760f, 0.88811f, - 0.88862f, 0.88912f, 0.88963f, 0.89013f, - 0.89063f, 0.89113f, 0.89163f, 0.89212f, - 0.89262f, 0.89311f, 0.89360f, 0.89409f, - 0.89458f, 0.89507f, 0.89556f, 0.89604f, - 0.89653f, 0.89701f, 0.89749f, 0.89797f, - 0.89845f, 0.89892f, 0.89940f, 0.89987f, - 0.90035f, 0.90082f, 0.90129f, 0.90176f, - 0.90222f, 0.90269f, 0.90316f, 0.90362f, - 0.90408f, 0.90454f, 0.90500f, 0.90546f, - 0.90592f, 0.90637f, 0.90683f, 0.90728f, - 0.90773f, 0.90818f, 0.90863f, 0.90908f, - 0.90952f, 0.90997f, 0.91041f, 0.91085f, - 0.91130f, 0.91173f, 0.91217f, 0.91261f, - 0.91305f, 0.91348f, 0.91392f, 0.91435f, - 0.91478f, 0.91521f, 0.91564f, 0.91606f, - 0.91649f, 0.91691f, 0.91734f, 0.91776f, - 0.91818f, 0.91860f, 0.91902f, 0.91944f, - 0.91985f, 0.92027f, 0.92068f, 0.92109f, - 0.92150f, 0.92191f, 0.92232f, 0.92273f, - 0.92314f, 0.92354f, 0.92395f, 0.92435f, - 0.92475f, 0.92515f, 0.92555f, 0.92595f, - 0.92634f, 0.92674f, 0.92713f, 0.92753f, - 0.92792f, 0.92831f, 0.92870f, 0.92909f, - 0.92947f, 0.92986f, 0.93025f, 0.93063f, - 0.93101f, 0.93139f, 0.93177f, 0.93215f, - 0.93253f, 0.93291f, 0.93328f, 0.93366f, - 0.93403f, 0.93440f, 0.93478f, 0.93515f, - 0.93551f, 0.93588f, 0.93625f, 0.93661f, - 0.93698f, 0.93734f, 0.93770f, 0.93807f, - 0.93843f, 0.93878f, 0.93914f, 0.93950f, - 0.93986f, 0.94021f, 0.94056f, 0.94092f, - 0.94127f, 0.94162f, 0.94197f, 0.94231f, - 0.94266f, 0.94301f, 0.94335f, 0.94369f, - 0.94404f, 0.94438f, 0.94472f, 0.94506f, - 0.94540f, 0.94573f, 0.94607f, 0.94641f, - 0.94674f, 0.94707f, 0.94740f, 0.94774f, - 0.94807f, 0.94839f, 0.94872f, 0.94905f, - 0.94937f, 0.94970f, 0.95002f, 0.95035f, - 0.95067f, 0.95099f, 0.95131f, 0.95163f, - 0.95194f, 0.95226f, 0.95257f, 0.95289f, - 0.95320f, 0.95351f, 0.95383f, 0.95414f, - 0.95445f, 0.95475f, 0.95506f, 0.95537f, - 0.95567f, 0.95598f, 0.95628f, 0.95658f, - 0.95688f, 0.95718f, 0.95748f, 0.95778f, - 0.95808f, 0.95838f, 0.95867f, 0.95897f, - 0.95926f, 0.95955f, 0.95984f, 0.96013f, - 0.96042f, 0.96071f, 0.96100f, 0.96129f, - 0.96157f, 0.96186f, 0.96214f, 0.96242f, - 0.96271f, 0.96299f, 0.96327f, 0.96355f, - 0.96382f, 0.96410f, 0.96438f, 0.96465f, - 0.96493f, 0.96520f, 0.96547f, 0.96574f, - 0.96602f, 0.96629f, 0.96655f, 0.96682f, - 0.96709f, 0.96735f, 0.96762f, 0.96788f, - 0.96815f, 0.96841f, 0.96867f, 0.96893f, - 0.96919f, 0.96945f, 0.96971f, 0.96996f, - 0.97022f, 0.97047f, 0.97073f, 0.97098f, - 0.97123f, 0.97149f, 0.97174f, 0.97199f, - 0.97223f, 0.97248f, 0.97273f, 0.97297f, - 0.97322f, 0.97346f, 0.97371f, 0.97395f, - 0.97419f, 0.97443f, 0.97467f, 0.97491f, - 0.97515f, 0.97539f, 0.97562f, 0.97586f, - 0.97609f, 0.97633f, 0.97656f, 0.97679f, - 0.97702f, 0.97725f, 0.97748f, 0.97771f, - 0.97794f, 0.97817f, 0.97839f, 0.97862f, - 0.97884f, 0.97907f, 0.97929f, 0.97951f, - 0.97973f, 0.97995f, 0.98017f, 0.98039f, - 0.98061f, 0.98082f, 0.98104f, 0.98125f, - 0.98147f, 0.98168f, 0.98189f, 0.98211f, - 0.98232f, 0.98253f, 0.98274f, 0.98295f, - 0.98315f, 0.98336f, 0.98357f, 0.98377f, - 0.98398f, 0.98418f, 0.98438f, 0.98458f, - 0.98478f, 0.98498f, 0.98518f, 0.98538f, - 0.98558f, 0.98578f, 0.98597f, 0.98617f, - 0.98636f, 0.98656f, 0.98675f, 0.98694f, - 0.98714f, 0.98733f, 0.98752f, 0.98771f, - 0.98789f, 0.98808f, 0.98827f, 0.98845f, - 0.98864f, 0.98882f, 0.98901f, 0.98919f, - 0.98937f, 0.98955f, 0.98973f, 0.98991f, - 0.99009f, 0.99027f, 0.99045f, 0.99063f, - 0.99080f, 0.99098f, 0.99115f, 0.99133f, - 0.99150f, 0.99167f, 0.99184f, 0.99201f, - 0.99218f, 0.99235f, 0.99252f, 0.99269f, - 0.99285f, 0.99302f, 0.99319f, 0.99335f, - 0.99351f, 0.99368f, 0.99384f, 0.99400f, - 0.99416f, 0.99432f, 0.99448f, 0.99464f, - 0.99480f, 0.99495f, 0.99511f, 0.99527f, - 0.99542f, 0.99558f, 0.99573f, 0.99588f, - 0.99603f, 0.99619f, 0.99634f, 0.99649f, - 0.99664f, 0.99678f, 0.99693f, 0.99708f, - 0.99722f, 0.99737f, 0.99751f, 0.99766f, - 0.99780f, 0.99794f, 0.99809f, 0.99823f, - 0.99837f, 0.99851f, 0.99865f, 0.99879f, - 0.99892f, 0.99906f, 0.99920f, 0.99933f, - 0.99947f, 0.99960f, 0.99974f, 0.99987f, - 1.00000f -}; - -struct ruvt { - double r; - double u; - double v; - double t; -}; - -static const ruvt kTempTable [] = { - { 0, 0.18006, 0.26352, -0.24341 }, - { 10, 0.18066, 0.26589, -0.25479 }, - { 20, 0.18133, 0.26846, -0.26876 }, - { 30, 0.18208, 0.27119, -0.28539 }, - { 40, 0.18293, 0.27407, -0.30470 }, - { 50, 0.18388, 0.27709, -0.32675 }, - { 60, 0.18494, 0.28021, -0.35156 }, - { 70, 0.18611, 0.28342, -0.37915 }, - { 80, 0.18740, 0.28668, -0.40955 }, - { 90, 0.18880, 0.28997, -0.44278 }, - { 100, 0.19032, 0.29326, -0.47888 }, - { 125, 0.19462, 0.30141, -0.58204 }, - { 150, 0.19962, 0.30921, -0.70471 }, - { 175, 0.20525, 0.31647, -0.84901 }, - { 200, 0.21142, 0.32312, -1.0182 }, - { 225, 0.21807, 0.32909, -1.2168 }, - { 250, 0.22511, 0.33439, -1.4512 }, - { 275, 0.23247, 0.33904, -1.7298 }, - { 300, 0.24010, 0.34308, -2.0637 }, - { 325, 0.24702, 0.34655, -2.4681 }, - { 350, 0.25591, 0.34951, -2.9641 }, - { 375, 0.26400, 0.35200, -3.5814 }, - { 400, 0.27218, 0.35407, -4.3633 }, - { 425, 0.28039, 0.35577, -5.3762 }, - { 450, 0.28863, 0.35714, -6.7262 }, - { 475, 0.29685, 0.35823, -8.5955 }, - { 500, 0.30505, 0.35907, -11.324 }, - { 525, 0.31320, 0.35968, -15.628 }, - { 550, 0.32129, 0.36011, -23.325 }, - { 575, 0.32931, 0.36038, -40.770 }, - { 600, 0.33724, 0.36051, -116.45 } -}; - // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -float sRGBGammaForward(float x) +float srgbGammaForward(float x) { return x <= 0.0031308f @@ -346,7 +43,7 @@ float sRGBGammaForward(float x) : 1.055f * pow(x, 1.0f / 2.4f) - 0.055f; } -float sRGBGammaInverse(float y) +float srgbGammaInverse(float y) { return y <= 0.0031308f * 12.92f @@ -356,17 +53,17 @@ float sRGBGammaInverse(float y) : pow ((y + 0.055f) * (1.0f / 1.055f), 2.4f); } -void invert3x3(const double (*A)[3], double (*B)[3]) +void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b) { - const double& a00 = A[0][0]; - const double& a01 = A[0][1]; - const double& a02 = A[0][2]; - const double& a10 = A[1][0]; - const double& a11 = A[1][1]; - const double& a12 = A[1][2]; - const double& a20 = A[2][0]; - const double& a21 = A[2][1]; - const double& a22 = A[2][2]; + const double& a00 = a[0][0]; + const double& a01 = a[0][1]; + const double& a02 = a[0][2]; + const double& a10 = a[1][0]; + const double& a11 = a[1][1]; + const double& a12 = a[1][2]; + const double& a20 = a[2][0]; + const double& a21 = a[2][1]; + const double& a22 = a[2][2]; double temp[3][3]; @@ -382,77 +79,77 @@ void invert3x3(const double (*A)[3], double (*B)[3]) const double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; - if (fabs(det) < 1.0E-10) { + if (fabs(det) < 1.0e-10) { abort(); // Can't be inverted, we shouldn't be dealing with such matrices } for (int j = 0; j < 3; ++j) { for (int k = 0; k < 3; ++k) { - B[j][k] = temp[j][k] / det; + b[j][k] = temp[j][k] / det; } } } -void multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) +void multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b, DCPProfile::Matrix& c) { // Use temp to support having output same as input - double M[3][3]; + DCPProfile::Matrix m; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - M[i][j] = 0; + m[i][j] = 0; for (int k = 0; k < 3; ++k) { - M[i][j] += A[i][k] * B[k][j]; + m[i][j] += a[i][k] * b[k][j]; } } } - memcpy(C, M, 3 * 3 * sizeof(double)); + c = m; } -void multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) +void multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b, DCPProfile::Triple& c) { // Use temp to support having output same as input - double M[3] = {}; + DCPProfile::Triple m = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - M[i] += A[i][j] * B[j]; + m[i] += a[i][j] * b[j]; } } - memcpy(C, M, 3 * sizeof(double)); + c = m; } -void mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) +void mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b, DCPProfile::Matrix& c) { - double M[3][3]; + DCPProfile::Matrix m; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - M[i][j] = A[i][j] * mulA + B[i][j] * mulB; + m[i][j] = a[i][j] * mul_a + b[i][j] * mul_b; } } - memcpy(C, M, 3 * 3 * sizeof(double)); + c = m; } -void mapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) +void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2, DCPProfile::Matrix& b) { // Code adapted from dng_color_spec::MapWhiteMatrix // Use the linearized Bradford adaptation matrix - const double Mb[3][3] = { + const DCPProfile::Matrix mb = {{ { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 } - }; + }}; - double w1[3]; - multiply3x3_v3(Mb, white1, w1); - double w2[3]; - multiply3x3_v3(Mb, white2, w2); + DCPProfile::Triple w1; + multiply3x3_v3(mb, white1, w1); + DCPProfile::Triple w2; + multiply3x3_v3(mb, white2, w2); // Negative white coordinates are kind of meaningless. w1[0] = std::max(w1[0], 0.0); @@ -463,37 +160,33 @@ void mapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[ w2[2] = std::max(w2[2], 0.0); // Limit scaling to something reasonable. - double A[3][3] = {}; - A[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); - A[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); - A[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); + DCPProfile::Matrix a = {}; + a[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); + a[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); + a[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); - double temp[3][3]; - invert3x3(Mb, temp); - multiply3x3(temp, A, temp); - multiply3x3(temp, Mb, B); + DCPProfile::Matrix temp; + invert3x3(mb, temp); + multiply3x3(temp, a, temp); + multiply3x3(temp, mb, b); } -void XYZtoXY(const double XYZ[3], double XY[2]) +void xyzToXy(const DCPProfile::Triple& xyz, double xy[2]) { - const double& X = XYZ[0]; - const double& Y = XYZ[1]; - const double& Z = XYZ[2]; - - const double total = X + Y + Z; + const double total = xyz[0] + xyz[1] + xyz[2]; if (total > 0.0) { - XY[0] = X / total; - XY[1] = Y / total; + xy[0] = xyz[0] / total; + xy[1] = xyz[1] / total; } else { - XY[0] = 0.3457; - XY[1] = 0.3585; + xy[0] = 0.3457; + xy[1] = 0.3585; } } -void XYtoXYZ(const double XY[2], double XYZ[3]) +void xyToXyz(const double xy[2], DCPProfile::Triple& xyz) { - double temp[2] = { XY[0], XY[1] }; + double temp[2] = {xy[0], xy[1]}; // Restrict xy coord to someplace inside the range of real xy coordinates. // This prevents math from doing strange things when users specify @@ -507,9 +200,9 @@ void XYtoXYZ(const double XY[2], double XYZ[3]) temp[1] *= scale; } - XYZ[0] = temp[0] / temp[1]; - XYZ[1] = 1.0; - XYZ[2] = (1.0 - temp[0] - temp[1]) / temp[1]; + xyz[0] = temp[0] / temp[1]; + xyz[1] = 1.0; + xyz[2] = (1.0 - temp[0] - temp[1]) / temp[1]; } double calibrationIlluminantToTemperature(int light) @@ -600,6 +293,146 @@ double calibrationIlluminantToTemperature(int light) } } +void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) +{ + struct Ruvt { + double r; + double u; + double v; + double t; + }; + + static const Ruvt temp_table[] = { + { 0, 0.18006, 0.26352, -0.24341 }, + { 10, 0.18066, 0.26589, -0.25479 }, + { 20, 0.18133, 0.26846, -0.26876 }, + { 30, 0.18208, 0.27119, -0.28539 }, + { 40, 0.18293, 0.27407, -0.30470 }, + { 50, 0.18388, 0.27709, -0.32675 }, + { 60, 0.18494, 0.28021, -0.35156 }, + { 70, 0.18611, 0.28342, -0.37915 }, + { 80, 0.18740, 0.28668, -0.40955 }, + { 90, 0.18880, 0.28997, -0.44278 }, + { 100, 0.19032, 0.29326, -0.47888 }, + { 125, 0.19462, 0.30141, -0.58204 }, + { 150, 0.19962, 0.30921, -0.70471 }, + { 175, 0.20525, 0.31647, -0.84901 }, + { 200, 0.21142, 0.32312, -1.0182 }, + { 225, 0.21807, 0.32909, -1.2168 }, + { 250, 0.22511, 0.33439, -1.4512 }, + { 275, 0.23247, 0.33904, -1.7298 }, + { 300, 0.24010, 0.34308, -2.0637 }, + { 325, 0.24702, 0.34655, -2.4681 }, + { 350, 0.25591, 0.34951, -2.9641 }, + { 375, 0.26400, 0.35200, -3.5814 }, + { 400, 0.27218, 0.35407, -4.3633 }, + { 425, 0.28039, 0.35577, -5.3762 }, + { 450, 0.28863, 0.35714, -6.7262 }, + { 475, 0.29685, 0.35823, -8.5955 }, + { 500, 0.30505, 0.35907, -11.324 }, + { 525, 0.31320, 0.35968, -15.628 }, + { 550, 0.32129, 0.36011, -23.325 }, + { 575, 0.32931, 0.36038, -40.770 }, + { 600, 0.33724, 0.36051, -116.45 } + }; + + constexpr double tint_scale = -3000.0; + + double temperature = 0; + double computed_tint = 0; + + // Convert to uv space. + double u = 2.0 * white_xy[0] / (1.5 - white_xy[0] + 6.0 * white_xy[1]); + double v = 3.0 * white_xy[1] / (1.5 - white_xy[0] + 6.0 * white_xy[1]); + + // Search for line pair coordinate is between. + double last_dt = 0.0; + double last_dv = 0.0; + double last_du = 0.0; + + for (uint32_t index = 1; index <= 30; ++index) { + // Convert slope to delta-u and delta-v, with length 1. + double du = 1.0; + double dv = temp_table[index].t; + double len = sqrt(1.0 + dv * dv); + du /= len; + dv /= len; + + // Find delta from black body point to test coordinate. + double uu = u - temp_table[index].u; + double vv = v - temp_table[index].v; + + // Find distance above or below line. + double dt = -uu * dv + vv * du; + + // If below line, we have found line pair. + if (dt <= 0.0 || index == 30) { + // Find fractional weight of two lines. + if (dt > 0.0) { + dt = 0.0; + } + + dt = -dt; + + double f; + + if (index == 1) { + f = 0.0; + } else { + f = dt / (last_dt + dt); + } + + // Interpolate the temperature. + temperature = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); + + // Find delta from black body point to test coordinate. + uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f)); + vv = v - (temp_table [index - 1].v * f + temp_table [index].v * (1.0 - f)); + // Interpolate vectors along slope. + du = du * (1.0 - f) + last_du * f; + dv = dv * (1.0 - f) + last_dv * f; + len = sqrt (du * du + dv * dv); + du /= len; + dv /= len; + + // Find distance along slope. + computed_tint = (uu * du + vv * dv) * tint_scale; + break; + } + + // Try next line pair. + last_dt = dt; + last_du = du; + last_dv = dv; + } + + if (temp != nullptr) { + *temp = temperature; + } + + if (tint != nullptr) { + *tint = computed_tint; + } +} + +} + +struct DCPProfile::ApplyState::Data { + double pro_photo[3][3]; + double work[3][3]; + bool already_pro_photo; + bool use_tone_curve; + bool apply_look_table; + float bl_scale; +}; + +DCPProfile::ApplyState::ApplyState() : + data(new Data{}) +{ +} + +DCPProfile::ApplyState::~ApplyState() +{ } DCPProfile::DCPProfile(const Glib::ustring& filename) : @@ -633,6 +466,266 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : BASELINE_EXPOSURE_OFFSET = 51109 }; + static const float adobe_camera_raw_default_curve[] = { + 0.00000f, 0.00078f, 0.00160f, 0.00242f, + 0.00314f, 0.00385f, 0.00460f, 0.00539f, + 0.00623f, 0.00712f, 0.00806f, 0.00906f, + 0.01012f, 0.01122f, 0.01238f, 0.01359f, + 0.01485f, 0.01616f, 0.01751f, 0.01890f, + 0.02033f, 0.02180f, 0.02331f, 0.02485f, + 0.02643f, 0.02804f, 0.02967f, 0.03134f, + 0.03303f, 0.03475f, 0.03648f, 0.03824f, + 0.04002f, 0.04181f, 0.04362f, 0.04545f, + 0.04730f, 0.04916f, 0.05103f, 0.05292f, + 0.05483f, 0.05675f, 0.05868f, 0.06063f, + 0.06259f, 0.06457f, 0.06655f, 0.06856f, + 0.07057f, 0.07259f, 0.07463f, 0.07668f, + 0.07874f, 0.08081f, 0.08290f, 0.08499f, + 0.08710f, 0.08921f, 0.09134f, 0.09348f, + 0.09563f, 0.09779f, 0.09996f, 0.10214f, + 0.10433f, 0.10652f, 0.10873f, 0.11095f, + 0.11318f, 0.11541f, 0.11766f, 0.11991f, + 0.12218f, 0.12445f, 0.12673f, 0.12902f, + 0.13132f, 0.13363f, 0.13595f, 0.13827f, + 0.14061f, 0.14295f, 0.14530f, 0.14765f, + 0.15002f, 0.15239f, 0.15477f, 0.15716f, + 0.15956f, 0.16197f, 0.16438f, 0.16680f, + 0.16923f, 0.17166f, 0.17410f, 0.17655f, + 0.17901f, 0.18148f, 0.18395f, 0.18643f, + 0.18891f, 0.19141f, 0.19391f, 0.19641f, + 0.19893f, 0.20145f, 0.20398f, 0.20651f, + 0.20905f, 0.21160f, 0.21416f, 0.21672f, + 0.21929f, 0.22185f, 0.22440f, 0.22696f, + 0.22950f, 0.23204f, 0.23458f, 0.23711f, + 0.23963f, 0.24215f, 0.24466f, 0.24717f, + 0.24967f, 0.25216f, 0.25465f, 0.25713f, + 0.25961f, 0.26208f, 0.26454f, 0.26700f, + 0.26945f, 0.27189f, 0.27433f, 0.27676f, + 0.27918f, 0.28160f, 0.28401f, 0.28641f, + 0.28881f, 0.29120f, 0.29358f, 0.29596f, + 0.29833f, 0.30069f, 0.30305f, 0.30540f, + 0.30774f, 0.31008f, 0.31241f, 0.31473f, + 0.31704f, 0.31935f, 0.32165f, 0.32395f, + 0.32623f, 0.32851f, 0.33079f, 0.33305f, + 0.33531f, 0.33756f, 0.33981f, 0.34205f, + 0.34428f, 0.34650f, 0.34872f, 0.35093f, + 0.35313f, 0.35532f, 0.35751f, 0.35969f, + 0.36187f, 0.36404f, 0.36620f, 0.36835f, + 0.37050f, 0.37264f, 0.37477f, 0.37689f, + 0.37901f, 0.38112f, 0.38323f, 0.38533f, + 0.38742f, 0.38950f, 0.39158f, 0.39365f, + 0.39571f, 0.39777f, 0.39982f, 0.40186f, + 0.40389f, 0.40592f, 0.40794f, 0.40996f, + 0.41197f, 0.41397f, 0.41596f, 0.41795f, + 0.41993f, 0.42191f, 0.42388f, 0.42584f, + 0.42779f, 0.42974f, 0.43168f, 0.43362f, + 0.43554f, 0.43747f, 0.43938f, 0.44129f, + 0.44319f, 0.44509f, 0.44698f, 0.44886f, + 0.45073f, 0.45260f, 0.45447f, 0.45632f, + 0.45817f, 0.46002f, 0.46186f, 0.46369f, + 0.46551f, 0.46733f, 0.46914f, 0.47095f, + 0.47275f, 0.47454f, 0.47633f, 0.47811f, + 0.47989f, 0.48166f, 0.48342f, 0.48518f, + 0.48693f, 0.48867f, 0.49041f, 0.49214f, + 0.49387f, 0.49559f, 0.49730f, 0.49901f, + 0.50072f, 0.50241f, 0.50410f, 0.50579f, + 0.50747f, 0.50914f, 0.51081f, 0.51247f, + 0.51413f, 0.51578f, 0.51742f, 0.51906f, + 0.52069f, 0.52232f, 0.52394f, 0.52556f, + 0.52717f, 0.52878f, 0.53038f, 0.53197f, + 0.53356f, 0.53514f, 0.53672f, 0.53829f, + 0.53986f, 0.54142f, 0.54297f, 0.54452f, + 0.54607f, 0.54761f, 0.54914f, 0.55067f, + 0.55220f, 0.55371f, 0.55523f, 0.55673f, + 0.55824f, 0.55973f, 0.56123f, 0.56271f, + 0.56420f, 0.56567f, 0.56715f, 0.56861f, + 0.57007f, 0.57153f, 0.57298f, 0.57443f, + 0.57587f, 0.57731f, 0.57874f, 0.58017f, + 0.58159f, 0.58301f, 0.58443f, 0.58583f, + 0.58724f, 0.58864f, 0.59003f, 0.59142f, + 0.59281f, 0.59419f, 0.59556f, 0.59694f, + 0.59830f, 0.59966f, 0.60102f, 0.60238f, + 0.60373f, 0.60507f, 0.60641f, 0.60775f, + 0.60908f, 0.61040f, 0.61173f, 0.61305f, + 0.61436f, 0.61567f, 0.61698f, 0.61828f, + 0.61957f, 0.62087f, 0.62216f, 0.62344f, + 0.62472f, 0.62600f, 0.62727f, 0.62854f, + 0.62980f, 0.63106f, 0.63232f, 0.63357f, + 0.63482f, 0.63606f, 0.63730f, 0.63854f, + 0.63977f, 0.64100f, 0.64222f, 0.64344f, + 0.64466f, 0.64587f, 0.64708f, 0.64829f, + 0.64949f, 0.65069f, 0.65188f, 0.65307f, + 0.65426f, 0.65544f, 0.65662f, 0.65779f, + 0.65897f, 0.66013f, 0.66130f, 0.66246f, + 0.66362f, 0.66477f, 0.66592f, 0.66707f, + 0.66821f, 0.66935f, 0.67048f, 0.67162f, + 0.67275f, 0.67387f, 0.67499f, 0.67611f, + 0.67723f, 0.67834f, 0.67945f, 0.68055f, + 0.68165f, 0.68275f, 0.68385f, 0.68494f, + 0.68603f, 0.68711f, 0.68819f, 0.68927f, + 0.69035f, 0.69142f, 0.69249f, 0.69355f, + 0.69461f, 0.69567f, 0.69673f, 0.69778f, + 0.69883f, 0.69988f, 0.70092f, 0.70196f, + 0.70300f, 0.70403f, 0.70506f, 0.70609f, + 0.70711f, 0.70813f, 0.70915f, 0.71017f, + 0.71118f, 0.71219f, 0.71319f, 0.71420f, + 0.71520f, 0.71620f, 0.71719f, 0.71818f, + 0.71917f, 0.72016f, 0.72114f, 0.72212f, + 0.72309f, 0.72407f, 0.72504f, 0.72601f, + 0.72697f, 0.72794f, 0.72890f, 0.72985f, + 0.73081f, 0.73176f, 0.73271f, 0.73365f, + 0.73460f, 0.73554f, 0.73647f, 0.73741f, + 0.73834f, 0.73927f, 0.74020f, 0.74112f, + 0.74204f, 0.74296f, 0.74388f, 0.74479f, + 0.74570f, 0.74661f, 0.74751f, 0.74842f, + 0.74932f, 0.75021f, 0.75111f, 0.75200f, + 0.75289f, 0.75378f, 0.75466f, 0.75555f, + 0.75643f, 0.75730f, 0.75818f, 0.75905f, + 0.75992f, 0.76079f, 0.76165f, 0.76251f, + 0.76337f, 0.76423f, 0.76508f, 0.76594f, + 0.76679f, 0.76763f, 0.76848f, 0.76932f, + 0.77016f, 0.77100f, 0.77183f, 0.77267f, + 0.77350f, 0.77432f, 0.77515f, 0.77597f, + 0.77680f, 0.77761f, 0.77843f, 0.77924f, + 0.78006f, 0.78087f, 0.78167f, 0.78248f, + 0.78328f, 0.78408f, 0.78488f, 0.78568f, + 0.78647f, 0.78726f, 0.78805f, 0.78884f, + 0.78962f, 0.79040f, 0.79118f, 0.79196f, + 0.79274f, 0.79351f, 0.79428f, 0.79505f, + 0.79582f, 0.79658f, 0.79735f, 0.79811f, + 0.79887f, 0.79962f, 0.80038f, 0.80113f, + 0.80188f, 0.80263f, 0.80337f, 0.80412f, + 0.80486f, 0.80560f, 0.80634f, 0.80707f, + 0.80780f, 0.80854f, 0.80926f, 0.80999f, + 0.81072f, 0.81144f, 0.81216f, 0.81288f, + 0.81360f, 0.81431f, 0.81503f, 0.81574f, + 0.81645f, 0.81715f, 0.81786f, 0.81856f, + 0.81926f, 0.81996f, 0.82066f, 0.82135f, + 0.82205f, 0.82274f, 0.82343f, 0.82412f, + 0.82480f, 0.82549f, 0.82617f, 0.82685f, + 0.82753f, 0.82820f, 0.82888f, 0.82955f, + 0.83022f, 0.83089f, 0.83155f, 0.83222f, + 0.83288f, 0.83354f, 0.83420f, 0.83486f, + 0.83552f, 0.83617f, 0.83682f, 0.83747f, + 0.83812f, 0.83877f, 0.83941f, 0.84005f, + 0.84069f, 0.84133f, 0.84197f, 0.84261f, + 0.84324f, 0.84387f, 0.84450f, 0.84513f, + 0.84576f, 0.84639f, 0.84701f, 0.84763f, + 0.84825f, 0.84887f, 0.84949f, 0.85010f, + 0.85071f, 0.85132f, 0.85193f, 0.85254f, + 0.85315f, 0.85375f, 0.85436f, 0.85496f, + 0.85556f, 0.85615f, 0.85675f, 0.85735f, + 0.85794f, 0.85853f, 0.85912f, 0.85971f, + 0.86029f, 0.86088f, 0.86146f, 0.86204f, + 0.86262f, 0.86320f, 0.86378f, 0.86435f, + 0.86493f, 0.86550f, 0.86607f, 0.86664f, + 0.86720f, 0.86777f, 0.86833f, 0.86889f, + 0.86945f, 0.87001f, 0.87057f, 0.87113f, + 0.87168f, 0.87223f, 0.87278f, 0.87333f, + 0.87388f, 0.87443f, 0.87497f, 0.87552f, + 0.87606f, 0.87660f, 0.87714f, 0.87768f, + 0.87821f, 0.87875f, 0.87928f, 0.87981f, + 0.88034f, 0.88087f, 0.88140f, 0.88192f, + 0.88244f, 0.88297f, 0.88349f, 0.88401f, + 0.88453f, 0.88504f, 0.88556f, 0.88607f, + 0.88658f, 0.88709f, 0.88760f, 0.88811f, + 0.88862f, 0.88912f, 0.88963f, 0.89013f, + 0.89063f, 0.89113f, 0.89163f, 0.89212f, + 0.89262f, 0.89311f, 0.89360f, 0.89409f, + 0.89458f, 0.89507f, 0.89556f, 0.89604f, + 0.89653f, 0.89701f, 0.89749f, 0.89797f, + 0.89845f, 0.89892f, 0.89940f, 0.89987f, + 0.90035f, 0.90082f, 0.90129f, 0.90176f, + 0.90222f, 0.90269f, 0.90316f, 0.90362f, + 0.90408f, 0.90454f, 0.90500f, 0.90546f, + 0.90592f, 0.90637f, 0.90683f, 0.90728f, + 0.90773f, 0.90818f, 0.90863f, 0.90908f, + 0.90952f, 0.90997f, 0.91041f, 0.91085f, + 0.91130f, 0.91173f, 0.91217f, 0.91261f, + 0.91305f, 0.91348f, 0.91392f, 0.91435f, + 0.91478f, 0.91521f, 0.91564f, 0.91606f, + 0.91649f, 0.91691f, 0.91734f, 0.91776f, + 0.91818f, 0.91860f, 0.91902f, 0.91944f, + 0.91985f, 0.92027f, 0.92068f, 0.92109f, + 0.92150f, 0.92191f, 0.92232f, 0.92273f, + 0.92314f, 0.92354f, 0.92395f, 0.92435f, + 0.92475f, 0.92515f, 0.92555f, 0.92595f, + 0.92634f, 0.92674f, 0.92713f, 0.92753f, + 0.92792f, 0.92831f, 0.92870f, 0.92909f, + 0.92947f, 0.92986f, 0.93025f, 0.93063f, + 0.93101f, 0.93139f, 0.93177f, 0.93215f, + 0.93253f, 0.93291f, 0.93328f, 0.93366f, + 0.93403f, 0.93440f, 0.93478f, 0.93515f, + 0.93551f, 0.93588f, 0.93625f, 0.93661f, + 0.93698f, 0.93734f, 0.93770f, 0.93807f, + 0.93843f, 0.93878f, 0.93914f, 0.93950f, + 0.93986f, 0.94021f, 0.94056f, 0.94092f, + 0.94127f, 0.94162f, 0.94197f, 0.94231f, + 0.94266f, 0.94301f, 0.94335f, 0.94369f, + 0.94404f, 0.94438f, 0.94472f, 0.94506f, + 0.94540f, 0.94573f, 0.94607f, 0.94641f, + 0.94674f, 0.94707f, 0.94740f, 0.94774f, + 0.94807f, 0.94839f, 0.94872f, 0.94905f, + 0.94937f, 0.94970f, 0.95002f, 0.95035f, + 0.95067f, 0.95099f, 0.95131f, 0.95163f, + 0.95194f, 0.95226f, 0.95257f, 0.95289f, + 0.95320f, 0.95351f, 0.95383f, 0.95414f, + 0.95445f, 0.95475f, 0.95506f, 0.95537f, + 0.95567f, 0.95598f, 0.95628f, 0.95658f, + 0.95688f, 0.95718f, 0.95748f, 0.95778f, + 0.95808f, 0.95838f, 0.95867f, 0.95897f, + 0.95926f, 0.95955f, 0.95984f, 0.96013f, + 0.96042f, 0.96071f, 0.96100f, 0.96129f, + 0.96157f, 0.96186f, 0.96214f, 0.96242f, + 0.96271f, 0.96299f, 0.96327f, 0.96355f, + 0.96382f, 0.96410f, 0.96438f, 0.96465f, + 0.96493f, 0.96520f, 0.96547f, 0.96574f, + 0.96602f, 0.96629f, 0.96655f, 0.96682f, + 0.96709f, 0.96735f, 0.96762f, 0.96788f, + 0.96815f, 0.96841f, 0.96867f, 0.96893f, + 0.96919f, 0.96945f, 0.96971f, 0.96996f, + 0.97022f, 0.97047f, 0.97073f, 0.97098f, + 0.97123f, 0.97149f, 0.97174f, 0.97199f, + 0.97223f, 0.97248f, 0.97273f, 0.97297f, + 0.97322f, 0.97346f, 0.97371f, 0.97395f, + 0.97419f, 0.97443f, 0.97467f, 0.97491f, + 0.97515f, 0.97539f, 0.97562f, 0.97586f, + 0.97609f, 0.97633f, 0.97656f, 0.97679f, + 0.97702f, 0.97725f, 0.97748f, 0.97771f, + 0.97794f, 0.97817f, 0.97839f, 0.97862f, + 0.97884f, 0.97907f, 0.97929f, 0.97951f, + 0.97973f, 0.97995f, 0.98017f, 0.98039f, + 0.98061f, 0.98082f, 0.98104f, 0.98125f, + 0.98147f, 0.98168f, 0.98189f, 0.98211f, + 0.98232f, 0.98253f, 0.98274f, 0.98295f, + 0.98315f, 0.98336f, 0.98357f, 0.98377f, + 0.98398f, 0.98418f, 0.98438f, 0.98458f, + 0.98478f, 0.98498f, 0.98518f, 0.98538f, + 0.98558f, 0.98578f, 0.98597f, 0.98617f, + 0.98636f, 0.98656f, 0.98675f, 0.98694f, + 0.98714f, 0.98733f, 0.98752f, 0.98771f, + 0.98789f, 0.98808f, 0.98827f, 0.98845f, + 0.98864f, 0.98882f, 0.98901f, 0.98919f, + 0.98937f, 0.98955f, 0.98973f, 0.98991f, + 0.99009f, 0.99027f, 0.99045f, 0.99063f, + 0.99080f, 0.99098f, 0.99115f, 0.99133f, + 0.99150f, 0.99167f, 0.99184f, 0.99201f, + 0.99218f, 0.99235f, 0.99252f, 0.99269f, + 0.99285f, 0.99302f, 0.99319f, 0.99335f, + 0.99351f, 0.99368f, 0.99384f, 0.99400f, + 0.99416f, 0.99432f, 0.99448f, 0.99464f, + 0.99480f, 0.99495f, 0.99511f, 0.99527f, + 0.99542f, 0.99558f, 0.99573f, 0.99588f, + 0.99603f, 0.99619f, 0.99634f, 0.99649f, + 0.99664f, 0.99678f, 0.99693f, 0.99708f, + 0.99722f, 0.99737f, 0.99751f, 0.99766f, + 0.99780f, 0.99794f, 0.99809f, 0.99823f, + 0.99837f, 0.99851f, 0.99865f, 0.99879f, + 0.99892f, 0.99906f, 0.99920f, 0.99933f, + 0.99947f, 0.99960f, 0.99974f, 0.99987f, + 1.00000f + }; + FILE* const file = g_fopen(filename.c_str(), "rb"); std::unique_ptr tagDir(ExifManager::parseTIFF(file, false)); @@ -855,7 +948,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : if (has_forward_matrix_1) { if (has_forward_matrix_2) { - if (memcmp(forward_matrix_1, forward_matrix_2, sizeof(forward_matrix_1)) != 0) { + if (forward_matrix_1 != forward_matrix_2) { // Common that forward matrices are the same! will_interpolate = true; } @@ -868,7 +961,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : } if (has_color_matrix_1 && has_color_matrix_2) { - if (memcmp(color_matrix_1, color_matrix_2, sizeof(color_matrix_1)) != 0) { + if (color_matrix_1 != color_matrix_2) { will_interpolate = true; } @@ -922,8 +1015,8 @@ void DCPProfile::apply( int preferred_illuminant, const Glib::ustring& working_space, const ColorTemp& white_balance, - double pre_mul[3], - double cam_wb_matrix[3][3], + const Triple& pre_mul, + const Matrix& cam_wb_matrix, bool use_tone_curve, bool apply_hue_sat_map, bool apply_look_table @@ -931,10 +1024,10 @@ void DCPProfile::apply( { const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); - double xyz_cam[3][3]; // Camera RGB to XYZ D50 matrix + Matrix xyz_cam; // Camera RGB to XYZ D50 matrix makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam); - const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); + const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); if (delta_base.empty()) { apply_hue_sat_map = false; @@ -1057,78 +1150,77 @@ void DCPProfile::apply( } } -void DCPProfile::setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut) +void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out) { - - asOut.useToneCurve = useToneCurve; - asOut.applyLookTable = applyLookTable; - asOut.blScale = 1.0; + as_out.data->use_tone_curve = use_tone_curve; + as_out.data->apply_look_table = apply_look_table; + as_out.data->bl_scale = 1.0; if (look_table.empty()) { - asOut.applyLookTable = false; + as_out.data->apply_look_table = false; } if (!has_tone_curve) { - asOut.useToneCurve = false; + as_out.data->use_tone_curve = false; } - if (has_baseline_exposure_offset && applyBaselineExposure) { - asOut.blScale = powf(2, baseline_exposure_offset); + if (has_baseline_exposure_offset && apply_baseline_exposure) { + as_out.data->bl_scale = powf(2, baseline_exposure_offset); } - if (workingSpace == "ProPhoto") { - asOut.alreadyProPhoto = true; + if (working_space == "ProPhoto") { + as_out.data->already_pro_photo = true; } else { - asOut.alreadyProPhoto = false; + as_out.data->already_pro_photo = false; TMatrix mWork; - mWork = iccStore->workingSpaceMatrix (workingSpace); - memset(asOut.m2ProPhoto, 0, sizeof(asOut.m2ProPhoto)); + mWork = iccStore->workingSpaceMatrix (working_space); + memset(as_out.data->pro_photo, 0, sizeof(as_out.data->pro_photo)); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) { - asOut.m2ProPhoto[i][j] += prophoto_xyz[i][k] * mWork[k][j]; + as_out.data->pro_photo[i][j] += prophoto_xyz[i][k] * mWork[k][j]; } - mWork = iccStore->workingSpaceInverseMatrix (workingSpace); - memset(asOut.m2Work, 0, sizeof(asOut.m2Work)); + mWork = iccStore->workingSpaceInverseMatrix (working_space); + memset(as_out.data->work, 0, sizeof(as_out.data->work)); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) { - asOut.m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + as_out.data->work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; } } } -void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int height, int tileWidth, const ApplyState &asIn) const +void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const ApplyState& as_in) const { #define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) #define CLIP01(a) ((a)>0?((a)<1?(a):1):0) float exp_scale = 1.0; - exp_scale *= asIn.blScale; + exp_scale *= as_in.data->bl_scale; - if (!asIn.useToneCurve && !asIn.applyLookTable) { + if (!as_in.data->use_tone_curve && !as_in.data->apply_look_table) { if (exp_scale == 1.0) { return; } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - rc[y * tileWidth + x] *= exp_scale; - gc[y * tileWidth + x] *= exp_scale; - bc[y * tileWidth + x] *= exp_scale; + rc[y * tile_width + x] *= exp_scale; + gc[y * tile_width + x] *= exp_scale; + bc[y * tile_width + x] *= exp_scale; } } } else { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - float r = rc[y * tileWidth + x]; - float g = gc[y * tileWidth + x]; - float b = bc[y * tileWidth + x]; + float r = rc[y * tile_width + x]; + float g = gc[y * tile_width + x]; + float b = bc[y * tile_width + x]; if (exp_scale != 1.0) { r *= exp_scale; @@ -1138,14 +1230,14 @@ void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int float newr, newg, newb; - if (asIn.alreadyProPhoto) { + if (as_in.data->already_pro_photo) { newr = r; newg = g; newb = b; } else { - newr = asIn.m2ProPhoto[0][0] * r + asIn.m2ProPhoto[0][1] * g + asIn.m2ProPhoto[0][2] * b; - newg = asIn.m2ProPhoto[1][0] * r + asIn.m2ProPhoto[1][1] * g + asIn.m2ProPhoto[1][2] * b; - newb = asIn.m2ProPhoto[2][0] * r + asIn.m2ProPhoto[2][1] * g + asIn.m2ProPhoto[2][2] * b; + newr = as_in.data->pro_photo[0][0] * r + as_in.data->pro_photo[0][1] * g + as_in.data->pro_photo[0][2] * b; + newg = as_in.data->pro_photo[1][0] * r + as_in.data->pro_photo[1][1] * g + as_in.data->pro_photo[1][2] * b; + newb = as_in.data->pro_photo[2][0] * r + as_in.data->pro_photo[2][1] * g + as_in.data->pro_photo[2][2] * b; } // with looktable and tonecurve we need to clip @@ -1153,7 +1245,7 @@ void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int newg = FCLIP(newg); newb = FCLIP(newb); - if (asIn.applyLookTable) { + if (as_in.data->apply_look_table) { float h, s, v; Color::rgb2hsv(newr, newg, newb, h, s, v); h *= 6.f; // RT calculates in [0,1] @@ -1175,220 +1267,142 @@ void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int Color::hsv2rgb( h, s, v, newr, newg, newb); } - if (asIn.useToneCurve) { + if (as_in.data->use_tone_curve) { tone_curve.Apply(newr, newg, newb); } - if (asIn.alreadyProPhoto) { - rc[y * tileWidth + x] = newr; - gc[y * tileWidth + x] = newg; - bc[y * tileWidth + x] = newb; + if (as_in.data->already_pro_photo) { + rc[y * tile_width + x] = newr; + gc[y * tile_width + x] = newg; + bc[y * tile_width + x] = newb; } else { - rc[y * tileWidth + x] = asIn.m2Work[0][0] * newr + asIn.m2Work[0][1] * newg + asIn.m2Work[0][2] * newb; - gc[y * tileWidth + x] = asIn.m2Work[1][0] * newr + asIn.m2Work[1][1] * newg + asIn.m2Work[1][2] * newb; - bc[y * tileWidth + x] = asIn.m2Work[2][0] * newr + asIn.m2Work[2][1] * newg + asIn.m2Work[2][2] * newb; + rc[y * tile_width + x] = as_in.data->work[0][0] * newr + as_in.data->work[0][1] * newg + as_in.data->work[0][2] * newb; + gc[y * tile_width + x] = as_in.data->work[1][0] * newr + as_in.data->work[1][1] * newg + as_in.data->work[1][2] * newb; + bc[y * tile_width + x] = as_in.data->work[2][0] * newr + as_in.data->work[2][1] * newg + as_in.data->work[2][2] * newb; } } } } } -void DCPProfile::dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const +void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const { - constexpr double kTintScale = -3000.0; + bool has_col_1 = has_color_matrix_1; + bool has_col_2 = has_color_matrix_2; - double fTemperature = 0; - double fTint = 0; - - // Convert to uv space. - double u = 2.0 * whiteXY[0] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - double v = 3.0 * whiteXY[1] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - - // Search for line pair coordinate is between. - double last_dt = 0.0; - double last_dv = 0.0; - double last_du = 0.0; - - for (uint32_t index = 1; index <= 30; index++) { - // Convert slope to delta-u and delta-v, with length 1. - double du = 1.0; - double dv = kTempTable [index] . t; - double len = sqrt (1.0 + dv * dv); - du /= len; - dv /= len; - - // Find delta from black body point to test coordinate. - double uu = u - kTempTable [index] . u; - double vv = v - kTempTable [index] . v; - - // Find distance above or below line. - double dt = - uu * dv + vv * du; - - // If below line, we have found line pair. - if (dt <= 0.0 || index == 30) { - // Find fractional weight of two lines. - if (dt > 0.0) { - dt = 0.0; - } - - dt = -dt; - double f; - - if (index == 1) { - f = 0.0; - } else { - f = dt / (last_dt + dt); - } - - // Interpolate the temperature. - fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f + - kTempTable [index ] . r * (1.0 - f)); - - // Find delta from black body point to test coordinate. - uu = u - (kTempTable [index - 1] . u * f + - kTempTable [index ] . u * (1.0 - f)); - vv = v - (kTempTable [index - 1] . v * f + - kTempTable [index ] . v * (1.0 - f)); - // Interpolate vectors along slope. - du = du * (1.0 - f) + last_du * f; - dv = dv * (1.0 - f) + last_dv * f; - len = sqrt (du * du + dv * dv); - du /= len; - dv /= len; - - // Find distance along slope. - fTint = (uu * du + vv * dv) * kTintScale; - break; + if (preferred_illuminant == 1) { + if (has_col_1) { + has_col_2 = false; } - - // Try next line pair. - last_dt = dt; - last_du = du; - last_dv = dv; - } - - if (temp != nullptr) { - *temp = fTemperature; - } - - if (tint != nullptr) { - *tint = fTint; - } -} - -void DCPProfile::dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const -{ - - bool hasCol1 = has_color_matrix_1; - bool hasCol2 = has_color_matrix_2; - - if (preferredIlluminant == 1) { - if (hasCol1) { - hasCol2 = false; - } - } else if (preferredIlluminant == 2) { - if (hasCol2) { - hasCol1 = false; + } else if (preferred_illuminant == 2) { + if (has_col_2) { + has_col_1 = false; } } - // mix if we have two matrices + // Mix if we have two matrices double mix; + Matrix col; - if (hasCol1 && hasCol2) { + if (has_col_1 && has_col_2) { double wbtemp; /* - Note: we're using DNG SDK reference code for XY to temperature translation to get the exact same mix as + Note: We're using DNG SDK reference code for XY to temperature translation to get the exact same mix as the reference code does. */ - dngref_XYCoord2Temperature(whiteXY, &wbtemp, nullptr); + xyCoordToTemperature(white_xy, &wbtemp, nullptr); if (wbtemp <= temperature_1) { mix = 1.0; } else if (wbtemp >= temperature_2) { mix = 0.0; } else { - double invT = 1.0 / wbtemp; + const double invT = 1.0 / wbtemp; mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2)); } - } - // Interpolate the color matrix. - double mCol[3][3]; - - if (hasCol1 && hasCol2) { - // interpolate + // Interpolate if (mix >= 1.0) { - memcpy(mCol, color_matrix_1, sizeof(mCol)); + col = color_matrix_1; } else if (mix <= 0.0) { - memcpy(mCol, color_matrix_2, sizeof(mCol)); + col = color_matrix_2; } else { - mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, mCol); + mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, col); } - } else if (hasCol1) { - memcpy(mCol, color_matrix_1, sizeof(mCol)); + } else if (has_col_1) { + col = color_matrix_1; } else { - memcpy(mCol, color_matrix_2, sizeof(mCol)); + col = color_matrix_2; } - memcpy(xyzToCamera, mCol, sizeof(mCol)); + xyz_to_camera = col; } -void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const +void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const { - const int kMaxPasses = 30; - double lastXY[2] = { 0.3457, 0.3585 }; // D50 + enum { + MAX_PASSES = 30 + }; - for (int pass = 0; pass < kMaxPasses; pass++) { - double xyzToCamera[3][3]; - dngref_FindXYZtoCamera(lastXY, preferredIlluminant, xyzToCamera); + double last_xy[2] = {0.3457, 0.3585}; // D50 - double invM[3][3], nextXYZ[3], nextXY[2]; - invert3x3(xyzToCamera, invM); - multiply3x3_v3(invM, neutral, nextXYZ); - XYZtoXY(nextXYZ, nextXY); + for (unsigned int pass = 0; pass < MAX_PASSES; ++pass) { + Matrix xyz_to_camera; + findXyztoCamera(last_xy, preferred_illuminant, xyz_to_camera); - if (fabs(nextXY[0] - lastXY[0]) + - fabs(nextXY[1] - lastXY[1]) < 0.0000001) { - XY[0] = nextXY[0]; - XY[1] = nextXY[1]; + Matrix inv_m; + Triple next_xyz; + double next_xy[2]; + invert3x3(xyz_to_camera, inv_m); + multiply3x3_v3(inv_m, neutral, next_xyz); + xyzToXy(next_xyz, next_xy); + + if (fabs(next_xy[0] - last_xy[0]) + + fabs(next_xy[1] - last_xy[1]) < 0.0000001) { + xy[0] = next_xy[0]; + xy[1] = next_xy[1]; return; } // If we reach the limit without converging, we are most likely // in a two value oscillation. So take the average of the last // two estimates and give up. - if (pass == kMaxPasses - 1) { - nextXY[0] = (lastXY[0] + nextXY[0]) * 0.5; - nextXY[1] = (lastXY[1] + nextXY[1]) * 0.5; + if (pass == MAX_PASSES - 1) { + next_xy[0] = (last_xy[0] + next_xy[0]) * 0.5; + next_xy[1] = (last_xy[1] + next_xy[1]) * 0.5; } - lastXY[0] = nextXY[0]; - lastXY[1] = nextXY[1]; + last_xy[0] = next_xy[0]; + last_xy[1] = next_xy[1]; } - XY[0] = lastXY[0]; - XY[1] = lastXY[1]; + xy[0] = last_xy[0]; + xy[1] = last_xy[1]; } -void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const +void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const { - // code adapted from dng_color_spec::FindXYZtoCamera - // note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support) - // we do not support cameracalibration either + // Code adapted from dng_color_spec::FindXYZtoCamera. + // Note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support), + // we do not support cameracalibration either. - double neutral[3]; // same as the DNG "AsShotNeutral" tag if white balance is Camera's own + Triple neutral; // Same as the DNG "AsShotNeutral" tag if white balance is Camera's own { /* A bit messy matrixing and conversions to get the neutral[] array from RT's own white balance which is stored in sRGB space, while the DCP code needs multipliers in CameraRGB space */ double r, g, b; - wb.getMultipliers(r, g, b); + white_balance.getMultipliers(r, g, b); // camWbMatrix == imatrices.xyz_cam - double cam_xyz[3][3]; - invert3x3(camWbMatrix, cam_xyz); - double cam_rgb[3][3]; - multiply3x3(cam_xyz, xyz_sRGB, cam_rgb); + Matrix cam_xyz; + invert3x3(cam_wb_matrix, cam_xyz); + Matrix cam_rgb; + constexpr Matrix xyz_srgb = {{ + {xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]}, + {xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]}, + {xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]} + }}; + multiply3x3(cam_xyz, xyz_srgb, cam_rgb); double camwb_red = cam_rgb[0][0] * r + cam_rgb[0][1] * g + cam_rgb[0][2] * b; double camwb_green = cam_rgb[1][0] * r + cam_rgb[1][1] * g + cam_rgb[1][2] * b; double camwb_blue = cam_rgb[2][0] * r + cam_rgb[2][1] * g + cam_rgb[2][2] * b; @@ -1413,40 +1427,40 @@ void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWb do it, which is a bit different from RT's own white balance model at the time of writing. When RT's white balance can make use of the DCP color matrices we could use that instead. */ double white_xy[2]; - dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); + neutralToXy(neutral, preferred_illuminant, white_xy); - bool hasFwd1 = has_forward_matrix_1; - bool hasFwd2 = has_forward_matrix_2; - bool hasCol1 = has_color_matrix_1; - bool hasCol2 = has_color_matrix_2; + bool has_fwd_1 = has_forward_matrix_1; + bool has_fwd_2 = has_forward_matrix_2; + bool has_col_1 = has_color_matrix_1; + bool has_col_2 = has_color_matrix_2; - if (preferredIlluminant == 1) { - if (hasFwd1) { - hasFwd2 = false; + if (preferred_illuminant == 1) { + if (has_fwd_1) { + has_fwd_2 = false; } - if (hasCol1) { - hasCol2 = false; + if (has_col_1) { + has_col_2 = false; } - } else if (preferredIlluminant == 2) { - if (hasFwd2) { - hasFwd1 = false; + } else if (preferred_illuminant == 2) { + if (has_fwd_2) { + has_fwd_1 = false; } - if (hasCol2) { - hasCol1 = false; + if (has_col_2) { + has_col_1 = false; } } - // mix if we have two matrices + // Mix if we have two matrices double mix = 1.0; - if ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { + if ((has_col_1 && has_col_2) || (has_fwd_1 && has_fwd_2)) { double wbtemp; /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here typically does not affect the result too much, ie it's probably not strictly necessary to use the DNG reference code here, but we do it for now. */ - dngref_XYCoord2Temperature(white_xy, &wbtemp, nullptr); + xyCoordToTemperature(white_xy, &wbtemp, nullptr); if (wbtemp <= temperature_1) { mix = 1.0; @@ -1459,21 +1473,21 @@ void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWb } // Colormatrix - double mCol[3][3]; + Matrix color_matrix; - if (hasCol1 && hasCol2) { + if (has_col_1 && has_col_2) { // interpolate if (mix >= 1.0) { - memcpy(mCol, color_matrix_1, sizeof(mCol)); + color_matrix = color_matrix_1; } else if (mix <= 0.0) { - memcpy(mCol, color_matrix_2, sizeof(mCol)); + color_matrix = color_matrix_2; } else { - mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, mCol); + mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, color_matrix); } - } else if (hasCol1) { - memcpy(mCol, color_matrix_1, sizeof(mCol)); + } else if (has_col_1) { + color_matrix = color_matrix_1; } else { - memcpy(mCol, color_matrix_2, sizeof(mCol)); + color_matrix = color_matrix_2; } /* @@ -1484,49 +1498,53 @@ void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWb will show incorrect color. */ - double white_xyz[3]; - XYtoXYZ(white_xy, white_xyz); + Triple white_xyz; + xyToXyz(white_xy, white_xyz); - double cam_xyz[3][3]; + Matrix cam_xyz; - if (hasFwd1 || hasFwd2) { - // always prefer ForwardMatrix ahead of ColorMatrix - double mFwd[3][3]; + if (has_fwd_1 || has_fwd_2) { + // Always prefer ForwardMatrix to ColorMatrix + Matrix fwd; - if (hasFwd1 && hasFwd2) { - // interpolate + if (has_fwd_1 && has_fwd_2) { + // Interpolate if (mix >= 1.0) { - memcpy(mFwd, forward_matrix_1, sizeof(mFwd)); + fwd = forward_matrix_1; } else if (mix <= 0.0) { - memcpy(mFwd, forward_matrix_2, sizeof(mFwd)); + fwd = forward_matrix_2; } else { - mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, mFwd); + mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, fwd); } - } else if (hasFwd1) { - memcpy(mFwd, forward_matrix_1, sizeof(mFwd)); + } else if (has_fwd_1) { + fwd = forward_matrix_1; } else { - memcpy(mFwd, forward_matrix_2, sizeof(mFwd)); + fwd = forward_matrix_2; } // adapted from dng_color_spec::SetWhiteXY - double CameraWhite[3]; - multiply3x3_v3(mCol, white_xyz, CameraWhite); + Triple camera_white; + multiply3x3_v3(color_matrix, white_xyz, camera_white); - double whiteDiag[3][3] = {{CameraWhite[0], 0, 0}, {0, CameraWhite[1], 0}, {0, 0, CameraWhite[2]}}; - double whiteDiagInv[3][3]; - invert3x3(whiteDiag, whiteDiagInv); + const Matrix white_diag = {{ + {camera_white[0], 0, 0}, + {0, camera_white[1], 0}, + {0, 0, camera_white[2]} + }}; + Matrix white_diag_inv; + invert3x3(white_diag, white_diag_inv); - double xyz_cam[3][3]; - multiply3x3(mFwd, whiteDiagInv, xyz_cam); + Matrix xyz_cam; + multiply3x3(fwd, white_diag_inv, xyz_cam); invert3x3(xyz_cam, cam_xyz); } else { - double whiteMatrix[3][3]; - const double white_d50[3] = { 0.3457, 0.3585, 0.2958 }; // D50 - mapWhiteMatrix(white_d50, white_xyz, whiteMatrix); - multiply3x3(mCol, whiteMatrix, cam_xyz); + Matrix white_matrix; + const Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50 + mapWhiteMatrix(white_d50, white_xyz, white_matrix); + multiply3x3(color_matrix, white_matrix, cam_xyz); } - // convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM + // Convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM { // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix @@ -1534,47 +1552,52 @@ void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWb int i, j, k; // Multiply out XYZ colorspace - double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + double cam_rgb[3][3] = {}; - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) - for (k = 0; k < 3; k++) { + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; } + } + } - // Normalize cam_rgb so that: cam_rgb * (1,1,1) is (1,1,1,1) + // Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1) double num; - for (i = 0; i < 3; i++) { - for (num = j = 0; j < 3; j++) { + for (i = 0; i < 3; ++i) { + for (num = j = 0; j < 3; ++j) { num += cam_rgb[i][j]; } - for (j = 0; j < 3; j++) { + for (j = 0; j < 3; ++j) { cam_rgb[i][j] /= num; } } - double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - RawImageSource::inverse33 (cam_rgb, rgb_cam); + double rgb_cam[3][3] = {}; + RawImageSource::inverse33(cam_rgb, rgb_cam); - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) { - mXYZCAM[i][j] = 0; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + xyz_cam[i][j] = 0; } + } - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) - for (k = 0; k < 3; k++) { - mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { + xyz_cam[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; } + } + } } } -std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const +std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const { if (deltas_1.empty()) { - return std::vector(); + return std::vector(); } if (deltas_2.empty()) { @@ -1627,7 +1650,7 @@ std::vector DCPProfile::makeHueSatMap(const ColorTemp& wh } // Interpolate between the tables. - std::vector res(delta_info.array_count); + std::vector res(delta_info.array_count); const float w1 = mix; const float w2 = 1.0f - w1; @@ -1641,7 +1664,7 @@ std::vector DCPProfile::makeHueSatMap(const ColorTemp& wh return res; } -void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const +void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const { // Apply the HueSatMap. Ported from Adobes reference implementation. float hue_shift; @@ -1655,7 +1678,7 @@ void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector(h_scaled, 0); - const int s_index0 = max(min(s_scaled, table_info.pc.max_sat_index0), 0); + const int s_index0 = std::max(std::min(s_scaled, table_info.pc.max_sat_index0), 0); int h_index1 = h_index0 + 1; @@ -1670,8 +1693,8 @@ void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector::size_type e00_index = h_index0 * table_info.pc.hue_step + s_index0; - std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; + std::vector::size_type e00_index = h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; const float hue_shift0 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift; const float sat_scale0 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale; @@ -1692,14 +1715,14 @@ void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector(s_scaled, table_info.pc.max_sat_index0), 0); - const int v_index0 = max(min(v_scaled, table_info.pc.max_val_index0), 0); + const int s_index0 = std::max(std::min(s_scaled, table_info.pc.max_sat_index0), 0); + const int v_index0 = std::max(std::min(v_scaled, table_info.pc.max_val_index0), 0); int h_index1 = h_index0 + 1; @@ -1716,10 +1739,10 @@ void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector::size_type e00_index = v_index0 * table_info.pc.val_step + h_index0 * table_info.pc.hue_step + s_index0; - std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; - std::vector::size_type e10_index = e00_index + table_info.pc.val_step; - std::vector::size_type e11_index = e01_index + table_info.pc.val_step; + std::vector::size_type e00_index = v_index0 * table_info.pc.val_step + h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; + std::vector::size_type e10_index = e00_index + table_info.pc.val_step; + std::vector::size_type e11_index = e01_index + table_info.pc.val_step; const float hueShift0 = v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift) @@ -1757,7 +1780,7 @@ void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector #include +#include +#include #include @@ -36,13 +38,18 @@ namespace rtengine class DCPProfile final { public: - struct ApplyState { - double m2ProPhoto[3][3]; - double m2Work[3][3]; - bool alreadyProPhoto; - bool useToneCurve; - bool applyLookTable; - float blScale; + class ApplyState final + { + public: + ApplyState(); + ~ApplyState(); + + private: + struct Data; + + std::unique_ptr data; + + friend class DCPProfile; }; struct Illuminants { @@ -53,6 +60,9 @@ public: bool will_interpolate; }; + using Triple = std::array; + using Matrix = std::array; + DCPProfile(const Glib::ustring& filename); ~DCPProfile(); @@ -68,23 +78,23 @@ public: int preferred_illuminant, const Glib::ustring& working_space, const ColorTemp& white_balance, - double pre_mul[3], - double cam_matrix[3][3], + const Triple& pre_mul, + const Matrix& cam_wb_matrix, bool use_tone_curve = false, bool apply_hue_sat_map = true, bool apply_look_table = false ) const; - void setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut); - void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth, const ApplyState &asIn) const; + void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); + void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; private: - struct HSBModify { + struct HsbModify { float hue_shift; float sat_scale; float val_scale; }; - struct HSDTableInfo { + struct HsdTableInfo { int hue_divisions; int sat_divisions; int val_divisions; @@ -104,15 +114,14 @@ private: } pc; }; - void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; - void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; - void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const; - void makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; - std::vector makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const; - void hsdApply(const HSDTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const; + void findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const; + void neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const; + void makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const; + std::vector makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const; + void hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const; - double color_matrix_1[3][3]; - double color_matrix_2[3][3]; + Matrix color_matrix_1; + Matrix color_matrix_2; bool has_color_matrix_1; bool has_color_matrix_2; bool has_forward_matrix_1; @@ -120,16 +129,16 @@ private: bool has_tone_curve; bool has_baseline_exposure_offset; bool will_interpolate; - double forward_matrix_1[3][3]; - double forward_matrix_2[3][3]; + Matrix forward_matrix_1; + Matrix forward_matrix_2; double temperature_1; double temperature_2; double baseline_exposure_offset; - std::vector deltas_1; - std::vector deltas_2; - std::vector look_table; - HSDTableInfo delta_info; - HSDTableInfo look_info; + std::vector deltas_1; + std::vector deltas_2; + std::vector look_table; + HsdTableInfo delta_info; + HsdTableInfo look_info; short light_source_1; short light_source_2; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 16c7fb21b..1c04f1af3 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -889,7 +889,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima } } -DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp &wb,DCPProfile::ApplyState &as) +DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) { DCPProfile *dcpProf = NULL; cmsHPROFILE dummy; @@ -3727,7 +3727,17 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam if (dcpProf != NULL) { // DCP processing - dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false); + const DCPProfile::Triple pre_mul_row = { + pre_mul[0], + pre_mul[1], + pre_mul[2] + }; + const DCPProfile::Matrix cam_matrix = {{ + {camMatrix[0][0], camMatrix[0][1], camMatrix[0][2]}, + {camMatrix[1][0], camMatrix[1][1], camMatrix[1][2]}, + {camMatrix[2][0], camMatrix[2][1], camMatrix[2][2]} + }}; + dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, false, cmp.applyHueSatMap, false); return; }