CSS十六进制到速记十六进制转换 [英] CSS Hex to Shorthand Hex conversion

查看:183
本文介绍了CSS十六进制到速记十六进制转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将十六进制转换为速记十六进制的正确算法是什么?例如:#996633 很容易转换为#963 。但是,如果它是类似于#F362C3



的话,我的第一个猜测就是我只是将第一个值每种颜色,并与此一起去。因此#F362C3 变成#F6C 。但我不知道如何在数学上证明这种做法是正确的。



我在网上发现了这个: http://www.ipaste.org/Jch

 函数hex_to_shorthand($ hex ,$ uppercase = true)
{
//删除前面的哈希如果存在
if($ hex [0] ==#)$ hex = substr($ hex,1);

//如果它已经是速记,没有更多的事要做
if(strlen($ hex)== 3)return#$ hex;

//如果它不是6个字符,那么它是无效的
elseif(strlen($ hex)!== 6)return;

//最后的简写HEX值
$ final =;

//获取三元组
$ triplets = str_split($ hex,2);

//分别检查每个三元组
foreach($ triplets as $ t)
{
//获取三元组的十进制等值
$ dec = base_convert($ t,16,10);

//找到余数
$余数= $ dec%17;

//转到最接近的小数点,这会产生双倍小数点
$ new =($ dec%17> 7)? 17 +($ dec- $余数):$ dec- $余数;

//将十进制转换为HEX
$ hex = base_convert($ new,10,16);

//添加两个相同半字节中的一个
$ final。= $ hex [0];
}
//返回简写HEX颜色值
返回$大写字母? strtoupper($ final):strtolower($ final);
}

这似乎有点牵扯,再次,我不确定数学证明就在它背后。因此,像#F362C3 这样的东西变成了#E6C ,这不是我所期望的。



这样做的正确方法是什么以及转换工作背后的数学证明是什么?
$ b

(上面的代码是PHP,但是可以应用于任何语言)上面的代码是正确的高效的 strong>,具有时间复杂性: O(1)



您需要获取最初颜色的最近颜色。



由于存在RGB代码,因此每个颜色都可以被视为,它具有整数坐标(0到255之间)在 3D空间中:

   -  R  - > OX 
- G - > OY
- B - > OZ



目的



确定要点 P'(r',g',b')(输出),它是最接近 P(r,g,b) $ b

   -  r',g',b'在{0 = 0x00,17 = 0x11,34 = 0x22,... 255 = 0xff} 
(因为在CSS中只有0x可以减少到?,其中0x代表16)
- r,g,b在{0,1,2,3,...,255}

这是什么意思?我们希望在3D空间中

与P'之间的最小距离

