From 96ed4cc496be35903121ca4e3176206d3f28efc6 Mon Sep 17 00:00:00 2001 From: Caroline Larimore Date: Tue, 4 Feb 2025 19:15:59 -0800 Subject: migration: color conversion functions --- snowfall/lib/color-conversion/default.nix | 175 ++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 snowfall/lib/color-conversion/default.nix (limited to 'snowfall/lib') diff --git a/snowfall/lib/color-conversion/default.nix b/snowfall/lib/color-conversion/default.nix new file mode 100644 index 0000000..437b511 --- /dev/null +++ b/snowfall/lib/color-conversion/default.nix @@ -0,0 +1,175 @@ +{ lib }: + +let + hexToDecMap = { + "0" = 0; + "1" = 1; + "2" = 2; + "3" = 3; + "4" = 4; + "5" = 5; + "6" = 6; + "7" = 7; + "8" = 8; + "9" = 9; + "a" = 10; + "b" = 11; + "c" = 12; + "d" = 13; + "e" = 14; + "f" = 15; + }; + + /* Base raised to the power of the exponent. + + Type: pow :: int or float -> int -> int + + Args: + base: The base. + exponent: The exponent. + + Example: + pow 0 1000 + => 0 + pow 1000 0 + => 1 + pow 2 30 + => 1073741824 + pow 3 3 + => 27 + pow (-5) 3 + => -125 + */ + pow = base: exponent: + if exponent > 1 then + let + x = pow base (exponent / 2); + odd_exp = lib.mod exponent 2 == 1; + in + x * x * (if odd_exp then base else 1) + else if exponent == 1 then + base + else if exponent == 0 && base == 0 then + throw "undefined" + else if exponent == 0 then + 1 + else + throw "undefined"; + + /* Conversion from base 16 to base 10 with a exponent. Is of the form + scalar * 16 ** exponent. + + Type: base16To10 :: int -> int -> int + + Args: + exponent: The exponent for the base, 16. + scalar: The value to multiple to the exponentiated base. + + Example: + base16To10 0 11 + => 11 + base16To10 1 3 + => 48 + base16To10 2 7 + 1792 + base16To10 3 14 + 57344 + */ + base16To10 = exponent: scalar: scalar * pow 16 exponent; + + /* Converts a hexadecimal character to decimal. + Only takes a string of length 1. + + Type: hexCharToDec :: string -> int + + Args: + hex: A hexadecimal character. + + Example: + hexCharToDec "5" + => 5 + hexCharToDec "e" + => 14 + hexCharToDec "A" + => 10 + */ + hexCharToDec = hex: + let + lowerHex = lib.toLower hex; + in + if builtins.stringLength hex != 1 then + throw "Function only accepts a single character." + else if hexToDecMap ? ${lowerHex} then + hexToDecMap."${lowerHex}" + else + throw "Character ${hex} is not a hexadecimal value."; +in rec { + /* Converts from hexadecimal to decimal. + + Type: hexToDec :: string -> int + + Args: + hex: A hexadecimal string. + + Example: + hexadecimal "12" + => 18 + hexadecimal "FF" + => 255 + hexadecimal "abcdef" + => 11259375 + */ + hexToDec = hex: + let + decimals = builtins.map hexCharToDec (lib.stringToCharacters hex); + decimalsAscending = lib.reverseList decimals; + decimalsPowered = lib.imap0 base16To10 decimalsAscending; + in + lib.foldl builtins.add 0 decimalsPowered; + + /* Converts a 6 character hexadecimal string to RGB values. + + Type: hexToRGB :: string => [int] + + Args: + hex: A hexadecimal string of length 6. + + Example: + hexToRGB "012345" + => [ 1 35 69 ] + hexToRGB "abcdef" + => [171 205 239 ] + hexToRGB "000FFF" + => [ 0 15 255 ] + */ + hexToRGB = hex: + let + rgbStartIndex = [ 0 2 4 ]; + hexList = builtins.map (x: builtins.substring x 2 hex) rgbStartIndex; + hexLength = builtins.stringLength hex; + in + if hexLength != 6 then + throw '' + Unsupported hex string length of ${builtins.toString hexLength}. + Length must be exactly 6. + '' + else + builtins.map hexToDec hexList; + + /* Converts a 6 character hexadecimal string to an RGB string seperated by a + delimiter. + + Type: hexToRGBString :: string -> string + + Args: + sep: The delimiter or seperator. + hex: A hexadecimal string of length 6. + */ + hexToRGBString = sep: hex: + let + inherit (builtins) map toString; + hexInRGB = hexToRGB hex; + hexInRGBString = map toString hexInRGB; + in + lib.concatStringsSep sep hexInRGBString; +} -- cgit v1.2.3