loading...

Daily Challenge #236 - RGB to Hex Conversion

thepracticaldev profile image dev.to staff ・1 min read

This rgb function is incomplete. Complete it so that passing in RGB decimal values will result in a hexadecimal representation being returned. Valid decimal values for RGB are 0 - 255. Any values that fall out of that range must be rounded to the closest valid value.

The following are examples of expected output values:

rgb(255, 255, 255) # returns FFFFFF
rgb(255, 255, 300) # returns FFFFFF
rgb(0,0,0) # returns 000000
rgb(148, 0, 211) # returns 9400D3

Tests:
rgb(-20,275,125)
rgb(255,255,255)


This challenge comes from jhoffner on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

pic
Editor guide
 

Here is a short Python solution,

def rgb(r, g, b):
    return ('{:02x}'*3).format(*map(lambda x : max(0, min(255, x)), (r, g, b))).upper()

Output,

print(rgb(255, 255, 300)) # output -> FFFFFF
print(rgb(0,0,0)) # output -> 000000
print(rgb(148, 0, 211)) # output -> 9400D3
print(rgb(-20,275,125)) # output -> 00FF7D
print(rgb(255, 255, 255)) # output -> FFFFFF
 

Scala, providing the shortest and most elegant solution so far 😎

def rgb(r: Int, g: Int, b: Int) = {
  def h(x: Int) = f"${x max 0 min 255}%02X"
  h(r) + h(g) + h(b)
}

Tests

scala> rgb(255, 255, 255)
res24: String = FFFFFF

scala> rgb(255, 255, 300)
res25: String = FFFFFF

scala> rgb(0, 0, 0)
res26: String = 000000

scala> rgb(148, 0, 211)
res27: String = 9400D3

scala> rgb(-20, 275, 125)
res28: String = 00FF7D

scala> rgb(255, 255, 255)
res29: String = FFFFFF
 

JavaScript:

function rgb(r, g, b) {
  return [r,g,b].map(n => 
    Math.max(0, Math.min(255, n))
      .toString(16)
      .padStart(2, '0')
      .toUpperCase()
  ).join('')
}
 

A similar solution in R

rgb <- function(r, g, b) {
  h <- function(x) toupper(format(as.hexmode(min(255, max(0, x))), width=2))
  paste0(h(r), h(g), h(b))
}

Tests

> rgb(255, 255, 255)
[1] "FFFFFF"
> rgb(255, 255, 300)
[1] "FFFFFF"
> rgb(0, 0, 0)
[1] "000000"
> rgb(148, 0, 211)
[1] "9400D3"
> rgb(-20, 275, 125)
[1] "00FF7D"
> rgb(255, 255, 255)
[1] "FFFFFF"
 

BeanShell

int clip(int n) {
    return Math.max(0, Math.min(n, 255));
}

String rgb(int r, int g, int b) {
    r = clip(r);
    g = clip(g);
    b = clip(b);
    return String.format("%02x%02x%02x", new Object[] { r, g, b}).toUpperCase();
}

show();
rgb(255, 255, 255); // returns FFFFFF
rgb(255, 255, 300); // returns FFFFFF
rgb(0,0,0); // returns 000000
rgb(148, 0, 211); // returns 9400D3
rgb(-20,275,125); // returns 00FF7D

Run this code using AJShA Android app

 

Here's my solution, with C

int limit_value(int value) {
  if(value <= 0) {
    return 0;
  }
  if(value >= 255) {
    return 255;
  }
  return value;
}

char *rgb(int r, int g, int b) {
  r = limit_value(r);
  g = limit_value(g);
  b = limit_value(b);

  char *result = calloc(7, sizeof(char));
  sprintf(result, "%02X%02X%02X", r, g, b);
  return result;
}
 

Haskell solution:

import Numeric (showIntAtBase)
import Data.Char (intToDigit)

clamp :: (Ord a) => a -> a -> a -> a
clamp mi ma x = minimum [maximum [x, mi], ma]

padStart :: Int -> a -> [a] -> [a]
padStart l x = until ((>=l) . length) (x:)

rgb2num :: (Int, Int, Int) -> Int
rgb2num (r, g, b) = clampColor r * 65536 + clampColor g * 256 + clampColor b
  where clampColor = clamp 0 255

rgb2hex :: (Int, Int, Int) -> String
rgb2hex n = padStart 6 '0' $ showIntAtBase 16 intToDigit (rgb2num n) ""
 

Just for fun in Postgres, with 2 helper functions, clamp8 for keeping the value to 8 bytes (0-255) and int_to_hex for converting an int into a hex number.

create function clamp8 (value integer)
    returns integer
    as 'select greatest(0, least(255, value));'
    language SQL
    immutable
        returns null on null input;

create function int_to_hex (n integer)
    returns text
    as $$ select lpad(to_hex(clamp8(n)), 2, '0'); $$
    language SQL
    immutable
        returns null on null input;

create function rgb (r integer, g integer, b integer)
    returns text
    as 'select upper(concat(int_to_hex(r), int_to_hex(g), int_to_hex(b)));'
    language SQL
    immutable
        returns null on null input;

