```
-- | Utilities for converting pixel color values.
--
-- NOTE: These functions are not polymorphic in the Float type because
--       without assisatance, GHC does a bad job of converting Word8s
--       to and from floats.
--
module Data.Array.Repa.Algorithms.Pixel
( floatRmsOfRGB8
, doubleRmsOfRGB8
, floatLuminanceOfRGB8
, doubleLuminanceOfRGB8
, rgb8OfGreyFloat
, rgb8OfGreyDouble
, rgb8OfFloat
, rgb8OfDouble)
where
import Data.Word

-- | Compute the root mean square of an RGB color. Result is in the range [0..1].
floatRmsOfRGB8 :: (Word8, Word8, Word8) -> Float
{-# INLINE floatRmsOfRGB8 #-}
floatRmsOfRGB8 (r, g, b)
= let  r'      = fromIntegral (fromIntegral r :: Int) / 255
g'      = fromIntegral (fromIntegral g :: Int) / 255
b'      = fromIntegral (fromIntegral b :: Int) / 255
s       = ((r' * r') + (g' * g') + (b' * b')) / 3
in   sqrt s

-- | Compute the root mean square of an RGB color. Result is in the range [0..1].
doubleRmsOfRGB8 :: (Word8, Word8, Word8) -> Float
{-# INLINE doubleRmsOfRGB8 #-}
doubleRmsOfRGB8 (r, g, b)
= let  r'      = fromIntegral (fromIntegral r :: Int) / 255
g'      = fromIntegral (fromIntegral g :: Int) / 255
b'      = fromIntegral (fromIntegral b :: Int) / 255
s       = ((r' * r') + (g' * g') + (b' * b')) / 3
in   sqrt s

-- | Convert an RGB color to its luminance value. Result in the range [0..1].
floatLuminanceOfRGB8 :: (Word8, Word8, Word8) -> Float
{-# INLINE floatLuminanceOfRGB8 #-}
floatLuminanceOfRGB8 (r, g, b)
= let  r'      = fromIntegral (fromIntegral r :: Int) / 255
g'      = fromIntegral (fromIntegral g :: Int) / 255
b'      = fromIntegral (fromIntegral b :: Int) / 255
in   r' * 0.3 + g' * 0.59 + b' * 0.11

-- | Convert an RGB color to its luminance value. Result in the range [0..1].
doubleLuminanceOfRGB8 :: (Word8, Word8, Word8) -> Double
{-# INLINE doubleLuminanceOfRGB8 #-}
doubleLuminanceOfRGB8 (r, g, b)
= let  r'      = fromIntegral (fromIntegral r :: Int) / 255
g'      = fromIntegral (fromIntegral g :: Int) / 255
b'      = fromIntegral (fromIntegral b :: Int) / 255
in   r' * 0.3 + g' * 0.59 + b' * 0.11

-- | Promote a value in the range [0..1] to a grey RGB8 color.
rgb8OfGreyFloat :: Float -> (Word8, Word8, Word8)
{-# INLINE rgb8OfGreyFloat #-}
rgb8OfGreyFloat x
= let  v        = fromIntegral (truncate (x * 255) :: Int)
in   (v, v, v)

-- | Promote a value in the range [0..1] to a grey RGB8 color.
rgb8OfGreyDouble :: Double -> (Word8, Word8, Word8)
{-# INLINE rgb8OfGreyDouble #-}
rgb8OfGreyDouble x
= let  v        = fromIntegral (truncate (x * 255) :: Int)
in   (v, v, v)

-- | Promote a tuple of color components to a RGB8 color.
--   Each of the source components should be in the range [0..1].
rgb8OfFloat :: (Float, Float, Float) -> (Word8, Word8, Word8)
{-# INLINE rgb8OfFloat #-}
rgb8OfFloat (r, g, b)
= let  r8      = fromIntegral (truncate (r * 255) :: Int)
g8      = fromIntegral (truncate (g * 255) :: Int)
b8      = fromIntegral (truncate (b * 255) :: Int)
in   (r8, g8, b8)

-- | Promote a tuple of color components to a RGB8 color.
--   Each of the source components should be in the range [0..1].
rgb8OfDouble :: (Double, Double, Double) -> (Word8, Word8, Word8)
{-# INLINE rgb8OfDouble #-}
rgb8OfDouble (r, g, b)
= let  r8      = fromIntegral (truncate (r * 255) :: Int)
g8      = fromIntegral (truncate (g * 255) :: Int)
b8      = fromIntegral (truncate (b * 255) :: Int)
in   (r8, g8, b8)
```