packages feed

union-color-0.1.2.1: src/Data/Color/Internal.hs

{-# 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