将Hex转换为Shorthand Hex的正确算法是什么?例如:#996633
很容易转换为#963
。但如果它像#F362C3
那样呢?
我的第一个猜测是,我只取每种颜色的第一个值,然后继续使用。因此#F362C3
变为#F6C
。但我不知道如何在数学上证明这种方法的合理性。
我在网上找到了这个:http://www.ipaste.org/Jch
function hex_to_shorthand($hex, $uppercase=true)
{
// Remove preceding hash if present
if ($hex[0] == "#") $hex = substr($hex, 1);
// If it already is shorthand, nothing more to do here
if (strlen($hex) == 3) return "#$hex";
// If it is not 6 characters long then it is invalid
elseif (strlen($hex) !== 6) return "";
// The final shorthand HEX value
$final = "";
// Get the triplets
$triplets = str_split($hex, 2);
// Go over each triplet separately
foreach ($triplets as $t)
{
// Get the decimal equivalent of triplet
$dec = base_convert($t, 16, 10);
// Find the remainder
$remainder = $dec % 17;
// Go to the nearest decimal that will yield a double nibble
$new = ($dec%17 > 7) ? 17+($dec-$remainder) : $dec-$remainder;
// Convert decimal into HEX
$hex = base_convert($new, 10, 16);
// Add one of the two identical nibbles
$final .= $hex[0];
}
// Return the shorthand HEX colour value
return $uppercase ? strtoupper($final) : strtolower($final);
}
这似乎有点复杂,我不确定它背后的数学理由是什么。因此#F362C3
之类的内容会变成#E6C
,这不是我所期望的。
这样做的正确方法是什么,以及转换如何运作的数学证明是什么?
(上面的代码是PHP但可以应用于任何语言)
答案 0 :(得分:5)
以上代码正确且高效,时间复杂: O(1)。
您需要获取最接近颜色的初始颜色。
因为有RGB代码,所以颜色可以被视为点,在 3D空间中具有整数坐标(0到255之间)强>:
- R -> OX
- G -> OY
- B -> OZ
确定与P'(r',g',b')
(输入)最近的点P(r,g,b)
(输出),其中:
- r', g', b' are in {0=0x00, 17=0x11, 34=0x22, ... 255=0xff}
(because only 0x?? can be reduced to ? in CSS, where 0x represents base 16)
- r, g, b are in {0,1,2,3, ..., 255}
这是什么意思?我们希望3D空间中的 P和P'之间的最小距离。
因此,我们希望D = sqrt( (r-r')^2 + (g-g')^2 + (b-b')^2 )
最小化。这是3D空间中2个点之间的距离。
<强>观测值强>:
每个成员都是>= 0
。
因此,如果我们想要最低D
=&gt;我们想要:
|r-r'|
|g-g'|
|b-b'|
因此,问题归结为:找到最接近给定十六进制数的2个相同字符的最接近的十六进制数。
如您所见,我们在xx和yy =&gt;之间有一个偶数个数字。在xx和yy的相同距离处没有数字(其中y=x+1
)=&gt;我们不需要近似任何东西(例如:我们确定08更接近00而不是11。):
00, 01, 02, 03, 04, 05, 06, 07, 08 -> close to 00
09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11 -> close to 11
11, 12, 13, 14, 15, 16, 17, 18, 19 -> close to 11
1A, 1B, 1C, 1D, 1E, 1F, 20, 21, 22 -> close to 22
...
问题:解决方案是否独一无二?
我们提出这个问题是因为(r-r')^2 = min
可以通过两种不同的方式实现:
r-r1'= sqrt(min)
r-r2'=-sqrt(min)
我们仅针对r'
进行演示,因为其他颜色相似。
我们可以使用两种不同的方法显示唯一性:
让我们添加以上几行:
r1' + r2' = 2*r
其中r1'=xx, r2'=yy => r = zz = (x+y)/2(x+y)/2 in (00, ..., ff)
但因为r'-r
是最小值而r=zz
=&gt; r'=zz
=&gt; r1'=r2'
=&gt; 独特解决方案
根据上述问题的示例,如果我们考虑一个数字,我们找不到2个不同的数字r1'=xx
和r2'=yy
r-r1'
= {{1}因为r2'-r
更接近其中一个。它只能在r
时处于相同的距离,但在这种情况下,r=zz
可以用作r
(因为r'
必须看起来像r'
并且最小距离=> 0距离非常完美)。 =&GT;我们没有2个解决方案(zz
)=&gt; 独特解决方案
g'的类似物,b'=&gt; P'(r',g',b')是唯一的(P没有与P'接近的点。)
您还可以看到 Java代码:
r1'=r2'