diff --git a/colorhash.cabal b/colorhash.cabal index 74e905e..8af8da7 100644 --- a/colorhash.cabal +++ b/colorhash.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: colorhash -version: 0.1.0.0 +version: 0.2.0.0 synopsis: Generate a color for a hashable object. -- description: homepage: https://github.com/hapytex/colorhash#readme diff --git a/src/Data/Hashable/Color.hs b/src/Data/Hashable/Color.hs index 9650bd7..0ca68fa 100644 --- a/src/Data/Hashable/Color.hs +++ b/src/Data/Hashable/Color.hs @@ -12,17 +12,52 @@ -- each of the items a different color based on the hash. -- -- This module provides a function 'rgbHash' that can convert any 'Hashable' object to a 'Colour'. -module Data.Hashable.Color (rgbHash) where +module Data.Hashable.Color + ( -- * Determine color + rgbHash, -import Data.Bits (shiftR, (.&.)) + -- * Show items with color + rgbHashBgShow, + rgbHashFgShow, + ) +where + +import Data.Bits (shiftR, xor, (.&.)) import Data.Colour (Colour) import Data.Colour.SRGB (sRGB24) import Data.Hashable (Hashable (hash)) import Data.Word (Word8) +type Col8 = (Word8, Word8, Word8) + _word8 :: Int -> Word8 _word8 = toEnum . (255 .&.) +_scramble :: Int -> Int +_scramble x = (shiftR x 16 `xor` x) * 0x45d9f3b + +_rgbHash :: (Hashable a) => a -> Col8 +_rgbHash x = (r, g, b) + where + h = _scramble (_scramble (hash x)) + b = _word8 h + g = _word8 (shiftR h 8) + r = _word8 (shiftR h 16) + +_ansiSeq :: Int -> Col8 -> String -> String +_ansiSeq md ~(r, g, b) = (("\027[" ++ show md ++ ";2;" ++ show r ++ ";" ++ show g ++ ";" ++ show b ++ "m") ++) + +_ansiSeqBg :: Col8 -> String -> String +_ansiSeqBg = _ansiSeq 48 + +_ansiSeqFg :: Col8 -> String -> String +_ansiSeqFg = _ansiSeq 38 + +_altColor :: Col8 -> Col8 +_altColor ~(r, g, b) + | 1063 * fromEnum r + 3576 * fromEnum g + 361 * fromEnum b <= 200000 = (255, 255, 255) + | otherwise = (0, 0, 0) + -- | Convert a given 'Hashable' object to a 'Colour' by determining the hash, and using the last 24 bits as source for the red, green, and blue channels of the 'Colour' to construct. rgbHash :: (Hashable a, Floating b, Ord b) => @@ -32,7 +67,28 @@ rgbHash :: Colour b rgbHash x = sRGB24 r g b where - h = hash x - b = _word8 h - g = _word8 (shiftR h 8) - r = _word8 (shiftR h 16) + ~(r, g, b) = _rgbHash x + +-- | Show the given 'Hashable' object with ANSI terminal codes such that the background is colorized by the hash of that object. This will only work if the terminal supports [24-bit colors](https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit). The foreground is either black or white depending on whether the color is more light or dark. +rgbHashBgShow :: + (Hashable a, Show a) => + -- | The 'Hashable' object to print in a colorized way. + a -> + -- | A String with ANSI terminal codes to colorize the object + String +rgbHashBgShow x = _ansiSeqBg c (_ansiSeqFg ca (shows x "\027[0m")) + where + c = _rgbHash x + ca = _altColor c + +-- | Show the given 'Hashable' object with ANSI terminal codes such that the foreground is colorized by the hash of that object. This will only work if the terminal supports [24-bit colors](https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit). The background is either black or white depending on whether the color is more light or dark. +rgbHashFgShow :: + (Hashable a, Show a) => + -- | The 'Hashable' object to print in a colorized way. + a -> + -- | A String with ANSI terminal codes to colorize the object + String +rgbHashFgShow x = _ansiSeqFg c (_ansiSeqBg ca (shows x "\027[0m")) + where + c = _rgbHash x + ca = _altColor c