See it in action:

select rgb(148, 0, 211);
┌────────┐
│  rgb   │
╞════════╡
│ 9400D3 │
└────────┘
(1 row)

The function definitions are a bit more verbose than they have to be, but they are immutable and return null on null inputs, so might as well add that.

 

In rust:

// Convert number to hex string.
pub fn to_hex (value: i32) -> String {
    let value = if value > 255 { 255 } else if value < 0 { 0 } else { value };
    format!("{:02X}", value)
}

// Join all hex strings together from rgb input.
pub fn rgb (r: i32, g: i32, b: i32) -> String {
    format!("{}{}{}", to_hex(r), to_hex(g), to_hex(b))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_should_be_black() {
        assert_eq!(rgb(255, 255, 255), "FFFFFF".to_string());
    }
    #[test]
    fn it_should_be_black_too() {
        assert_eq!(rgb(255, 255, 300), "FFFFFF".to_string());
    }
    #[test]
    fn it_should_be_white() {
        assert_eq!(rgb(0, 0, 0), "000000".to_string());
    }
    #[test]
    fn it_should_be_other() {
        assert_eq!(rgb(148, 0, 211), "9400D3".to_string());
    }
}

Rust Playground
GitHub Gist

 

In javascript

const toHex = (c) => {
const toHex = (c) => {
  const hex = Math.max(0, Math.min(255, c)).toString(16);
  return hex.length == 1 ? `0${hex}` : hex;
};

const rgb = (r, g, b) => {
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
};

rgb(255, 255, 255) // #ffffff
rgb(255, 255, 300) // #ffffff
rgb(0,0,0) // #000000
rgb(148, 0, 211) // #9400d3
rgb(-20,275,125) // #00ff7d
rgb(255,255,255) // #ffffff
 

Here is the simple PHP solution:

function rgb($r,$g,$b) {
  $colorHexLists = [
      0 => '0',
      1 => '1',
      2 => '2',
      3 => '3',
      4 => '4',
      5 => '5',
      6 => '6',
      7 => '7',
      8 => '8',
      9 => '9',
      10 => 'A',
      11 => 'B',
      12 => 'C',
      13 => 'D',
      14 => 'E',
      15 => 'F',
  ];

  if ($r > 255) {
    $r = 255;
  }
  if ($r < 0) {
    $r = 0;
  }
  if ($g > 255) {
    $g = 255;
  }
  if ($g < 0) {
    $g = 0;
  }
  if ($b > 255) {
    $b = 255;
  }
  if ($b < 0) {
    $b = 0;
  }

  $rStringArray = [];
  if ($r <= 15) {
    $rStringArray[] = '0' . $colorHexLists[(int)($r)];
  } else {
      while(count($rStringArray) !== 2) {
          if ($r < 16) {
            $rStringArray[] = $colorHexLists[(int)($r)];
          } else {
            $rStringArray[] = $colorHexLists[(int)($r / 16)];
          }
          $r = $r % 16;
      }
  }  

  $gStringArray = [];
  if ($g <= 15) {
    $gStringArray[] = '0' . $colorHexLists[(int)($g)];
  } else {
      while(count($gStringArray) !== 2) {
          if ($g < 16) {
            $gStringArray[] = $colorHexLists[(int)($g)];
          } else {
            $gStringArray[] = $colorHexLists[(int)($g / 16)];
          }
          $g = $g % 16;
      }
  }

  $bStringArray = [];
  if ($b <= 15) {
      $bStringArray[] = '0' . $colorHexLists[(int)($b)];
  } else {
      while(count($bStringArray) !== 2) {
          if ($b < 16) {
            $bStringArray[] = $colorHexLists[(int)($b)];
          } else {
            $bStringArray[] = $colorHexLists[(int)($b / 16)];
          }
          $b = $b % 16;
      }
  }

  return implode($rStringArray) . implode($gStringArray) . implode($bStringArray);
}
 

Here's a quick one-liner JS solution... It would look better with a helper function to validate min/max though :-)

const rgb = (r, g, b) => Buffer.from([Math.max(0, Math.min(255, r)), Math.max(0, Math.min(255, g)), Math.max(0, Math.min(255, b))]).toString('hex').toUpperCase()

edit:
Ok, so I came up with a nicer one-liner :-) but it requires using the funky Uint8ClampedArray, which normally shouldn't be used outside of canvas API... because it rounds values to nearest from 0 to 255... which is what we want! Without further ado:

const newRGB = (r, g, b) => Buffer.from(new Uint8ClampedArray([r, g, b])).toString('hex').toUpperCase()
 

Python

r = int(input("R: "))
g = int(input("G: "))
b = int(input("B: "))

def rgb(var):
        if var < 0:
                var = 0
        if var > 255:
                var = 255

        return hex(var).split('x')[-1].zfill(2)

print('#',rgb(r), rgb(g), rgb(b), sep='')
 

You need to create a rgb function which takes three arguments. Also, this challenge didn't specify to put # at the start.