Module:Hct/ViewingConditions
跳转到导航
跳转到搜索
此模块的文档可以在Module:Hct/ViewingConditions/doc创建
--[[
Copyright 2021 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]
--[[
This file has been modified. The original version is at
https://github.com/material-foundation/material-color-utilities
]]
local utils = require('Module:Hct/ColorUtils')
local mathU = require('Module:Hct/MathUtils')
--[[
In traditional color spaces, a color can be identified solely by the observer's measurement of
the color. Color appearance models such as CAM16 also use information about the environment where
the color was observed, known as the viewing conditions.
For example, white under the traditional assumption of a midday sun white point is accurately
measured as a slightly chromatic blue by CAM16. (roughly, hue 203, chroma 3, lightness 100)
This class caches intermediate values of the CAM16 conversion process that depend only on
viewing conditions, enabling speed ups.
]]
ViewingConditions = {}
--[[
Parameters are intermediate values of the CAM16 conversion process. Their names are shorthand
for technical color science terminology, this class would not benefit from documenting them
individually. A brief overview is available in the CAM16 specification, and a complete overview
requires a color science textbook, such as Fairchild's Color Appearance Models.
]]
-- private
local function newViewingConditions(n, aw, nbb, ncb, c, nc, rgbD, fl, flRoot, z)
return {
n = n,
aw = aw,
nbb = nbb,
ncb = ncb,
c = c,
nc = nc,
rgbD = rgbD,
fl = fl,
flRoot = flRoot,
z = z,
};
end
--[[
Create ViewingConditions from a simple, physically relevant, set of parameters.
@param whitePoint White point, measured in the XYZ color space. default = D65, or sunny day
afternoon
@param adaptingLuminance The luminance of the adapting field. Informally, how bright it is in
the room where the color is viewed. Can be calculated from lux by multiplying lux by
0.0586. default = 11.72, or 200 lux.
@param backgroundLstar The lightness of the area surrounding the color. measured by L* in
L*a*b*. default = 50.0
@param surround A general description of the lighting surrounding the color. 0 is pitch dark,
like watching a movie in a theater. 1.0 is a dimly light room, like watching TV at home at
night. 2.0 means there is no difference between the lighting on the color and around it.
default = 2.0
@param discountingIlluminant Whether the eye accounts for the tint of the ambient lighting,
such as knowing an apple is still red in green light. default = false, the eye does not
perform this process on self-luminous objects like displays.
]]
local function makeViewingConditions(whitePoint, adaptingLuminance, backgroundLstar, surround, discountingIlluminant)
-- Transform white point XYZ to 'cone'/'rgb' responses
local xyz = whitePoint;
local rW = xyz[1] * 0.401288 + xyz[2] * 0.650173 + xyz[3] * -0.051461;
local gW = xyz[1] * -0.250268 + xyz[2] * 1.204414 + xyz[3] * 0.045854;
local bW = xyz[1] * -0.002079 + xyz[2] * 0.048952 + xyz[3] * 0.953127;
local f = 0.8 + surround / 10.0;
local c = f >= 0.9 and mathU.lerp(0.59, 0.69, ((f - 0.9) * 10.0))
or mathU.lerp(0.525, 0.59, ((f - 0.8) * 10.0));
local d = discountingIlluminant
and 1.0
or f * (1.0 - ((1.0 / 3.6) * math.exp((-adaptingLuminance - 42.0) / 92.0)));
d = mathU.clampDouble(0.0, 1.0, d);
local nc = f;
local rgbD = {
d * (100.0 / rW) + 1.0 - d,
d * (100.0 / gW) + 1.0 - d,
d * (100.0 / bW) + 1.0 - d,
};
local k = 1.0 / (5.0 * adaptingLuminance + 1.0);
local k4 = k * k * k * k;
local k4F = 1.0 - k4;
local fl = (k4 * adaptingLuminance) + (0.1 * k4F * k4F * (mathU.cbrt(5.0 * adaptingLuminance)));
local n = (utils.yFromLstar(backgroundLstar) / whitePoint[2]);
local z = 1.48 + math.sqrt(n);
local nbb = 0.725 / math.pow(n, 0.2);
local ncb = nbb;
local rgbAFactors = {
math.pow(fl * rgbD[1] * rW / 100.0, 0.42),
math.pow(fl * rgbD[2] * gW / 100.0, 0.42),
math.pow(fl * rgbD[3] * bW / 100.0, 0.42),
};
local rgbA = {
(400.0 * rgbAFactors[1]) / (rgbAFactors[1] + 27.13),
(400.0 * rgbAFactors[2]) / (rgbAFactors[2] + 27.13),
(400.0 * rgbAFactors[3]) / (rgbAFactors[3] + 27.13)
};
local aw = (2.0 * rgbA[1] + rgbA[2] + 0.05 * rgbA[3]) * nbb;
return newViewingConditions(n, aw, nbb, ncb, c, nc, rgbD, fl, math.pow(fl, 0.25), z);
end
return makeViewingConditions(
utils.whitePointD65(),
(200.0 / math.pi * utils.yFromLstar(50.0) / 100.0),
50.0,
2.0,
false
);