/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// We are going to be doing so, so many transforms, so descriptive labels are // critical.
#include"Colorspaces.h"
#include"nsDebug.h" #include"qcms.h"
namespace mozilla::color {
float TfFromLinear(const TransferFunctionDesc& desc, constfloat linear) { float sign = linear < 0.0f ? -1.0f : 1.0f; float l = std::abs(linear); float ret; switch (desc.tfType) { case TransferFunctionDescType::PiecewiseGamma: // When processing sRGB in f16 buffers the numbers can be negative, so // need to preserve the sign. tf = { k * linear | linear // < b // { a * pow(linear, 1/g) - (1-a) | linear >= b
ret = (l < desc.b) ? (l * desc.k)
: (desc.a * powf(l, 1.0f / desc.g) - (desc.a - 1)); break; case TransferFunctionDescType::HLG: // Rec2100 Hybrid-Log Gamma is defined as display-referred with nominal // display white being 1.0 which is encoded as 0.5, and maximum white // as 12.0 which is encoded as 1.0, the spec suggests that displays are // typically set to 1.0=80 cd/m^2 which means 12.0=960 cd/m^2.
ret = l < 1.0f ? 0.5f * sqrtf(l)
: (0.17883277f * logf(l - 0.28466892f) + 0.55991073f); break; case TransferFunctionDescType::PQ: { // Linear is display-referred (i.e. relative to the configured white level // commonly called 'SDR content brightness' or similar) whereas PQ is a // scene-referred brightness value in absolute terms (cd/m^2), so we have // to scale by the brightness of our theoretical reference display. float y = l * (Rec2100ReferenceDisplayWhite / 10000.0f); constfloat m1 = 0.1593017578125f; // (2610.0f / 16384.0f) constfloat m2 = 78.84375f; // (2523.0f / 4096.0f * 128.0f) constfloat c1 = 0.8359375f; // (3424.0f / 4096.0f) constfloat c2 = 18.8515625f; // (2413.0f / 4096.0f * 32.0f) constfloat c3 = 18.6875f; // (2392.0f / 4096.0f * 32.0f)
ret = (c1 + c2 * y * m1) / (1.0f + c3 * y * m1) * m2; break;
}
} return ret * sign;
}
float LinearFromTf(const TransferFunctionDesc& desc, constfloat tf) { float sign = tf < 0.0f ? -1.0f : 1.0f; float t = std::abs(tf); float ret; switch (desc.tfType) { case TransferFunctionDescType::PiecewiseGamma: // When processing sRGB in f16 buffers the numbers can be negative, so // need to preserve the sign.
ret = (t / desc.k < desc.b) ? (t / desc.k)
: powf((t + (desc.a - 1)) / desc.a, desc.g); break; case TransferFunctionDescType::HLG: // Rec2100 Hybrid-Log Gamma is defined as display-referred with nominal // display white being 1.0 which is encoded as 0.5, and maximum white // as 12.0 which is encoded as 1.0, the spec suggests that displays are // typically set to 1.0=80 cd/m^2 which means 12.0=960 cd/m^2.
ret = t < 0.5f ? 4.0f * (t * t)
: (expf((t - 0.55991073f) / 0.17883277f) + 0.28466892f); break; case TransferFunctionDescType::PQ: { // Linear is display-referred (i.e. relative to the configured white level // commonly called 'SDR content brightness' or similar) whereas PQ is a // scene-referred brightness value in absolute terms (cd/m^2), so we have // to scale by the brightness of our theoretical reference display. constfloat linearHdrHeadroom = 10000.0f / Rec2100ReferenceDisplayWhite; constfloat m1 = 0.1593017578125f; // (2610.0f / 16384.0f) constfloat m2 = 78.84375f; // (2523.0f / 4096.0f * 128.0f) constfloat c1 = 0.8359375f; // (3424.0f / 4096.0f) constfloat c2 = 18.8515625f; // (2413.0f / 4096.0f * 32.0f) constfloat c3 = 18.6875f; // (2392.0f / 4096.0f * 32.0f)
ret =
linearHdrHeadroom *
(std::max(0.0f, t * (1.0f / m2) - c1) / (c2 - c3 * t * (1.0f / m2))) *
(1.0f / m1); break;
}
} return ret * sign;
}
// -
mat3 YuvFromRgb(const YuvLumaCoeffs& yc) { // Y is always [0,1] // U and V are signed, and could be either [-1,+1] or [-0.5,+0.5]. // Specs generally use [-0.5,+0.5], so we use that too. // E.g. // y = 0.2126*r + 0.7152*g + 0.0722*b // u = (b - y) / (u_range = u_max - u_min) // u_min = -u_max // = (b - y) / (u(0,0,1) - u(1,1,0)) // = (b - y) / (2 * u(0,0,1)) // = (b - y) / (2 * u.b)) // = (b - y) / (2 * (1 - 0.0722)) // = (-0.2126*r + -0.7152*g + (1-0.0722)*b) / 1.8556 // v = (r - y) / 1.5748; // = ((1-0.2126)*r + -0.7152*g + -0.0722*b) / 1.5748 constauto y = vec3({yc.r, yc.g, yc.b}); constauto u = vec3({0, 0, 1}) - y; constauto v = vec3({1, 0, 0}) - y;
// From rows: return mat3({y, u / (2 * u.z()), v / (2 * v.x())});
}
mat3 XyzAFromXyzB_BradfordLinear(const vec2 xyA, const vec2 xyB) { // This is what ICC profiles use to do whitepoint transforms, // because ICC also requires D50 for the Profile Connection Space.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.