因此,我们希望 D = sqrt ((r-r')^ 2 +(g-g')^ 2 +(b-b')^ 2)为最小值。这是3D空间中2点之间的距离。



Obs

每个成员都是> = 0



因此,如果我们希望最小 D =>我们希望:

  • 最低 | r-r'|

  • 最低 | g-g'|

  • a最小 | b-b'|



所以,问题归结为:找到距离给定的十六进制数字最近的2个相同字符的最接近的十六进制数字。



正如您所看到的,我们在xx和yy之间有偶数个数字=>在xx和yy的相同距离处没有数字(其中 y = x + 1 )=>我们不需要近似任何东西(例如:我们知道):

  00,01,02,03,04,05, 06,07,08  - >接近00 
09,0A,0B,0C,0D,0E,0F,10,11 - >接近11

11,12,13,14,15,16,17,18,19 - >接近11
1A,1B,1C,1D,1E,1F,20,21,22 - >接近22

...

问题:解决方案是否独一无二?

我们问这个问题是因为(r-r')^ 2 = min 可以实现2个不同的方式:


  • r-r1'= sqrt(min)

  • r-r2'= - sqrt(min)



我们只为 r'演示它,因为其他颜色是相似的。



我们可以显示唯一性使用两种不同的方法:


  1. 让我们添加上面的几行:

    r1'+ r2'= 2 * r



    其中 r1'= xx, r2'= yy => (00,...,ff)
    中的r = zz =(x + y)/ 2(x + y)/ 2,但是因为 r'- r 是最小值, r = zz => r'= zz => r1'= r2' => 独特的解决方案 问题是,如果我们考虑一个数字,我们找不到两个不同的数字 r1'= xx r2'= yy r 具有 r-r1' = r2'-r $ c>更接近其中之一。只有在 r = zz 时它才可以在相同的距离,但在这种情况下 r 可以用作 r'(因为 r'必须看起来像 zz 并且有最小距离=>一个0的距离是相当完美的)。 =>我们没有2个解决方案( r1'= r2')=> 独特的解决方案



  2. $ b 类似于g',b'=> P'(r',g',b')是唯一的没有任何一点与P'接近)。






    您还可以看到 Java代码

      public static void main(String [] args){
    String s =#F362C3;
    System.out.println(hexToShort(s));

    $ b private static String hexToShort(String hex){

    //如果它很短,则返回
    if(hex.length()= = 4){
    return hex;
    }

    //删除#
    if(hex.charAt(0)=='#'){
    hex = hex.substring(1);
    }

    //检查十六进制是否有效
    if(hex.length()!= 6){
    return;
    }

    字符串r = hex.substring(0,2);
    String g = hex.substring(2,4);
    String b = hex.substring(4,6);

    return#+ shortVal(r)+ shortVal(g)+ shortVal(b);


    $ 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();
    }


    What is the proper algorithm to convert Hex to Shorthand Hex? For example: #996633 easily is converted to #963. But what if it's something like #F362C3?

    My first guess would be that I just take the first value of each color and go with that. So #F362C3 becomes #F6C. But I don't know how to mathematically justify that approach.

    I found this online: 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);
    }
    

    This seems a little more involved and again, I'm not sure what the mathematical justification is behind it. So something like #F362C3 becomes #E6C, which is not what I would expect.

    What the proper way to do this and what is the mathematical proof behind how the conversion works?

    (The above code is PHP but that can apply to any language)

    解决方案

    The code above is correct and efficient, having a time complexity: O(1).

    You need to obtain the nearest color for the initial color.

    Because there is an RGB code, every color can be considered a point that has integer coordinates (between 0 and 255) in a 3D space:

    - R -> OX
    - G -> OY
    - B -> OZ
    

    Purpose

    Identify the point P'(r',g',b') (output) which is the closest point to P(r,g,b) (input) where:

    - 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}
    

    What does it mean ? We want the minimum distance between P and P' in a 3D space.

    So, we want D = sqrt( (r-r')^2 + (g-g')^2 + (b-b')^2 ) to be minimum. This is the distance between 2 points in a 3D space.

    Obs:

    Every member is >= 0.

    So, if we want a minimum D => we want:

    • a minimum |r-r'|
    • a minimum |g-g'|
    • a minimum |b-b'|

    So, the problem boils down to: find the closest hexadecimal number of 2 identical characters that is closest to a given hexadecimal number.

    As you can see, we have an even number of numbers between xx and yy => there is no number at the same distance of xx and yy (where y=x+1) => we don't need to approximate anything (E.g.: we know for sure that 08 is closer to 00 than to 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
    
    ...
    

    Question: Is the solution unique?

    We are asking this question because (r-r')^2 = min can be achieved in 2 different ways:

    • r-r1'= sqrt(min)
    • r-r2'=-sqrt(min)

    We demonstrate it only for r' because the other colors are similar.

    We can show the uniqueness using 2 different methods:

    1. Let's add the lines above:

      r1' + r2' = 2*r

      where r1'=xx, r2'=yy => r = zz = (x+y)/2(x+y)/2 in (00, ..., ff) but because r'-r is minimum and r=zz => r'=zz => r1'=r2' => unique solution

    2. Based on the examples above the question, if we consider a number, we can't find 2 different numbers r1'=xx and r2'=yy having r-r1'=r2'-r because r is closer to one of them. It can be at the same distance only if r=zz, but in this case r can be used as r' (because r' had to look like zz and to have the minimum distance => a 0 distance is quite perfect). => we don't have 2 solutions (r1'=r2') => unique solution

    Analogue for g', b' => P'(r',g',b') is unique ( there is no point as close to P as P' ).


    You can also see a Java code:

    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();
    }
    

    这篇关于CSS十六进制到速记十六进制转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