<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.pttlink.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AColor%2Fsandbox</id>
	<title>Module:Color/sandbox - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.pttlink.org/index.php?action=history&amp;feed=atom&amp;title=Module%3AColor%2Fsandbox"/>
	<link rel="alternate" type="text/html" href="https://wiki.pttlink.org/index.php?title=Module:Color/sandbox&amp;action=history"/>
	<updated>2026-05-04T21:38:11Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.5</generator>
	<entry>
		<id>https://wiki.pttlink.org/index.php?title=Module:Color/sandbox&amp;diff=7183&amp;oldid=prev</id>
		<title>Kg7qin: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://wiki.pttlink.org/index.php?title=Module:Color/sandbox&amp;diff=7183&amp;oldid=prev"/>
		<updated>2022-01-21T17:59:57Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left diff-editfont-monospace&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 17:59, 21 January 2022&lt;/td&gt;
				&lt;/tr&gt;
&lt;!-- diff cache key mediawiki:diff::1.12:old-7182:rev-7183 --&gt;
&lt;/table&gt;</summary>
		<author><name>Kg7qin</name></author>
	</entry>
	<entry>
		<id>https://wiki.pttlink.org/index.php?title=Module:Color/sandbox&amp;diff=7182&amp;oldid=prev</id>
		<title>Mediawiki&gt;Ftrebien at 18:55, 19 January 2022</title>
		<link rel="alternate" type="text/html" href="https://wiki.pttlink.org/index.php?title=Module:Color/sandbox&amp;diff=7182&amp;oldid=prev"/>
		<updated>2022-01-19T18:55:30Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local function isempty(v)&lt;br /&gt;
	return v == nil or v == ''&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function hexToRgb(color)&lt;br /&gt;
	local cleanColor = color:gsub(&amp;quot;&amp;amp;#35;&amp;quot;, &amp;quot;#&amp;quot;):match('^[%s#]*(.-)[%s;]*$')&lt;br /&gt;
	if (#cleanColor == 6) then&lt;br /&gt;
		return {&lt;br /&gt;
			r = tonumber(string.sub(cleanColor, 1, 2), 16),&lt;br /&gt;
			g = tonumber(string.sub(cleanColor, 3, 4), 16),&lt;br /&gt;
			b = tonumber(string.sub(cleanColor, 5, 6), 16)&lt;br /&gt;
		}&lt;br /&gt;
	elseif (#cleanColor == 3) then&lt;br /&gt;
		return {&lt;br /&gt;
			r = 17 * tonumber(string.sub(cleanColor, 1, 1), 16),&lt;br /&gt;
			g = 17 * tonumber(string.sub(cleanColor, 2, 2), 16),&lt;br /&gt;
			b = 17 * tonumber(string.sub(cleanColor, 3, 3), 16)&lt;br /&gt;
		}&lt;br /&gt;
	end&lt;br /&gt;
	error(&amp;quot;Invalid hexadecimal color &amp;quot; .. cleanColor, 1)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function round(v)&lt;br /&gt;
	if (v &amp;lt; 0) then&lt;br /&gt;
		return math.ceil(v - 0.5)&lt;br /&gt;
	else&lt;br /&gt;
		return math.floor(v + 0.5)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rgbToHex(r, g, b)&lt;br /&gt;
	return string.format(&amp;quot;%02X%02X%02X&amp;quot;, round(r), round(g), round(b))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rgbToCmyk(r, g, b)&lt;br /&gt;
	if (r &amp;gt; 255 or g &amp;gt; 255 or b &amp;gt; 255 or r &amp;lt; 0 or g &amp;lt; 0 or b &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local c = 1 - r / 255&lt;br /&gt;
	local m = 1 - g / 255&lt;br /&gt;
	local y = 1 - b / 255&lt;br /&gt;
	local k = math.min(c, m, y)&lt;br /&gt;
	if (k == 1) then&lt;br /&gt;
		c = 0&lt;br /&gt;
		m = 0&lt;br /&gt;
		y = 0&lt;br /&gt;
	else&lt;br /&gt;
		local d = 1 - k&lt;br /&gt;
		c = (c - k) / d&lt;br /&gt;
		m = (m - k) / d&lt;br /&gt;
		y = (y - k) / d&lt;br /&gt;
	end&lt;br /&gt;
	return { c = c * 100, m = m * 100, y = y * 100, k = k * 100 }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rgbToHsl(r, g, b)&lt;br /&gt;
	if (r &amp;gt; 255 or g &amp;gt; 255 or b &amp;gt; 255 or r &amp;lt; 0 or g &amp;lt; 0 or b &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local channelMax = math.max(r, g, b)&lt;br /&gt;
	local channelMin = math.min(r, g, b)&lt;br /&gt;
	local range = channelMax - channelMin&lt;br /&gt;
	local h, s&lt;br /&gt;
	if (range == 0) then&lt;br /&gt;
		h = 0&lt;br /&gt;
	elseif (channelMax == r) then&lt;br /&gt;
		h = 60 * ((g - b) / range)&lt;br /&gt;
		if (h &amp;lt; 0) then&lt;br /&gt;
			h = 360 + h&lt;br /&gt;
		end&lt;br /&gt;
	elseif (channelMax == g) then&lt;br /&gt;
		h = 60 * (2 + (b - r) / range)&lt;br /&gt;
	else&lt;br /&gt;
		h = 60 * (4 + (r - g) / range)&lt;br /&gt;
	end&lt;br /&gt;
	local L = channelMax + channelMin&lt;br /&gt;
	if (L == 0 or L == 510) then&lt;br /&gt;
		s = 0&lt;br /&gt;
	else&lt;br /&gt;
		s = 100 * range / math.min(L, 510 - L)&lt;br /&gt;
	end&lt;br /&gt;
	return { h = h, s = s, l = L * 50 / 255 }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rgbToHsv(r, g, b)&lt;br /&gt;
	if (r &amp;gt; 255 or g &amp;gt; 255 or b &amp;gt; 255 or r &amp;lt; 0 or g &amp;lt; 0 or b &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local channelMax = math.max(r, g, b)&lt;br /&gt;
	local channelMin = math.min(r, g, b)&lt;br /&gt;
	local range = channelMax - channelMin&lt;br /&gt;
	local h, s&lt;br /&gt;
	if (range == 0) then&lt;br /&gt;
		h = 0&lt;br /&gt;
	elseif (channelMax == r) then&lt;br /&gt;
		h = 60 * ((g - b) / range)&lt;br /&gt;
		if (h &amp;lt; 0) then&lt;br /&gt;
			h = 360 + h&lt;br /&gt;
		end&lt;br /&gt;
	elseif (channelMax == g) then&lt;br /&gt;
		h = 60 * (2 + (b - r) / range)&lt;br /&gt;
	else&lt;br /&gt;
		h = 60 * (4 + (r - g) / range)&lt;br /&gt;
	end&lt;br /&gt;
	if (channelMax == 0) then&lt;br /&gt;
		s = 0&lt;br /&gt;
	else&lt;br /&gt;
		s = 100 * range / channelMax&lt;br /&gt;
	end&lt;br /&gt;
	return { h = h, s = s, v = channelMax * 100 / 255 }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function hsvToRgb(h, s, v)&lt;br /&gt;
	if (s &amp;gt; 100 or v &amp;gt; 100 or s &amp;lt; 0 or v &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end	&lt;br /&gt;
	local hn = (h / 60 - 6 * math.floor(h / 360))&lt;br /&gt;
	local hi = math.floor(hn)&lt;br /&gt;
	local hr = hn - hi&lt;br /&gt;
	local sn = s / 100&lt;br /&gt;
	local vs = v * 255 / 100&lt;br /&gt;
    local p = vs * (1 - sn);&lt;br /&gt;
    local q = vs * (1 - sn * hr);&lt;br /&gt;
    local t = vs * (1 - sn * (1 - hr));&lt;br /&gt;
    if (hi &amp;lt; 3) then&lt;br /&gt;
		if (hi == 0) then&lt;br /&gt;
			return { r = vs, g = t, b = p }&lt;br /&gt;
		elseif (hi == 1) then&lt;br /&gt;
			return { r = q, g = vs, b = p }&lt;br /&gt;
		else&lt;br /&gt;
			return { r = p, g = vs, b = t }&lt;br /&gt;
		end&lt;br /&gt;
    else&lt;br /&gt;
		if (hi == 3) then&lt;br /&gt;
			return { r = p, g = q, b = vs }&lt;br /&gt;
		elseif (hi == 4) then&lt;br /&gt;
			return { r = t, g = p, b = vs }&lt;br /&gt;
		else&lt;br /&gt;
			return { r = vs, g = p, b = q }&lt;br /&gt;
		end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- c in [0, 255], condition tweaked for no discontinuity&lt;br /&gt;
-- http://entropymine.com/imageworsener/srgbformula/&lt;br /&gt;
local function toLinear(c)&lt;br /&gt;
	if (c &amp;gt; 10.314300250662591) then&lt;br /&gt;
		return math.pow((c + 14.025) / 269.025, 2.4)&lt;br /&gt;
	else&lt;br /&gt;
		return c / 3294.6&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function toNonLinear(c)&lt;br /&gt;
	if (c &amp;gt; 0.00313066844250063) then&lt;br /&gt;
		return 269.025 * math.pow(c, 1.0/2.4) - 14.025&lt;br /&gt;
	else&lt;br /&gt;
		return 3294.6 * c&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function srgbToCielchuvD65o2deg(r, g, b)&lt;br /&gt;
	if (r &amp;gt; 255 or g &amp;gt; 255 or b &amp;gt; 255 or r &amp;lt; 0 or g &amp;lt; 0 or b &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local R = toLinear(r)&lt;br /&gt;
	local G = toLinear(g)&lt;br /&gt;
	local B = toLinear(b)&lt;br /&gt;
	-- https://github.com/w3c/csswg-drafts/issues/5922&lt;br /&gt;
	local X = 0.1804807884018343 * B + 0.357584339383878 * G + 0.41239079926595934 * R&lt;br /&gt;
	local Y = 0.07219231536073371 * B + 0.21263900587151027 * R + 0.715168678767756 * G&lt;br /&gt;
	local Z = 0.01933081871559182 * R + 0.11919477979462598 * G + 0.9505321522496607 * B&lt;br /&gt;
	local L, C, h&lt;br /&gt;
	if (Y &amp;gt; 0.00885645167903563082) then&lt;br /&gt;
		L = 116 * math.pow(Y, 1/3) - 16&lt;br /&gt;
	else&lt;br /&gt;
		L = Y * 903.2962962962962962963&lt;br /&gt;
	end&lt;br /&gt;
	if ((r == g and g == b) or L == 0) then&lt;br /&gt;
		C = 0&lt;br /&gt;
		h = 0&lt;br /&gt;
	else&lt;br /&gt;
		d = X + 3 * Z + 15 * Y&lt;br /&gt;
		if (d == 0) then&lt;br /&gt;
			C = 0&lt;br /&gt;
			h = 0&lt;br /&gt;
		else&lt;br /&gt;
			-- 0.19783... and 0.4631... computed with extra precision from (X,Y,Z) when (R,G,B) = (1,1,1),&lt;br /&gt;
			-- in which case (u,v) ≈ (0,0)&lt;br /&gt;
			local us = 4 * X / d - 0.19783000664283678994&lt;br /&gt;
			local vs = 9 * Y / d - 0.46831999493879099801&lt;br /&gt;
			h = math.atan2(vs, us) * 57.2957795130823208768&lt;br /&gt;
			if (h &amp;lt; 0) then&lt;br /&gt;
				h = h + 360&lt;br /&gt;
			elseif (h == 0) then&lt;br /&gt;
				h = 0 -- ensure zero is positive&lt;br /&gt;
			end&lt;br /&gt;
			C = math.sqrt(us * us + vs * vs) * 13 * L&lt;br /&gt;
			if (C == 0) then&lt;br /&gt;
				C = 0&lt;br /&gt;
				h = 0&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return { L = L, C = C, h = h }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function srgbMix(t, r0, g0, b0, r1, g1, b1)&lt;br /&gt;
	if (t &amp;gt; 1 or t &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Interpolation parameter out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if (r0 &amp;gt; 255 or g0 &amp;gt; 255 or b0 &amp;gt; 255 or r1 &amp;gt; 255 or g1 &amp;gt; 255 or b1 &amp;gt; 255 or r0 &amp;lt; 0 or g0 &amp;lt; 0 or b0 &amp;lt; 0 or r1 &amp;lt; 0 or g1 &amp;lt; 0 or b1 &amp;lt; 0) then&lt;br /&gt;
		error(&amp;quot;Color level out of bounds&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local tc = 1 - t&lt;br /&gt;
	return {&lt;br /&gt;
		r = toNonLinear(tc * toLinear(r0) + t * toLinear(r1)),&lt;br /&gt;
		g = toNonLinear(tc * toLinear(g0) + t * toLinear(g1)),&lt;br /&gt;
		b = toNonLinear(tc * toLinear(b0) + t * toLinear(b1))&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- functions for generating gradients, inspired by OKLCH but not needing gamut mapping&lt;br /&gt;
local function adjustHueToCielch(h)&lt;br /&gt;
	local n = 180 * math.floor(h / 180)&lt;br /&gt;
	local d = h - n&lt;br /&gt;
	if (d &amp;lt; 60) then&lt;br /&gt;
		d = 73.7 * d / 60&lt;br /&gt;
	elseif (d &amp;lt; 120) then		&lt;br /&gt;
		d = 0.6975 * d + 31.85&lt;br /&gt;
	else&lt;br /&gt;
		d = 1.07416666666666666667 * d - 13.35&lt;br /&gt;
	end&lt;br /&gt;
	return n + d&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function unadjustHueFromCielch(h)&lt;br /&gt;
	local n = 180 * math.floor(h / 180)&lt;br /&gt;
	local d = h - n&lt;br /&gt;
	if (d &amp;lt; 73.7) then&lt;br /&gt;
		d = 0.81411126187245590231 * d&lt;br /&gt;
	elseif (d &amp;lt; 115.55) then&lt;br /&gt;
		d = 1.43369175627240143369 * d - 45.66308243727598566308&lt;br /&gt;
	else&lt;br /&gt;
		d = 0.93095422808378588053 * d + 12.42823894491854150504&lt;br /&gt;
	end&lt;br /&gt;
	return n + d&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getLightness(r, g, b)&lt;br /&gt;
	local Y = 0.07219231536073371 * toLinear(b) + 0.21263900587151027 * toLinear(r) + 0.715168678767756 * toLinear(g)&lt;br /&gt;
	if (Y &amp;gt; 0.00885645167903563082) then&lt;br /&gt;
		return 116 * math.pow(Y, 1/3) - 16&lt;br /&gt;
	else&lt;br /&gt;
		return Y * 903.2962962962962962963&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function adjustLightness(L, r, g, b)&lt;br /&gt;
	if (L &amp;gt;= 100) then&lt;br /&gt;
		return { r = 255, g = 255, b = 255 }&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local Yc&lt;br /&gt;
	if (L &amp;gt; 8) then&lt;br /&gt;
		Yc = (L + 16) / 116&lt;br /&gt;
		Yc = Yc * Yc * Yc&lt;br /&gt;
	else&lt;br /&gt;
		Yc = L * 0.00110705645987945385&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local R = toLinear(r)&lt;br /&gt;
	local G = toLinear(g)&lt;br /&gt;
	local B = toLinear(b)&lt;br /&gt;
	local Y = 0.07219231536073371 * B + 0.21263900587151027 * R + 0.715168678767756 * G&lt;br /&gt;
	if (Y &amp;gt; 0) then&lt;br /&gt;
		local scale = Yc / Y&lt;br /&gt;
		R = R * scale&lt;br /&gt;
		G = G * scale&lt;br /&gt;
		B = B * scale&lt;br /&gt;
		local cmax = math.max(R, G, B)&lt;br /&gt;
		if (cmax &amp;gt; 1) then&lt;br /&gt;
			R = R / cmax&lt;br /&gt;
			G = G / cmax&lt;br /&gt;
			B = B / cmax&lt;br /&gt;
			local d = 0.07219231536073371 * (1 - B) + 0.21263900587151027 * (1 - R) + 0.715168678767756 * (1 - G)&lt;br /&gt;
			if (d &amp;lt;= 0) then&lt;br /&gt;
				R = 1&lt;br /&gt;
				G = 1&lt;br /&gt;
				B = 1&lt;br /&gt;
			else&lt;br /&gt;
				local strength = 0.5 -- 1 yields equal lightness&lt;br /&gt;
				local t = (Yc - 0.07219231536073371 * B - 0.21263900587151027 * R - 0.715168678767756 * G) / d&lt;br /&gt;
				R = R + strength * (1 - R) * t&lt;br /&gt;
				G = G + strength * (1 - G) * t&lt;br /&gt;
				B = B + strength * (1 - B) * t&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		R = Yc&lt;br /&gt;
		G = Yc&lt;br /&gt;
		B = Yc&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return { r = toNonLinear(R), g = toNonLinear(G), b = toNonLinear(B) }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function interpolateHue(t, r0, g0, b0, r1, g1, b1, direction)&lt;br /&gt;
	local c0 = rgbToHsv(r0, g0, b0)&lt;br /&gt;
	local c1 = rgbToHsv(r1, g1, b1)&lt;br /&gt;
	&lt;br /&gt;
	if (c0.s == 0) then&lt;br /&gt;
		c0.h = c1.h&lt;br /&gt;
		if (c0.v == 0) then&lt;br /&gt;
			c0.s = c1.s&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if (c1.s == 0) then&lt;br /&gt;
		c1.h = c0.h&lt;br /&gt;
		if (c1.v == 0) then&lt;br /&gt;
			c1.s = c0.s&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local hn0 = c0.h / 360&lt;br /&gt;
	local hn1 = c1.h / 360&lt;br /&gt;
	if (direction == 0) then&lt;br /&gt;
		local dhn = hn1 - hn0&lt;br /&gt;
		if (dhn &amp;gt; 0.5) then&lt;br /&gt;
			dhn = dhn - math.ceil(dhn - 0.5)&lt;br /&gt;
		elseif (dhn &amp;lt; -0.5) then&lt;br /&gt;
			dhn = dhn - math.floor(dhn + 0.5)&lt;br /&gt;
		end&lt;br /&gt;
		if (dhn &amp;gt;= 0) then&lt;br /&gt;
			hn0 = hn0 - math.floor(hn0)&lt;br /&gt;
			hn1 = hn0 + dhn&lt;br /&gt;
		else&lt;br /&gt;
			hn1 = hn1 - math.floor(hn1)&lt;br /&gt;
			hn0 = hn1 - dhn&lt;br /&gt;
		end&lt;br /&gt;
	elseif (direction &amp;gt; 0) then&lt;br /&gt;
		hn1 = 1 - math.ceil(hn1 - hn0) - math.floor(hn0) + hn1&lt;br /&gt;
		hn0 = hn0 - math.floor(hn0)&lt;br /&gt;
	else&lt;br /&gt;
		hn0 = 1 - math.ceil(hn0 - hn1) - math.floor(hn1) + hn0&lt;br /&gt;
		hn1 = hn1 - math.floor(hn1)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if (t &amp;lt; 0) then&lt;br /&gt;
		t = 0&lt;br /&gt;
	elseif (t &amp;gt; 1) then&lt;br /&gt;
		t = 1&lt;br /&gt;
	end&lt;br /&gt;
	local tc = 1 - t&lt;br /&gt;
	local ha = tc * adjustHueToCielch(360 * hn0) + t * adjustHueToCielch(360 * hn1)&lt;br /&gt;
	local c = hsvToRgb(unadjustHueFromCielch(ha), tc * c0.s + t * c1.s, tc * c0.v + t * c1.v)&lt;br /&gt;
	&lt;br /&gt;
	local L0 = getLightness(r0, g0, b0)&lt;br /&gt;
	local L1 = getLightness(r1, g1, b1)&lt;br /&gt;
	local Lc = tc * L0 + t * L1&lt;br /&gt;
	return adjustLightness(Lc, c.r, c.g, c.b)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatToPrecision(value, p)&lt;br /&gt;
	return string.format(&amp;quot;%.&amp;quot; .. p .. &amp;quot;f&amp;quot;, value)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getFractionalZeros(p)&lt;br /&gt;
	if (p &amp;gt; 0) then&lt;br /&gt;
		return &amp;quot;.&amp;quot; .. string.rep(&amp;quot;0&amp;quot;, p)&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function polyMix(t, pal)&lt;br /&gt;
	if (t &amp;lt;= 0) then&lt;br /&gt;
		return pal[1]&lt;br /&gt;
	elseif (t &amp;gt;= 1) then&lt;br /&gt;
		return pal[#pal]&lt;br /&gt;
	end&lt;br /&gt;
	local n, f = math.modf(t * (#pal - 1))&lt;br /&gt;
	if (f == 0) then&lt;br /&gt;
		return pal[n + 1]&lt;br /&gt;
	else&lt;br /&gt;
		local c1 = hexToRgb(pal[n + 1])&lt;br /&gt;
		local c2 = hexToRgb(pal[n + 2])&lt;br /&gt;
		local c = srgbMix(f, c1.r, c1.g, c1.b, c2.r, c2.g, c2.b)&lt;br /&gt;
		return rgbToHex(c.r, c.g, c.b)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sequentialGradient(t, name)&lt;br /&gt;
	local colors = {&lt;br /&gt;
		YlGnBu = { 'FFFFD9', 'EDF8B1', 'C7E9B4', '7FCDBB', '41B6C4', '1D91C0', '225EA8', '253494', '081D58' },&lt;br /&gt;
		YlOrRd = { 'FFFFCC', 'FFEDA0', 'FED976', 'FEB24C', 'FD8D3C', 'FC4E2A', 'E31A1C', 'BD0026', '800026' },&lt;br /&gt;
		PuBuGn = { 'FFF7FB', 'ECE2F0', 'D0D1E6', 'A6BDDB', '67A9CF', '3690C0', '02818A', '016C59', '014636' }&lt;br /&gt;
	}&lt;br /&gt;
	return polyMix(t / 100, colors[name or 'PuBuGn'])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function divergentGradient(t, name)&lt;br /&gt;
	local colors = {&lt;br /&gt;
		RdYlBu = { 'A50026', 'D73027', 'F46D43', 'FDAE61', 'FEE090', 'FFFFBF', 'E0F3F8', 'ABD9E9', '74ADD1', '4575B4', '313695' },&lt;br /&gt;
		RdYlGn = { 'A50026', 'D73027', 'F46D43', 'FDAE61', 'FEE08B', 'FFFFBF', 'D9EF8B', 'A6D96A', '66BD63', '1A9850', '006837' },&lt;br /&gt;
		Spectral = { '9E0142', 'D53E4F', 'F46D43', 'FDAE61', 'FEE08B', 'FFFFBF', 'E6F598', 'ABDDA4', '66C2A5', '3288BD', '5E4FA2' }&lt;br /&gt;
	}&lt;br /&gt;
	return polyMix((t + 100) / 200, colors[name or 'RdYlGn'])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexToRgbTriplet(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex = args[1]&lt;br /&gt;
	if (hex) then&lt;br /&gt;
		local rgb = hexToRgb(hex)&lt;br /&gt;
		return rgb.r .. ', ' .. rgb.g .. ', ' .. rgb.b&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexToCmyk(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex = args[1]&lt;br /&gt;
	if (hex) then&lt;br /&gt;
		local p = tonumber(args.precision) or 0&lt;br /&gt;
		local s = args.pctsign or &amp;quot;1&amp;quot;&lt;br /&gt;
		local rgb = hexToRgb(hex)&lt;br /&gt;
		local cmyk = rgbToCmyk(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
		local fk = formatToPrecision(cmyk.k, p)&lt;br /&gt;
		local fc, fm, fy&lt;br /&gt;
		local fracZeros = getFractionalZeros(p)&lt;br /&gt;
		if (fk == 100  .. fracZeros) then&lt;br /&gt;
			local fZero = 0 .. fracZeros&lt;br /&gt;
			fc = fZero&lt;br /&gt;
			fm = fZero&lt;br /&gt;
			fy = fZero&lt;br /&gt;
		else&lt;br /&gt;
			fc = formatToPrecision(cmyk.c, p)&lt;br /&gt;
			fm = formatToPrecision(cmyk.m, p)&lt;br /&gt;
			fy = formatToPrecision(cmyk.y, p)&lt;br /&gt;
		end&lt;br /&gt;
		if (s ~= &amp;quot;0&amp;quot;) then&lt;br /&gt;
			return fc .. &amp;quot;%, &amp;quot; .. fm .. &amp;quot;%, &amp;quot; .. fy .. &amp;quot;%, &amp;quot; .. fk .. &amp;quot;%&amp;quot;&lt;br /&gt;
		else&lt;br /&gt;
			return fc .. &amp;quot;, &amp;quot; .. fm .. &amp;quot;, &amp;quot; .. fy .. &amp;quot;, &amp;quot; .. fk&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexToHsl(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex = args[1]&lt;br /&gt;
	if (hex) then&lt;br /&gt;
		local p = tonumber(args.precision) or 0&lt;br /&gt;
		local rgb = hexToRgb(hex)&lt;br /&gt;
		local hsl = rgbToHsl(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
		local fl = formatToPrecision(hsl.l, p)&lt;br /&gt;
		local fs, fh&lt;br /&gt;
		local fracZeros = getFractionalZeros(p)&lt;br /&gt;
		local fZero = 0 .. fracZeros&lt;br /&gt;
		if (fl == fZero or fl == 100 .. fracZeros) then&lt;br /&gt;
			fs = fZero&lt;br /&gt;
			fh = fZero&lt;br /&gt;
		else&lt;br /&gt;
			fs = formatToPrecision(hsl.s, p)&lt;br /&gt;
			if (fs == fZero) then&lt;br /&gt;
				fh = fZero&lt;br /&gt;
			else&lt;br /&gt;
				fh = formatToPrecision(hsl.h, p)&lt;br /&gt;
				if (fh == 360 .. fracZeros) then&lt;br /&gt;
					fh = fZero -- handle rounding to 360&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return fh .. &amp;quot;°, &amp;quot; .. fs .. &amp;quot;%, &amp;quot; .. fl .. &amp;quot;%&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexToHsv(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex = args[1]&lt;br /&gt;
	if (hex) then&lt;br /&gt;
		local p = tonumber(args.precision) or 0&lt;br /&gt;
		local rgb = hexToRgb(hex)&lt;br /&gt;
		local hsv = rgbToHsv(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
		local fv = formatToPrecision(hsv.v, p)&lt;br /&gt;
		local fs, fh&lt;br /&gt;
		local fracZeros = getFractionalZeros(p)&lt;br /&gt;
		local fZero = 0 .. fracZeros&lt;br /&gt;
		if (fv == fZero) then&lt;br /&gt;
			fh = fZero&lt;br /&gt;
			fs = fZero&lt;br /&gt;
		else&lt;br /&gt;
			fs = formatToPrecision(hsv.s, p)&lt;br /&gt;
			if (fs == fZero) then&lt;br /&gt;
				fh = fZero&lt;br /&gt;
			else&lt;br /&gt;
				fh = formatToPrecision(hsv.h, p)&lt;br /&gt;
				if (fh == 360 .. fracZeros) then&lt;br /&gt;
					fh = fZero -- handle rounding to 360&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return fh .. &amp;quot;°, &amp;quot; .. fs .. &amp;quot;%, &amp;quot; .. fv .. &amp;quot;%&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexToCielch(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex = args[1]&lt;br /&gt;
	if (hex) then&lt;br /&gt;
		local p = tonumber(args.precision) or 0&lt;br /&gt;
		local rgb = hexToRgb(hex)&lt;br /&gt;
		local LCh = srgbToCielchuvD65o2deg(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
		local fL = formatToPrecision(LCh.L, p)&lt;br /&gt;
		local fC, fh&lt;br /&gt;
		local fracZeros = getFractionalZeros(p)&lt;br /&gt;
		local fZero = 0 .. fracZeros&lt;br /&gt;
		if (fL == fZero or fL == 100 .. fracZeros) then&lt;br /&gt;
			fC = fZero&lt;br /&gt;
			fh = fZero&lt;br /&gt;
		else&lt;br /&gt;
			fC = formatToPrecision(LCh.C, p)&lt;br /&gt;
			if (fC == fZero) then&lt;br /&gt;
				fh = fZero&lt;br /&gt;
			else&lt;br /&gt;
				fh = formatToPrecision(LCh.h, p)&lt;br /&gt;
				if (fh == 360 .. fracZeros) then&lt;br /&gt;
					fh = fZero -- handle rounding to 360&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return fL .. &amp;quot;, &amp;quot; .. fC .. &amp;quot;, &amp;quot; .. fh .. &amp;quot;°&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexMix(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex0 = args[1]&lt;br /&gt;
	local hex1 = args[2]&lt;br /&gt;
	if (isempty(hex0) or isempty(hex1)) then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local t = args[3]&lt;br /&gt;
	if (isempty(t)) then&lt;br /&gt;
		t = 0.5&lt;br /&gt;
	else&lt;br /&gt;
		t = tonumber(t)&lt;br /&gt;
		local min = tonumber(args.min) or 0&lt;br /&gt;
		local max = tonumber(args.max) or 100&lt;br /&gt;
		if (min &amp;gt;= max) then&lt;br /&gt;
			error(&amp;quot;Minimum proportion greater than or equal to maximum&amp;quot;)&lt;br /&gt;
		elseif (t &amp;lt; min) then&lt;br /&gt;
			t = 0&lt;br /&gt;
		elseif (t &amp;gt; max) then&lt;br /&gt;
			t = 1&lt;br /&gt;
		else&lt;br /&gt;
			t = (t - min) / (max - min)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local rgb0 = hexToRgb(hex0)&lt;br /&gt;
	local rgb1 = hexToRgb(hex1)&lt;br /&gt;
	local rgb = srgbMix(t, rgb0.r, rgb0.g, rgb0.b, rgb1.r, rgb1.g, rgb1.b)&lt;br /&gt;
	return rgbToHex(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexInterpolate(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local hex0 = args[1]&lt;br /&gt;
	local hex1 = args[2]&lt;br /&gt;
	if (isempty(hex0) or isempty(hex1)) then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local t = args[3]&lt;br /&gt;
	if (isempty(t)) then&lt;br /&gt;
		t = 0.5&lt;br /&gt;
	else&lt;br /&gt;
		t = tonumber(t)&lt;br /&gt;
		local min = tonumber(args.min) or 0&lt;br /&gt;
		local max = tonumber(args.max) or 100&lt;br /&gt;
		if (min &amp;gt;= max) then&lt;br /&gt;
			error(&amp;quot;Minimum proportion greater than or equal to maximum&amp;quot;)&lt;br /&gt;
		elseif (t &amp;lt; min) then&lt;br /&gt;
			t = 0&lt;br /&gt;
		elseif (t &amp;gt; max) then&lt;br /&gt;
			t = 1&lt;br /&gt;
		else&lt;br /&gt;
			t = (t - min) / (max - min)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local direction = tonumber(args.direction) or 0&lt;br /&gt;
	local rgb0 = hexToRgb(hex0)&lt;br /&gt;
	local rgb1 = hexToRgb(hex1)&lt;br /&gt;
	local rgb = interpolateHue(t, rgb0.r, rgb0.g, rgb0.b, rgb1.r, rgb1.g, rgb1.b, direction)&lt;br /&gt;
	return rgbToHex(rgb.r, rgb.g, rgb.b)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexSequentialGradient(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local t = args[1]&lt;br /&gt;
	local name = args.name&lt;br /&gt;
	local inv = args.inv&lt;br /&gt;
	local comp = args.comp&lt;br /&gt;
	if (isempty(t)) then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	t = tonumber(t)&lt;br /&gt;
	if (not isempty(inv) and inv ~= &amp;quot;0&amp;quot;) then&lt;br /&gt;
		t = 100 - t&lt;br /&gt;
	end&lt;br /&gt;
	if (not isempty(comp) and comp ~= &amp;quot;0&amp;quot;) then&lt;br /&gt;
		if (comp == &amp;quot;2&amp;quot;) then&lt;br /&gt;
			t = 100 * math.tanh(2 * t - 100)&lt;br /&gt;
		else&lt;br /&gt;
			t = 100 * math.tanh(t / 100)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return sequentialGradient(t, name)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.hexDivergentGradient(frame)&lt;br /&gt;
	local args = frame.args or frame:getParent().args&lt;br /&gt;
	local t = args[1]&lt;br /&gt;
	local name = args.name&lt;br /&gt;
	local inv = args.inv&lt;br /&gt;
	local comp = args.comp&lt;br /&gt;
	if (isempty(t)) then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	t = tonumber(t)&lt;br /&gt;
	if (not isempty(inv) and inv ~= &amp;quot;0&amp;quot;) then&lt;br /&gt;
		t = -t&lt;br /&gt;
	end&lt;br /&gt;
	if (not isempty(comp) and comp ~= &amp;quot;0&amp;quot;) then&lt;br /&gt;
		t = 100 * math.tanh(t / 100)&lt;br /&gt;
	end&lt;br /&gt;
	return divergentGradient(t, name)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Mediawiki&gt;Ftrebien</name></author>
	</entry>
</feed>