Documentation for this module may be created at Module:Color temperature/doc
Documentation for this module may be created at Module:Color temperature/doc
-- Module:Color temperature
local p = {}
local function blackbody_xy(T)
-- Formulas from https://github.com/crosscountrycoder/color-converter/blob/main/README.md#polynomial_fitpy-and-polynomial_testpy
-- T must be greater than or equal to 800 (this is enforced elsewhere in the code)
local x, y
if T < 1661 then
x = 0.12790668 + 1311.3574 / T - 1335109.8 / T^2 + 6.9429482e8 / T^3 - 1.4571589e11 / T^4
y = 0.35946988 + 477.95393 / T - 1062716.0 / T^2 + 7.5671541e8 / T^3 - 1.8700243e11 / T^4
elseif T < 4328 then
x = 0.21594484 + 460.83273 / T + 1497568.7 / T^2 - 3.3177634e9 / T^3 + 1.9306612e12 / T^4
y = 0.15480888 + 1394.6527 / T - 2259297.6 / T^2 + 8.4916936e8 / T^3 + 3.1769991e11 / T^4
else
x = 0.23994527 + 246.81976 / T + 1707275.0 / T^2 - 5.4391967e8 / T^3 - 5.0736771e12 / T^4
y = 0.23417818 + 359.64997 / T + 2585341.6 / T^2 - 8.1436004e9 / T^3 + 4.5501218e12 / T^4
end
return x, y
end
local function xy_to_XYZ(x, y)
if y == 0 then
return 0, 0, 0
end
local Y = 1
local X = x / y
local Z = (1 - x - y) / y
return X, Y, Z
end
local function XYZ_to_linear_sRGB(X, Y, Z)
local r = 3.2404542 * X - 1.5371385 * Y - 0.4985314 * Z
local g = -0.9692660 * X + 1.8760108 * Y + 0.0415560 * Z
local b = 0.0556434 * X - 0.2040259 * Y + 1.0572252 * Z
return r, g, b
end
local function normalize_rgb(r, g, b)
-- First normalize so the brightest linear RGB channel is 1.
local max_channel = math.max(r, g, b)
if max_channel <= 0 then
return 0, 0, 0
end
r = r / max_channel
g = g / max_channel
b = b / max_channel
-- Then, if needed, compress toward D65 white.
--
-- In linear sRGB, D65 white is (1, 1, 1). This transformation moves
-- the color along the line toward white until the lowest channel reaches 0,
-- while keeping the highest channel at 1.
--
-- Example:
-- (1.0, 0.25, -0.5) -> (1.0, 0.5, 0.0)
local min_channel = math.min(r, g, b)
if min_channel < 0 then
local denominator = 1 - min_channel
r = (r - min_channel) / denominator
g = (g - min_channel) / denominator
b = (b - min_channel) / denominator
end
return r, g, b
end
local function linear_to_srgb(c)
if c <= 0.0031308 then
return 12.92 * c
end
return 1.055 * c^(1 / 2.4) - 0.055
end
local function to_8bit(c)
return math.floor(255 * linear_to_srgb(c) + 0.5)
end
local function rgb_to_hex(r, g, b)
return string.format("%02x%02x%02x", r, g, b)
end
local function temperature_to_rgb(T)
local x, y = blackbody_xy(T)
local X, Y, Z = xy_to_XYZ(x, y)
local r, g, b = XYZ_to_linear_sRGB(X, Y, Z)
r, g, b = normalize_rgb(r, g, b)
return to_8bit(r), to_8bit(g), to_8bit(b)
end
local function get_temperature(frame)
local parent = frame:getParent()
local raw = frame.args[1]
if (not raw or raw == "") and parent then
raw = parent.args[1]
end
return tonumber(raw), raw
end
local function get_arg(frame, name)
local parent = frame:getParent()
local value = frame.args[name]
if (not value or value == "") and parent then
value = parent.args[name]
end
return value
end
function p.hex(frame)
local T, raw = get_temperature(frame)
if not T then
return ""
end
if T < 800 then
return "Error: Temperature must be at least 800 K"
end
local r, g, b = temperature_to_rgb(T)
return rgb_to_hex(r, g, b)
end
function p.rgb(frame)
local T, raw = get_temperature(frame)
if not T then
return ""
end
if T < 800 then
return "Error: Temperature must be at least 800 K"
end
local r, g, b = temperature_to_rgb(T)
return string.format("%d, %d, %d", r, g, b)
end
function p.xy(frame)
local T, raw = get_temperature(frame)
if not T then
return ""
end
if T < 800 then
return "Error: Temperature must be at least 800 K"
end
local x, y = blackbody_xy(T)
return string.format("%.8f, %.8f", x, y)
end
function p.swatch(frame)
local T, raw = get_temperature(frame)
if not T then
return ""
end
if T < 800 then
return "Error: Temperature must be at least 800 K"
end
local text = get_arg(frame, "text")
local r, g, b = temperature_to_rgb(T)
local hex = rgb_to_hex(r, g, b)
if not text or text == "" then
text = mw.language.getContentLanguage():formatNum(T) .. " K"
end
return string.format(
'<span class="mw-no-invert" style="background:gray;padding:1px 1px 1px 0;color:white;border:solid 2px gray;margin:0 0.1em;text-align:center;vertical-align:middle;display:inline;font-family:sans-serif"><span style="padding:1px;margin:0 3px 0 0;background:#%s"> </span><small>%s</small></span>',
hex,
text
)
end
return p
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.