{-# LANGUAGE LambdaCase, ViewPatterns #-} {-# LANGUAGE PatternSynonyms #-} {-# OPTIONS_GHC -Wall -fno-warn-tabs #-} module Data.Color.Internal ( -- * Alpha Alpha(..), pattern AlphaWord8, pattern AlphaWord16, pattern AlphaWord32, pattern AlphaInt32, alphaInt32, pattern AlphaDouble, alphaDouble, alphaRealToFrac, -- * RGB Rgb(..), pattern RgbWord8, pattern RgbWord16, pattern RgbWord32, pattern RgbInt32, rgbInt32, pattern RgbDouble, rgbDouble, rgbRealToFrac, -- * RGBA -- ** Straight Rgba(..), pattern RgbaWord8, pattern RgbaWord16, pattern RgbaWord32, pattern RgbaInt32, rgbaInt32, pattern RgbaDouble, rgbaDouble, -- ** Premultiplied pattern RgbaPremultipliedWord8, rgbaPremultipliedWord8, pattern RgbaPremultipliedWord16, rgbaPremultipliedWord16, pattern RgbaPremultipliedDouble, rgbaPremultipliedDouble, -- ** From and To Rgb and Alpha toRgba, fromRgba, -- ** Convert Fractional rgbaRealToFrac ) where import Data.Bits import Data.Bool import Data.Word import Data.Int data Alpha d = AlphaWord8_ Word8 | AlphaWord16_ Word16 | AlphaWord32_ Word32 | AlphaInt32_ Int32 | AlphaDouble_ d deriving Show {-# COMPLETE AlphaWord8 #-} pattern AlphaWord8 :: RealFrac d => Word8 -> Alpha d pattern AlphaWord8 a <- (fromAlphaWord8 -> a) where AlphaWord8 = AlphaWord8_ fromAlphaWord8 :: RealFrac d => Alpha d -> Word8 fromAlphaWord8 = \case AlphaWord8_ a -> a AlphaWord16_ a -> fromIntegral $ a `shiftR` 8 AlphaWord32_ a -> fromIntegral $ a `shiftR` 24 AlphaInt32_ a -> fromIntegral $ a `shiftR` 23 AlphaDouble_ a -> cDoubleToWord8 a {-# COMPLETE AlphaWord16 #-} pattern AlphaWord16 :: RealFrac d => Word16 -> Alpha d pattern AlphaWord16 a <- (fromAlphaWord16 -> a) where AlphaWord16 = AlphaWord16_ fromAlphaWord16 :: RealFrac d => Alpha d -> Word16 fromAlphaWord16 = \case AlphaWord8_ (fromIntegral -> a) -> a `shiftL` 8 .|. a AlphaWord16_ a -> a AlphaWord32_ a -> fromIntegral $ a `shiftR` 16 AlphaInt32_ a -> fromIntegral $ a `shiftR` 15 AlphaDouble_ a -> cDoubleToWord16 a {-# COMPLETE AlphaWord32 #-} pattern AlphaWord32 :: RealFrac d => Word32 -> Alpha d pattern AlphaWord32 a <- (fromAlphaWord32 -> a) where AlphaWord32 = AlphaWord32_ fromAlphaWord32 :: RealFrac d => Alpha d -> Word32 fromAlphaWord32 = \case AlphaWord8_ (fromIntegral -> a) -> a `shiftL` 24 .|. a `shiftL` 16 .|. a `shiftL` 8 .|. a AlphaWord16_ (fromIntegral -> a) -> a `shiftL` 16 .|. a AlphaWord32_ a -> a AlphaInt32_ (fromIntegral -> a) -> a `shiftL` 1 .|. a `shiftR` 30 AlphaDouble_ a -> cDoubleToWord32 a {-# COMPLETE AlphaInt32 #-} pattern AlphaInt32 :: RealFrac d => Int32 -> Alpha d pattern AlphaInt32 a <- (fromAlphaInt32 -> a) alphaInt32 :: Int32 -> Maybe (Alpha d) alphaInt32 a = bool Nothing (Just $ AlphaInt32_ a) (a >= 0) fromAlphaInt32 :: RealFrac d => Alpha d -> Int32 fromAlphaInt32 = \case AlphaWord8_ (fromIntegral -> a) -> a `shiftL` 23 .|. a `shiftL` 15 .|. a `shiftL` 7 .|. a `shiftR` 1 AlphaWord16_ (fromIntegral -> a) -> a `shiftL` 15 .|. a `shiftR` 1 AlphaWord32_ a -> fromIntegral $ a `shiftR` 1 AlphaInt32_ a -> a AlphaDouble_ a -> cDoubleToInt32 a {-# COMPLETE AlphaDouble #-} pattern AlphaDouble :: Fractional d => d -> (Alpha d) pattern AlphaDouble a <- (fromAlphaDouble -> a) fromAlphaDouble :: Fractional d => Alpha d -> d fromAlphaDouble = \case AlphaWord8_ a -> word8ToCDouble a AlphaWord16_ a -> word16ToCDouble a AlphaWord32_ a -> word32ToCDouble a AlphaInt32_ a -> int32ToCDouble a AlphaDouble_ a -> a alphaDouble :: (Ord d, Num d) => d -> Maybe (Alpha d) alphaDouble a | from0to1 a = Just $ AlphaDouble_ a | otherwise = Nothing alphaRealToFrac :: (Real d, Fractional d') => Alpha d -> Alpha d' alphaRealToFrac = \case AlphaWord8_ a -> AlphaWord8_ a AlphaWord16_ a -> AlphaWord16_ a AlphaWord32_ a -> AlphaWord32_ a AlphaInt32_ a -> AlphaInt32_ a AlphaDouble_ a -> AlphaDouble_ $ realToFrac a data Rgb d = RgbWord8_ Word8 Word8 Word8 | RgbWord16_ Word16 Word16 Word16 | RgbWord32_ Word32 Word32 Word32 | RgbInt32_ Int32 Int32 Int32 | RgbDouble_ d d d deriving Show {-# COMPLETE RgbWord8 #-} pattern RgbWord8 :: RealFrac d => Word8 -> Word8 -> Word8 -> Rgb d pattern RgbWord8 r g b <- (fromRgbWord8 -> (r, g, b)) where RgbWord8 = RgbWord8_ fromRgbWord8 :: RealFrac d => Rgb d -> (Word8, Word8, Word8) fromRgbWord8 = \case RgbWord8_ r g b -> (r, g, b) RgbWord16_ r g b -> ( fromIntegral $ r `shiftR` 8, fromIntegral $ g `shiftR` 8, fromIntegral $ b `shiftR` 8 ) RgbWord32_ r g b -> ( fromIntegral $ r `shiftR` 24, fromIntegral $ g `shiftR` 24, fromIntegral $ b `shiftR` 24 ) RgbInt32_ r g b -> ( fromIntegral $ r `shiftR` 23, fromIntegral $ g `shiftR` 23, fromIntegral $ b `shiftR` 23 ) RgbDouble_ r g b -> case cDoubleToWord8 <$> [r, g, b] of [r', g', b'] -> (r', g', b') _ -> error "never occur" {-# COMPLETE RgbWord16 #-} pattern RgbWord16 :: RealFrac d => Word16 -> Word16 -> Word16 -> Rgb d pattern RgbWord16 r g b <- (fromRgbWord16 -> (r, g, b)) where RgbWord16 = RgbWord16_ fromRgbWord16 :: RealFrac d => Rgb d -> (Word16, Word16, Word16) fromRgbWord16 = \case RgbWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> (r `shiftL` 8 .|. r, g `shiftL` 8 .|. g, b `shiftL` 8 .|. b) RgbWord16_ r g b -> (r, g, b) RgbWord32_ r g b -> ( fromIntegral $ r `shiftR` 16, fromIntegral $ g `shiftR` 16, fromIntegral $ b `shiftR` 16 ) RgbInt32_ r g b -> ( fromIntegral $ r `shiftR` 15, fromIntegral $ g `shiftR` 15, fromIntegral $ b `shiftR` 15 ) RgbDouble_ r g b -> let [r', g', b'] = cDoubleToWord16 <$> [r, g, b] in (r', g', b') {-# COMPLETE RgbWord32 #-} pattern RgbWord32 :: RealFrac d => Word32 -> Word32 -> Word32 -> Rgb d pattern RgbWord32 r g b <- (fromRgbWord32 -> (r, g, b)) where RgbWord32 = RgbWord32_ fromRgbWord32 :: RealFrac d => Rgb d -> (Word32, Word32, Word32) fromRgbWord32 = \case RgbWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> ( r `shiftL` 24 .|. r `shiftL` 16 .|. r `shiftL` 8 .|. r, g `shiftL` 24 .|. g `shiftL` 16 .|. g `shiftL` 8 .|. g, b `shiftL` 24 .|. b `shiftL` 16 .|. b `shiftL` 8 .|. b ) RgbWord16_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> ( r `shiftL` 16 .|. r, g `shiftL` 16 .|. g, b `shiftL` 16 .|. b ) RgbWord32_ r g b -> (r, g, b) RgbInt32_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> ( r `shiftL` 1 .|. r `shiftR` 30, g `shiftL` 1 .|. g `shiftR` 30, b `shiftL` 1 .|. b `shiftR` 30 ) RgbDouble_ r g b -> let [r', g', b'] = cDoubleToWord32 <$> [r, g, b] in (r', g', b') {-# COMPLETE RgbInt32 #-} pattern RgbInt32 :: RealFrac d => Int32 -> Int32 -> Int32 -> Rgb d pattern RgbInt32 r g b <- (fromRgbInt32 -> (r, g, b)) rgbInt32 :: Int32 -> Int32 -> Int32 -> Maybe (Rgb d) rgbInt32 r g b | r < 0 || g < 0 || b < 0 = Nothing | otherwise = Just $ RgbInt32_ r g b fromRgbInt32 :: RealFrac d => Rgb d -> (Int32, Int32, Int32) fromRgbInt32 = \case RgbWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> ( r `shiftL` 23 .|. r `shiftL` 15 .|. r `shiftL` 7 .|. r `shiftR` 1, g `shiftL` 23 .|. g `shiftL` 15 .|. g `shiftL` 7 .|. g `shiftR` 1, b `shiftL` 23 .|. b `shiftL` 15 .|. b `shiftL` 7 .|. b `shiftR` 1 ) RgbWord16_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) -> ( r `shiftL` 15 .|. r `shiftR` 1, g `shiftL` 15 .|. g `shiftR` 1, b `shiftL` 15 .|. b `shiftR` 1 ) RgbWord32_ r g b -> ( fromIntegral $ r `shiftR` 1, fromIntegral $ g `shiftR` 1, fromIntegral $ b `shiftR` 1 ) RgbInt32_ r g b -> (r, g, b) RgbDouble_ r g b -> let [r', g', b'] = cDoubleToInt32 <$> [r, g, b] in (r', g', b') {-# COMPLETE RgbDouble #-} pattern RgbDouble :: Fractional d => d -> d -> d -> (Rgb d) pattern RgbDouble r g b <- (fromRgbDouble -> (r, g, b)) fromRgbDouble :: Fractional d => Rgb d -> (d, d, d) fromRgbDouble = \case RgbWord8_ r g b -> let [r', g', b'] = word8ToCDouble <$> [r, g, b] in (r', g', b') RgbWord16_ r g b -> let [r', g', b'] = word16ToCDouble <$> [r, g, b] in (r', g', b') RgbWord32_ r g b -> let [r', g', b'] = word32ToCDouble <$> [r, g, b] in (r', g', b') RgbInt32_ r g b -> let [r', g', b'] = int32ToCDouble <$> [r, g, b] in (r', g', b') RgbDouble_ r g b -> (r, g, b) rgbDouble :: (Ord d, Num d) => d -> d -> d -> Maybe (Rgb d) rgbDouble r g b | from0to1 r && from0to1 g && from0to1 b = Just $ RgbDouble_ r g b | otherwise = Nothing rgbRealToFrac :: (Real d, Fractional d') => Rgb d -> Rgb d' rgbRealToFrac = \case RgbWord8_ r g b -> RgbWord8_ r g b RgbWord16_ r g b -> RgbWord16_ r g b RgbWord32_ r g b -> RgbWord32_ r g b RgbInt32_ r g b -> RgbInt32_ r g b RgbDouble_ r g b -> RgbDouble_ r' g' b' where [r', g', b'] = realToFrac <$> [r, g, b] data Rgba d = RgbaWord8_ Word8 Word8 Word8 Word8 | RgbaWord16_ Word16 Word16 Word16 Word16 | RgbaWord32_ Word32 Word32 Word32 Word32 | RgbaInt32_ Int32 Int32 Int32 Int32 | RgbaDouble_ d d d d | RgbaPremultipliedWord8_ Word8 Word8 Word8 Word8 | RgbaPremultipliedWord16_ Word16 Word16 Word16 Word16 | RgbaPremultipliedDouble_ d d d d deriving Show {-# COMPLETE RgbaWord8 #-} pattern RgbaWord8 :: RealFrac d => Word8 -> Word8 -> Word8 -> Word8 -> Rgba d pattern RgbaWord8 r g b a <- (fromRgbaWord8 -> (r, g, b, a)) where RgbaWord8 = RgbaWord8_ fromRgbaWord8 :: RealFrac d => Rgba d -> (Word8, Word8, Word8, Word8) fromRgbaWord8 = \case RgbaWord8_ r g b a -> (r, g, b, a) RgbaWord16_ r g b a -> ( fromIntegral $ r `shiftR` 8, fromIntegral $ g `shiftR` 8, fromIntegral $ b `shiftR` 8, fromIntegral $ a `shiftR` 8 ) RgbaWord32_ r g b a -> ( fromIntegral $ r `shiftR` 24, fromIntegral $ g `shiftR` 24, fromIntegral $ b `shiftR` 24, fromIntegral $ a `shiftR` 24 ) RgbaInt32_ r g b a -> ( fromIntegral $ r `shiftR` 23, fromIntegral $ g `shiftR` 23, fromIntegral $ b `shiftR` 23, fromIntegral $ a `shiftR` 23 ) RgbaDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = cDoubleToWord8 <$> [r, g, b, a] RgbaPremultipliedWord8_ r g b a -> (r', g', b', a') where [r', g', b', a'] = unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> ( fromIntegral $ r' `shiftR` 8, fromIntegral $ g' `shiftR` 8, fromIntegral $ b' `shiftR` 8, fromIntegral $ a' `shiftR` 8 ) where [r', g', b', a'] = unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = cDoubleToWord8 <$> unPremultipliedDouble (r, g, b, a) {-# COMPLETE RgbaWord16 #-} pattern RgbaWord16 :: RealFrac d => Word16 -> Word16 -> Word16 -> Word16 -> Rgba d pattern RgbaWord16 r g b a <- (fromRgbaWord16 -> (r, g, b, a)) where RgbaWord16 = RgbaWord16_ fromRgbaWord16 :: RealFrac d => Rgba d -> (Word16, Word16, Word16, Word16) fromRgbaWord16 = \case RgbaWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 8 .|. r, g `shiftL` 8 .|. g, b `shiftL` 8 .|. b, a `shiftL` 8 .|. a) RgbaWord16_ r g b a -> (r, g, b, a) RgbaWord32_ r g b a -> ( fromIntegral $ r `shiftR` 16, fromIntegral $ g `shiftR` 16, fromIntegral $ b `shiftR` 16, fromIntegral $ a `shiftR` 16 ) RgbaInt32_ r g b a -> ( fromIntegral $ r `shiftR` 15, fromIntegral $ g `shiftR` 15, fromIntegral $ b `shiftR` 15, fromIntegral $ a `shiftR` 15 ) RgbaDouble_ r g b a -> let [r', g', b', a'] = cDoubleToWord16 <$> [r, g, b, a] in (r', g', b', a') RgbaPremultipliedWord8_ r g b a -> ( r' `shiftL` 8 .|. r', g' `shiftL` 8 .|. g', b' `shiftL` 8 .|. b', a' `shiftL` 8 .|. a') where [r', g', b', a'] = fromIntegral <$> unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> (r', g', b', a') where [r', g', b', a'] = unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = cDoubleToWord16 <$> unPremultipliedDouble (r, g, b, a) {-# COMPLETE RgbaWord32 #-} pattern RgbaWord32 :: RealFrac d => Word32 -> Word32 -> Word32 -> Word32 -> Rgba d pattern RgbaWord32 r g b a <- (fromRgbaWord32 -> (r, g, b, a)) where RgbaWord32 = RgbaWord32_ fromRgbaWord32 :: RealFrac d => Rgba d -> (Word32, Word32, Word32, Word32) fromRgbaWord32 = \case RgbaWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 24 .|. r `shiftL` 16 .|. r `shiftL` 8 .|. r, g `shiftL` 24 .|. g `shiftL` 16 .|. g `shiftL` 8 .|. g, b `shiftL` 24 .|. b `shiftL` 16 .|. b `shiftL` 8 .|. b, a `shiftL` 24 .|. a `shiftL` 16 .|. a `shiftL` 8 .|. a ) RgbaWord16_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 16 .|. r, g `shiftL` 16 .|. g, b `shiftL` 16 .|. b, a `shiftL` 16 .|. a ) RgbaWord32_ r g b a -> (r, g, b, a) RgbaInt32_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 1 .|. r `shiftR` 30, g `shiftL` 1 .|. g `shiftR` 30, b `shiftL` 1 .|. b `shiftR` 30, a `shiftL` 1 .|. a `shiftR` 30 ) RgbaDouble_ r g b a -> let [r', g', b', a'] = cDoubleToWord32 <$> [r, g, b, a] in (r', g', b', a') RgbaPremultipliedWord8_ r g b a -> ( r' `shiftL` 24 .|. r' `shiftL` 16 .|. r' `shiftL` 8 .|. r', g' `shiftL` 24 .|. g' `shiftL` 16 .|. g' `shiftL` 8 .|. g', b' `shiftL` 24 .|. b' `shiftL` 16 .|. b' `shiftL` 8 .|. b', a' `shiftL` 24 .|. a' `shiftL` 16 .|. a' `shiftL` 8 .|. a' ) where [r', g', b', a'] = fromIntegral <$> unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> ( r' `shiftL` 16 .|. r', g' `shiftL` 16 .|. g', b' `shiftL` 16 .|. b', a' `shiftL` 16 .|. a' ) where [r', g', b', a'] = fromIntegral <$> unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = cDoubleToWord32 <$> unPremultipliedDouble (r, g, b, a) {-# COMPLETE RgbaInt32 #-} pattern RgbaInt32 :: RealFrac d => Int32 -> Int32 -> Int32 -> Int32 -> Rgba d pattern RgbaInt32 r g b a <- (fromRgbaInt32 -> (r, g, b, a)) rgbaInt32 :: Int32 -> Int32 -> Int32 -> Int32 -> Maybe (Rgba d) rgbaInt32 r g b a | r < 0 || g < 0 || b < 0 || a < 0 = Nothing | otherwise = Just $ RgbaInt32_ r g b a fromRgbaInt32 :: RealFrac d => Rgba d -> (Int32, Int32, Int32, Int32) fromRgbaInt32 = \case RgbaWord8_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 23 .|. r `shiftL` 15 .|. r `shiftL` 7 .|. r `shiftR` 1, g `shiftL` 23 .|. g `shiftL` 15 .|. g `shiftL` 7 .|. g `shiftR` 1, b `shiftL` 23 .|. b `shiftL` 15 .|. b `shiftL` 7 .|. b `shiftR` 1, a `shiftL` 23 .|. a `shiftL` 15 .|. a `shiftL` 7 .|. a `shiftR` 1 ) RgbaWord16_ (fromIntegral -> r) (fromIntegral -> g) (fromIntegral -> b) (fromIntegral -> a) -> ( r `shiftL` 15 .|. r `shiftR` 1, g `shiftL` 15 .|. g `shiftR` 1, b `shiftL` 15 .|. b `shiftR` 1, a `shiftL` 15 .|. a `shiftR` 1 ) RgbaWord32_ r g b a -> ( fromIntegral $ r `shiftR` 1, fromIntegral $ g `shiftR` 1, fromIntegral $ b `shiftR` 1, fromIntegral $ a `shiftR` 1 ) RgbaInt32_ r g b a -> (r, g, b, a) RgbaDouble_ r g b a -> let [r', g', b', a'] = cDoubleToInt32 <$> [r, g, b, a] in (r', g', b', a') RgbaPremultipliedWord8_ r g b a -> ( r' `shiftL` 23 .|. r' `shiftL` 15 .|. r' `shiftL` 7 .|. r' `shiftR` 1, g' `shiftL` 23 .|. g' `shiftL` 15 .|. g' `shiftL` 7 .|. g' `shiftR` 1, b' `shiftL` 23 .|. b' `shiftL` 15 .|. b' `shiftL` 7 .|. b' `shiftR` 1, a' `shiftL` 23 .|. a' `shiftL` 15 .|. a' `shiftL` 7 .|. a' `shiftR` 1 ) where [r', g', b', a'] = fromIntegral <$> unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> ( r' `shiftL` 15 .|. r' `shiftR` 1, g' `shiftL` 15 .|. g' `shiftR` 1, b' `shiftL` 15 .|. b' `shiftR` 1, a' `shiftL` 15 .|. a' `shiftR` 1 ) where [r', g', b', a'] = fromIntegral <$> unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = cDoubleToInt32 <$> unPremultipliedDouble (r, g, b, a) {-# COMPLETE RgbaDouble #-} pattern RgbaDouble :: (Eq d, Fractional d) => d -> d -> d -> d -> Rgba d pattern RgbaDouble r g b a <- (fromRgbaDouble -> (r, g, b, a)) fromRgbaDouble :: (Eq d, Fractional d) => Rgba d -> (d, d, d, d) fromRgbaDouble = \case RgbaWord8_ r g b a -> (r', g', b', a') where [r', g', b', a'] = word8ToCDouble <$> [r, g, b, a] RgbaWord16_ r g b a -> (r', g', b', a') where [r', g', b', a'] = word16ToCDouble <$> [r, g, b, a] RgbaWord32_ r g b a -> (r', g', b', a') where [r', g', b', a'] = word32ToCDouble <$> [r, g, b, a] RgbaInt32_ r g b a -> (r', g', b', a') where [r', g', b', a'] = int32ToCDouble <$> [r, g, b, a] RgbaDouble_ r g b a -> (r, g, b, a) RgbaPremultipliedWord8_ r g b a -> (r', g', b', a') where [r', g', b', a'] = word8ToCDouble <$> unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> (r', g', b', a') where [r', g', b', a'] = word16ToCDouble <$> unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (r', g', b', a') where [r', g', b', a'] = unPremultipliedDouble (r, g, b, a) rgbaDouble :: (Ord d, Num d) => d -> d -> d -> d -> Maybe (Rgba d) rgbaDouble r g b a | from0to1 r && from0to1 g && from0to1 b && from0to1 a = Just $ RgbaDouble_ r g b a | otherwise = Nothing fromRgba :: (Eq d, Fractional d) => Rgba d -> (Rgb d, Alpha d) fromRgba = \case RgbaWord8_ r g b a -> (RgbWord8_ r g b, AlphaWord8_ a) RgbaWord16_ r g b a -> (RgbWord16_ r g b, AlphaWord16_ a) RgbaWord32_ r g b a -> (RgbWord32_ r g b, AlphaWord32_ a) RgbaInt32_ r g b a -> (RgbInt32_ r g b, AlphaInt32_ a) RgbaDouble_ r g b a -> (RgbDouble_ r g b, AlphaDouble_ a) RgbaPremultipliedWord8_ r g b a -> (RgbWord8_ r' g' b', AlphaWord8_ a') where [r', g', b', a'] = unPremultipliedWord8 (r, g, b, a) RgbaPremultipliedWord16_ r g b a -> (RgbWord16_ r' g' b', AlphaWord16_ a') where [r', g', b', a'] = unPremultipliedWord16 (r, g, b, a) RgbaPremultipliedDouble_ r g b a -> (RgbDouble_ r' g' b', AlphaDouble_ a') where [r', g', b', a'] = unPremultipliedDouble (r, g, b, a) toRgba :: RealFrac d => Rgb d -> Alpha d -> Rgba d toRgba (RgbWord8_ r g b) (AlphaWord8 a) = RgbaWord8 r g b a toRgba (RgbWord16_ r g b) (AlphaWord16 a) = RgbaWord16 r g b a toRgba (RgbWord32_ r g b) (AlphaWord32 a) = RgbaWord32 r g b a toRgba (RgbInt32_ r g b) (AlphaInt32 a) = RgbaInt32_ r g b a toRgba (RgbDouble_ r g b) (AlphaDouble a) = RgbaDouble_ r g b a rgbaRealToFrac :: (Real d, Fractional d') => Rgba d -> Rgba d' rgbaRealToFrac = \case RgbaWord8_ r g b a -> RgbaWord8_ r g b a RgbaWord16_ r g b a -> RgbaWord16_ r g b a RgbaWord32_ r g b a -> RgbaWord32_ r g b a RgbaInt32_ r g b a -> RgbaInt32_ r g b a RgbaDouble_ r g b a -> RgbaDouble_ r' g' b' a' where [r', g', b', a'] = realToFrac <$> [r, g, b, a] RgbaPremultipliedWord8_ r g b a -> RgbaPremultipliedWord8_ r g b a RgbaPremultipliedWord16_ r g b a -> RgbaPremultipliedWord16_ r g b a RgbaPremultipliedDouble_ r g b a -> RgbaPremultipliedDouble_ r' g' b' a' where [r', g', b', a'] = realToFrac <$> [r, g, b, a] cDoubleToWord8 :: RealFrac d => d -> Word8 cDoubleToWord8 = round . (* 0xff) cDoubleToWord16 :: RealFrac d => d -> Word16 cDoubleToWord16 = round . (* 0xffff) cDoubleToWord32 :: RealFrac d => d -> Word32 cDoubleToWord32 = round . (* 0xffffffff) cDoubleToInt32 :: RealFrac d => d -> Int32 cDoubleToInt32 = round . (* 0x7fffffff) word8ToCDouble :: Fractional d => Word8 -> d word8ToCDouble = (/ 0xff) . fromIntegral word16ToCDouble :: Fractional d => Word16 -> d word16ToCDouble = (/ 0xffff) . fromIntegral word32ToCDouble :: Fractional d => Word32 -> d word32ToCDouble = (/ 0xffffffff) . fromIntegral int32ToCDouble :: Fractional d => Int32 -> d int32ToCDouble = (/ 0x7fffffff) . fromIntegral from0to1 :: (Ord d, Num d) => d -> Bool from0to1 n = 0 <= n && n <= 1 {-# COMPLETE RgbaPremultipliedWord8 #-} pattern RgbaPremultipliedWord8 :: RealFrac d => Word8 -> Word8 -> Word8 -> Word8 -> Rgba d pattern RgbaPremultipliedWord8 r g b a <- (fromRgbaPremultipliedWord8 -> (r, g, b, a)) rgbaPremultipliedWord8 :: Word8 -> Word8 -> Word8 -> Word8 -> Maybe (Rgba d) rgbaPremultipliedWord8 r g b a | r <= a && g <= a && b <= a = Just $ RgbaPremultipliedWord8_ r g b a | otherwise = Nothing fromRgbaPremultipliedWord8 :: RealFrac d => Rgba d -> (Word8, Word8, Word8, Word8) fromRgbaPremultipliedWord8 = toPremultipliedWord8 . fromRgbaWord8 toPremultipliedWord8 :: (Word8, Word8, Word8, Word8) -> (Word8, Word8, Word8, Word8) toPremultipliedWord8 ( fromIntegral -> r, fromIntegral -> g, fromIntegral -> b, fromIntegral -> a) = (r', g', b', a') where [r', g', b', a'] = fromIntegral <$> [ r * a `div` 0xff, g * a `div` 0xff, b * a `div` 0xff, a :: Word16 ] unPremultipliedWord8 :: (Word8, Word8, Word8, Word8) -> [Word8] unPremultipliedWord8 ( fromIntegral -> r, fromIntegral -> g, fromIntegral -> b, fromIntegral -> a ) = fromIntegral <$> [ r * 0xff `div'` a, g * 0xff `div'` a, b * 0xff `div'` a, a :: Word16 ] {-# COMPLETE RgbaPremultipliedWord16 #-} pattern RgbaPremultipliedWord16 :: RealFrac d => Word16 -> Word16 -> Word16 -> Word16 -> Rgba d pattern RgbaPremultipliedWord16 r g b a <- (fromRgbaPremultipliedWord16 -> (r, g, b, a)) rgbaPremultipliedWord16 :: Word16 -> Word16 -> Word16 -> Word16 -> Maybe (Rgba d) rgbaPremultipliedWord16 r g b a | r <= a && g <= a && b <= a = Just $ RgbaPremultipliedWord16_ r g b a | otherwise = Nothing fromRgbaPremultipliedWord16 :: RealFrac d => Rgba d -> (Word16, Word16, Word16, Word16) fromRgbaPremultipliedWord16 = toPremultipliedWord16 . fromRgbaWord16 toPremultipliedWord16 :: (Word16, Word16, Word16, Word16) -> (Word16, Word16, Word16, Word16) toPremultipliedWord16 ( fromIntegral -> r, fromIntegral -> g, fromIntegral -> b, fromIntegral -> a ) = (r', g', b', a') where [r', g', b', a'] = fromIntegral <$> [ r * a `div` 0xffff, g * a `div` 0xffff, b * a `div` 0xffff, a :: Word32 ] unPremultipliedWord16 :: (Word16, Word16, Word16, Word16) -> [Word16] unPremultipliedWord16 ( fromIntegral -> r, fromIntegral -> g, fromIntegral -> b, fromIntegral -> a ) = fromIntegral <$> [ r * 0xffff `div'` a, g * 0xffff `div'` a, b * 0xff `div'` a, a :: Word32 ] pattern RgbaPremultipliedDouble :: (Eq d, Fractional d) => d -> d -> d -> d -> Rgba d pattern RgbaPremultipliedDouble r g b a <- (fromRgbaPremultipliedDouble -> (r, g, b, a)) rgbaPremultipliedDouble :: (Ord d, Num d) => d -> d -> d -> d -> Maybe (Rgba d) rgbaPremultipliedDouble r g b a | 0 <= r && r <= a, 0 <= g && g <= a, 0 <= b && b <= a, 0 <= a && a <= 1 = Just $ RgbaPremultipliedDouble_ r g b a | otherwise = Nothing fromRgbaPremultipliedDouble :: (Eq d, Fractional d) => Rgba d -> (d, d, d, d) fromRgbaPremultipliedDouble = toPremultipliedDouble . fromRgbaDouble toPremultipliedDouble :: Fractional d => (d, d, d, d) -> (d, d, d, d) toPremultipliedDouble (r, g, b, a) = (r * a, g * a, b * a, a) unPremultipliedDouble :: (Eq d, Fractional d) => (d, d, d, d) -> [d] unPremultipliedDouble (r, g, b, a) = [r ./. a, g ./. a, b ./. a, a] div' :: (Integral n, Bounded n) => n -> n -> n 0 `div'` 0 = 0 _ `div'` 0 = maxBound a `div'` b = a `div` b (./.) :: (Eq a, Fractional a) => a -> a -> a 0 ./. 0 = 0 a ./. b = a / b