Jak*_*son 4 css algorithm math hex
将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);
}
Run Code Online (Sandbox Code Playgroud)
这似乎有点复杂,而且我不确定其背后的数学依据是什么。因此,像#F362C3变#E6C,这不是我期望的。
有什么合适的方法来完成转换,以及如何进行转换的数学证明是什么?
(以上代码是PHP,但可以应用于任何语言)
上面的代码是正确和有效的,具有时间复杂度:O(1) 。
您需要获取最接近初始颜色的颜色。
因为有一个RGB代码,每个颜色可以被认为是一个点,其具有整数的坐标(0到255之间)的3D空间:
- R -> OX
- G -> OY
- B -> OZ
Run Code Online (Sandbox Code Playgroud)
确定与(输入)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}
Run Code Online (Sandbox Code Playgroud)
这是什么意思 ?我们希望在3D空间中P和P'之间的最小距离。
因此,我们希望D = sqrt( (r-r')^2 + (g-g')^2 + (b-b')^2 )达到最低要求。这是3D空间中2个点之间的距离。
Obs:
每个成员都是>= 0。
因此,如果我们想要一个最小值D=>,我们想要:
|r-r'||g-g'||b-b'|因此,问题归结为:找到最接近给定十六进制数的2个相同字符的最接近十六进制数。
如您所见,在xx和yy之间有偶数个数字=>在xx和yy相同距离处没有数字(其中y=x+1)=>我们不需要近似任何值(例如:我们肯定知道08比11更接近00):
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
...
Run Code Online (Sandbox Code Playgroud)
问题:解决方案是否独特?
我们正在问这个问题,因为(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=> r'=zz=> r1'=r2'=> 唯一解
根据问题上方的示例,如果我们考虑一个数字,我们将找不到2个不同的数字,r1'=xx并且r2'=yy具有r-r1'=,r2'-r因为r它们更接近其中之一。仅当时,它才可以处于相同的距离r=zz,但是在这种情况下,r它可以用作r'(因为r'必须看起来像zz并且具有最小距离=> 0距离是非常完美的)。=>我们没有2个解决方案(r1'=r2')=> 唯一解决方案
g',b'=> P'(r',g',b')的模拟是唯一的(没有点像P'那样接近P)。
您还可以看到一个Java代码:
public static void main(String[] args) {
String s = "#F362C3";
System.out.println(hexToShort(s));
}
private static String hexToShort(String hex) {
// if it is short, return
if ( hex.length() == 4 ){
return hex;
}
// remove #
if ( hex.charAt(0) == '#' ) {
hex = hex.substring(1);
}
// check that hex is valid
if ( hex.length() != 6 ) {
return "";
}
String r = hex.substring(0,2);
String g = hex.substring(2,4);
String b = hex.substring(4,6);
return "#" + shortVal(r) + shortVal(g) + shortVal(b);
}
private static String shortVal(String c) {
int ci = Integer.parseInt(c, 16);
return Integer.toString((ci%17 > 7) ? (17+ci-ci%17) : (ci-ci%17), 16).substring(0,1).toUpperCase();
}
Run Code Online (Sandbox Code Playgroud)