Intersection with CSS hex transform with short hex

What is the correct Hex to Shorthand Hex conversion algorithm? For example: #996633

easily converts to #963

. But what if it's something like #F362C3

?

My first guess was that I just take the first value of each color and agree with that. So it #F362C3

becomes #F6C

. But I don't know how to mathematically justify this 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 complicated and again, I'm not sure there is a math behind it. So, something seems to #F362C3

become #E6C

, which I did not expect.

What is the correct way to do this and what is the mathematical proof of how the transformation works?

(the above code is PHP, but can apply to any language)

+3


source to share


1 answer


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

You need to get the closest color to the original color.

Since there is an RGB code, each color can be thought of as a point that has integer coordinates (0 to 255) in 3D space :

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

      

purpose

Define a point P'(r',g',b')

(output) that 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 3D space .

So we want it to D = sqrt( (r-r')^2 + (g-g')^2 + (b-b')^2 )

be minimal. This is the distance between two points in 3D space.

obs

Every member >= 0

.

So, if we want minimum D

=>, we want:

  • minimum |r-r'|

  • minimum |g-g'|

  • minimum |b-b'|



Thus, the problem boils down to the following: find the nearest hexadecimal number of two identical characters that is closest to the 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 from xx and yy (where y=x+1

) => we don't need to zoom in anything (For example: we know for sure that 08 is closer to 00 than by 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 ask this question because it (r-r')^2 = min

can be achieved in two different ways:

  • r-r1'= sqrt(min)

  • r-r2'=-sqrt(min)

We are only showing this for r'

, because other colors are similar.

We can show uniqueness using two different methods:

  • Add the above lines:

    r1' + r2' = 2*r

    where r1'=xx, r2'=yy => r = zz = (x+y)/2(x+y)/2 in (00, ..., ff)

    but since r'-r

    is minimal and r=zz

    => r'=zz

    => r1'=r2'

    => unique solution

  • Based on the examples above, the question, if we look at a number, cannot find 2 different numbers r1'=xx

    and r2'=yy

    having r-r1'

    = r2'-r

    because it is r

    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 it r'

    should look like zz

    and have a minimum distance => a 0 the distance is pretty perfect). => we don't have two solutions ( r1'=r2'

    ) => unique solution

The analog for g ', b' => P '(r', g ', b') is unique (points P are not as close as P ').


You can also see the 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();
}

      

+4


source







All Articles