{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -Wno-redundant-constraints #-} #endif -- | -- Module : Graphics.Image.ColorSpace -- Copyright : (c) Alexey Kuleshevich 2017 -- License : BSD3 -- Maintainer : Alexey Kuleshevich -- Stability : experimental -- Portability : non-portable -- module Graphics.Image.ColorSpace ( -- * Pixels -- ** Family of Pixels -- | Pixel is a type family for all available color spaces. Below is the -- listed of all class instances, that pixels are installed in, as well as all -- pixel constructors. -- -- >>> :t (PixelY 0) -- Black pixel in Luma -- (PixelY 0) :: Num e => Pixel Y e -- >>> PixelRGB 255 0 0 :: Pixel RGB Word8 -- Red pixel in RGB -- -- >>> PixelRGB 1 0 0 :: Pixel RGB Double -- Same red pixel in RGB with Double precision. -- -- >>> (PixelRGB 255 0 0 :: Pixel RGB Word8) == (toWord8 <$> (PixelRGB 1 0 0 :: Pixel RGB Double)) -- True -- Pixel(..), -- ** Luma (gray scale) -- | Conversion to Luma from other color spaces. toPixelY, toImageY, toPixelYA, toImageYA, -- ** RGB -- | Conversion to RGB from other color spaces. toPixelRGB, toImageRGB, toPixelRGBA, toImageRGBA, -- ** HSI -- | Conversion to HSI from other color spaces. toPixelHSI, toImageHSI, toPixelHSIA, toImageHSIA, -- ** CMYK -- | Conversion to CMYK from other color spaces. toPixelCMYK, toImageCMYK, toPixelCMYKA, toImageCMYKA, -- ** YCbCr -- | Conversion to YCbCr from other color spaces. toPixelYCbCr, toImageYCbCr, toPixelYCbCrA, toImageYCbCrA, -- ** Binary -- | This is a Binary colorspace, pixel's of which can be created using -- these __/constructors/__: -- -- [@'on'@] Represents value @1@ or 'True'. It's a foreground pixel and is -- displayed in black. -- -- [@'off'@] Represents value @0@ or 'False'. It's a background pixel and is -- displayed in white. -- -- Note, that values are inverted before writing to or reading from file, since -- grayscale images represent black as a @0@ value and white as @1@ on a -- @[0,1]@ scale. -- -- Binary pixels also behave as binary numbers with a size of 1-bit, for instance: -- -- >>> on + on -- equivalent to: 1 .|. 1 -- -- >>> (on + on) * off -- equivalent to: (1 .|. 1) .&. 0 -- -- >>> (on + on) - on -- -- toPixelBinary, fromPixelBinary, toImageBinary, fromImageBinary, module Graphics.Image.ColorSpace.Binary, -- ** Complex module Graphics.Image.ColorSpace.Complex, -- ** X squashWith, squashWith2, toPixelsX, fromPixelsX, toImagesX, fromImagesX, -- * ColorSpace -- ** Operations on Pixels eqTolPx, -- ** Luma Y(..), YA(..), ToY, ToYA, -- ** RGB RGB(..), RGBA(..), ToRGB, ToRGBA, -- ** HSI HSI(..), HSIA(..), ToHSI, ToHSIA, -- ** CMYK CMYK(..), CMYKA(..), ToCMYK, ToCMYKA, -- ** YCbCr YCbCr(..), YCbCrA(..), ToYCbCr, ToYCbCrA, -- ** X X(..), -- * Precision -- ** Image toWord8I, toWord16I, toWord32I, toFloatI, toDoubleI, -- ** Pixel toWord8Px, -- ** Componenet Word8, Word16, Word32, Word64 ) where import Data.Word import Graphics.Image.ColorSpace.Binary import Graphics.Image.ColorSpace.CMYK import Graphics.Image.ColorSpace.Complex import Graphics.Image.ColorSpace.HSI import Graphics.Image.ColorSpace.RGB import Graphics.Image.ColorSpace.X import Graphics.Image.ColorSpace.Y import Graphics.Image.ColorSpace.YCbCr import Graphics.Image.Interface as I import Graphics.Image.Interface.Elevator -- -- Binary: -- | Convert to a `Binary` pixel. toPixelBinary :: ColorSpace cs e => Pixel cs e -> Pixel X Bit toPixelBinary px = if px == 0 then on else off -- | Convert a Binary pixel to Luma pixel fromPixelBinary :: Pixel X Bit -> Pixel Y Word8 fromPixelBinary b = PixelY $ if isOn b then minBound else maxBound {-# INLINE fromPixelBinary #-} -- | Convert to a `Binary` image. toImageBinary :: (Array arr cs e, Array arr X Bit) => Image arr cs e -> Image arr X Bit toImageBinary = I.map toPixelBinary {-# INLINE toImageBinary #-} -- | Convert a Binary image to Luma image fromImageBinary :: (Array arr X Bit, Array arr Y Word8) => Image arr X Bit -> Image arr Y Word8 fromImageBinary = I.map fromPixelBinary {-# INLINE fromImageBinary #-} -- | Check weather two Pixels are equal within a tolerance. Useful for comparing -- pixels with `Float` or `Double` precision. eqTolPx :: (ColorSpace cs e, Ord e) => e -> Pixel cs e -> Pixel cs e -> Bool eqTolPx !tol = foldlPx2 comp True where comp !acc !e1 !e2 = acc && max e1 e2 - min e1 e2 <= tol {-# INLINE comp #-} {-# INLINE eqTolPx #-} -- ToY -- | Conversion to Luma color space. class ColorSpace cs e => ToY cs e where -- | Convert a pixel to Luma pixel. toPixelY :: Pixel cs e -> Pixel Y Double -- | Convert an image to Luma image. toImageY :: (ToY cs e, Array arr cs e, Array arr Y Double) => Image arr cs e -> Image arr Y Double toImageY = I.map toPixelY {-# INLINE toImageY #-} instance Elevator e => ToY X e where toPixelY (PixelX y) = PixelY $ toDouble y {-# INLINE toPixelY #-} instance Elevator e => ToY Y e where toPixelY (PixelY y) = PixelY $ toDouble y {-# INLINE toPixelY #-} instance Elevator e => ToY YA e where toPixelY (PixelYA y _) = PixelY $ toDouble y {-# INLINE toPixelY #-} -- | Computes Luma: @ Y' = 0.299 * R' + 0.587 * G' + 0.114 * B' @ instance Elevator e => ToY RGB e where toPixelY (fmap toDouble -> (PixelRGB r g b)) = PixelY (0.299*r + 0.587*g + 0.114*b) {-# INLINE toPixelY #-} instance Elevator e => ToY RGBA e where toPixelY = toPixelY . dropAlpha {-# INLINE toPixelY #-} instance Elevator e => ToY HSI e where toPixelY = toPixelY . toPixelRGB . fmap toDouble {-# INLINE toPixelY #-} instance Elevator e => ToY HSIA e where toPixelY = toPixelY . dropAlpha {-# INLINE toPixelY #-} instance Elevator e => ToY CMYK e where toPixelY = toPixelY . toPixelRGB . fmap toDouble {-# INLINE toPixelY #-} instance Elevator e => ToY CMYKA e where toPixelY = toPixelY . toPixelRGB . fmap toDouble . dropAlpha {-# INLINE toPixelY #-} instance Elevator e => ToY YCbCr e where toPixelY (PixelYCbCr y _ _) = PixelY $ toDouble y {-# INLINE toPixelY #-} instance Elevator e => ToY YCbCrA e where toPixelY (PixelYCbCrA y _ _ _) = PixelY $ toDouble y {-# INLINE toPixelY #-} -- ToYA -- | Conversion to Luma from another color space. class ToY cs e => ToYA cs e where -- | Convert a pixel to Luma pixel with Alpha. toPixelYA :: Pixel cs e -> Pixel YA Double toPixelYA = addAlpha 1 . toPixelY {-# INLINE toPixelYA #-} -- | Convert an image to Luma image with Alpha. toImageYA :: (ToYA cs e, Array arr cs e, Array arr YA Double) => Image arr cs e -> Image arr YA Double toImageYA = I.map toPixelYA {-# INLINE toImageYA #-} instance ToYA X Bit where toPixelYA (PixelX y) = PixelYA (toDouble y) 1 {-# INLINE toPixelYA #-} instance ToY Y e => ToYA Y e instance Elevator e => ToYA YA e where toPixelYA = fmap toDouble {-# INLINE toPixelYA #-} instance ToY RGB e => ToYA RGB e instance Elevator e => ToYA RGBA e where toPixelYA !px = addAlpha (toDouble $ getAlpha px) (toPixelY (dropAlpha px)) {-# INLINE toPixelYA #-} instance ToY HSI e => ToYA HSI e instance Elevator e => ToYA HSIA e where toPixelYA !px = addAlpha (toDouble $ getAlpha px) (toPixelY (dropAlpha px)) {-# INLINE toPixelYA #-} instance ToY CMYK e => ToYA CMYK e instance Elevator e => ToYA CMYKA e where toPixelYA !px = addAlpha (toDouble $ getAlpha px) (toPixelY (dropAlpha px)) {-# INLINE toPixelYA #-} instance ToY YCbCr e => ToYA YCbCr e instance Elevator e => ToYA YCbCrA e where toPixelYA !px = addAlpha (toDouble $ getAlpha px) (toPixelY (dropAlpha px)) {-# INLINE toPixelYA #-} -- ToRGB -- | Conversion to `RGB` color space. class ColorSpace cs e => ToRGB cs e where -- | Convert to an `RGB` pixel. toPixelRGB :: Pixel cs e -> Pixel RGB Double -- | Convert to an `RGB` image. toImageRGB :: (ToRGB cs e, Array arr cs e, Array arr RGB Double) => Image arr cs e -> Image arr RGB Double toImageRGB = I.map toPixelRGB {-# INLINE toImageRGB #-} instance ToRGB X Bit where toPixelRGB (PixelX b) = pure $ toDouble b {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB Y e where toPixelRGB (PixelY g) = promote $ toDouble g {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB YA e where toPixelRGB = toPixelRGB . dropAlpha {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB RGB e where toPixelRGB = fmap toDouble {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB RGBA e where toPixelRGB = fmap toDouble . dropAlpha {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB HSI e where toPixelRGB (fmap toDouble -> PixelHSI h' s i) = getRGB (h'*2*pi) where !is = i*s !second = i - is getFirst !a !b = i + is*cos a/cos b {-# INLINE getFirst #-} getThird !v1 !v2 = i + 2*is + v1 - v2 {-# INLINE getThird #-} getRGB h | h < 0 = error ("HSI pixel is not properly scaled, Hue: "++show h') | h < 2*pi/3 = let !r = getFirst h (pi/3 - h) !b = second !g = getThird b r in PixelRGB r g b | h < 4*pi/3 = let !g = getFirst (h - 2*pi/3) (h + pi) !r = second !b = getThird r g in PixelRGB r g b | h < 2*pi = let !b = getFirst (h - 4*pi/3) (2*pi - pi/3 - h) !g = second !r = getThird g b in PixelRGB r g b | otherwise = error ("HSI pixel is not properly scaled, Hue: "++show h') {-# INLINE getRGB #-} {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB HSIA e where toPixelRGB = toPixelRGB . dropAlpha {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB YCbCr e where toPixelRGB (fmap toDouble -> PixelYCbCr y cb cr) = PixelRGB r g b where !r = clamp01 (y + 1.402*(cr - 0.5)) !g = clamp01 (y - 0.34414*(cb - 0.5) - 0.71414*(cr - 0.5)) !b = clamp01 (y + 1.772*(cb - 0.5)) {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB YCbCrA e where toPixelRGB = toPixelRGB . dropAlpha {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB CMYK e where toPixelRGB (fmap toDouble -> PixelCMYK c m y k) = PixelRGB r g b where !r = (1-c)*(1-k) !g = (1-m)*(1-k) !b = (1-y)*(1-k) {-# INLINE toPixelRGB #-} instance Elevator e => ToRGB CMYKA e where toPixelRGB = toPixelRGB . dropAlpha {-# INLINE toPixelRGB #-} -- ToRGBA -- | Conversion to `RGBA` from another color space with Alpha channel. class ToRGB cs e => ToRGBA cs e where -- | Convert to an `RGBA` pixel. toPixelRGBA :: Pixel cs e -> Pixel RGBA Double toPixelRGBA = addAlpha 1 . toPixelRGB {-# INLINE toPixelRGBA #-} -- | Convert to an `RGBA` image. toImageRGBA :: (ToRGBA cs e, Array arr cs e, Array arr RGBA Double) => Image arr cs e -> Image arr RGBA Double toImageRGBA = I.map toPixelRGBA {-# INLINE toImageRGBA #-} instance ToRGBA X Bit instance ToRGB Y e => ToRGBA Y e instance Elevator e => ToRGBA YA e where toPixelRGBA !px = addAlpha (toDouble $ getAlpha px) (toPixelRGB (dropAlpha px)) {-# INLINE toPixelRGBA #-} instance ToRGB RGB e => ToRGBA RGB e instance Elevator e => ToRGBA RGBA e where toPixelRGBA = fmap toDouble {-# INLINE toPixelRGBA #-} instance ToRGB HSI e => ToRGBA HSI e instance Elevator e => ToRGBA HSIA e where toPixelRGBA !px = addAlpha (toDouble $ getAlpha px) (toPixelRGB (dropAlpha px)) {-# INLINE toPixelRGBA #-} instance ToRGB CMYK e => ToRGBA CMYK e instance Elevator e => ToRGBA CMYKA e where toPixelRGBA !px = addAlpha (toDouble $ getAlpha px) (toPixelRGB (dropAlpha px)) {-# INLINE toPixelRGBA #-} instance ToRGB YCbCr e => ToRGBA YCbCr e instance Elevator e => ToRGBA YCbCrA e where toPixelRGBA !px = addAlpha (toDouble $ getAlpha px) (toPixelRGB (dropAlpha px)) {-# INLINE toPixelRGBA #-} -- ToHSI -- | Conversion to `HSI` color space. class ColorSpace cs e => ToHSI cs e where -- | Convert to an `HSI` pixel. toPixelHSI :: Pixel cs e -> Pixel HSI Double -- | Convert to an `HSI` image. toImageHSI :: (ToHSI cs e, Array arr cs e, Array arr HSI Double) => Image arr cs e -> Image arr HSI Double toImageHSI = I.map toPixelHSI {-# INLINE toImageHSI #-} instance Elevator e => ToHSI Y e where toPixelHSI (PixelY y) = PixelHSI 0 0 $ toDouble y {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI YA e where toPixelHSI = toPixelHSI . dropAlpha {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI RGB e where toPixelHSI (fmap toDouble -> PixelRGB r g b) = PixelHSI h s i where !h' = atan2 y x !h = (if h' < 0 then h' + 2*pi else h') / (2*pi) !s = if i == 0 then 0 else 1 - minimum [r, g, b] / i !i = (r + g + b) / 3 !x = (2*r - g - b) / 2.449489742783178 !y = (g - b) / 1.4142135623730951 {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI RGBA e where toPixelHSI = toPixelHSI . dropAlpha {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI HSI e where toPixelHSI = fmap toDouble {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI HSIA e where toPixelHSI = toPixelHSI . dropAlpha {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI YCbCr e where toPixelHSI = toPixelHSI . toPixelRGB {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI YCbCrA e where toPixelHSI = toPixelHSI . dropAlpha {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI CMYK e where toPixelHSI = toPixelHSI . toPixelRGB {-# INLINE toPixelHSI #-} instance Elevator e => ToHSI CMYKA e where toPixelHSI = toPixelHSI . dropAlpha {-# INLINE toPixelHSI #-} -- ToHSIA -- | Conversion to `HSIA` from another color space with Alpha channel. class ToHSI cs e => ToHSIA cs e where -- | Convert to an `HSIA` pixel. toPixelHSIA :: Pixel cs e -> Pixel HSIA Double toPixelHSIA = addAlpha 1 . toPixelHSI {-# INLINE toPixelHSIA #-} -- | Convert to an `HSIA` image. toImageHSIA :: (ToHSIA cs e, Array arr cs e, Array arr HSIA Double) => Image arr cs e -> Image arr HSIA Double toImageHSIA = I.map toPixelHSIA {-# INLINE toImageHSIA #-} instance ToHSI Y e => ToHSIA Y e instance Elevator e => ToHSIA YA e where toPixelHSIA !px = addAlpha (toDouble $ getAlpha px) (toPixelHSI (dropAlpha px)) {-# INLINE toPixelHSIA #-} instance ToHSI RGB e => ToHSIA RGB e instance Elevator e => ToHSIA RGBA e where toPixelHSIA !px = addAlpha (toDouble $ getAlpha px) (toPixelHSI (dropAlpha px)) {-# INLINE toPixelHSIA #-} instance ToHSI HSI e => ToHSIA HSI e instance Elevator e => ToHSIA HSIA e where toPixelHSIA = fmap toDouble {-# INLINE toPixelHSIA #-} instance ToHSI CMYK e => ToHSIA CMYK e instance Elevator e => ToHSIA CMYKA e where toPixelHSIA !px = addAlpha (toDouble $ getAlpha px) (toPixelHSI (dropAlpha px)) {-# INLINE toPixelHSIA #-} instance ToHSI YCbCr e => ToHSIA YCbCr e instance Elevator e => ToHSIA YCbCrA e where toPixelHSIA !px = addAlpha (toDouble $ getAlpha px) (toPixelHSI (dropAlpha px)) {-# INLINE toPixelHSIA #-} -- ToCMYK -- | Conversion to `CMYK` color space. class ColorSpace cs e => ToCMYK cs e where -- | Convert to a `CMYK` pixel. toPixelCMYK :: Pixel cs e -> Pixel CMYK Double -- | Convert to a `CMYK` image. toImageCMYK :: (ToCMYK cs e, Array arr cs e, Array arr CMYK Double) => Image arr cs e -> Image arr CMYK Double toImageCMYK = I.map toPixelCMYK {-# INLINE toImageCMYK #-} instance Elevator e => ToCMYK Y e where toPixelCMYK = toPixelCMYK . toPixelRGB {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK YA e where toPixelCMYK = toPixelCMYK . dropAlpha {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK RGB e where toPixelCMYK (fmap toDouble -> PixelRGB r g b) = PixelCMYK c m y k where !c = (1 - r - k)/(1 - k) !m = (1 - g - k)/(1 - k) !y = (1 - b - k)/(1 - k) !k = 1 - max r (max g b) {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK RGBA e where toPixelCMYK = toPixelCMYK . dropAlpha {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK HSI e where toPixelCMYK = toPixelCMYK . toPixelRGB {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK HSIA e where toPixelCMYK = toPixelCMYK . dropAlpha {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK CMYK e where toPixelCMYK = fmap toDouble {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK CMYKA e where toPixelCMYK = toPixelCMYK . dropAlpha {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK YCbCr e where toPixelCMYK = toPixelCMYK . toPixelRGB {-# INLINE toPixelCMYK #-} instance Elevator e => ToCMYK YCbCrA e where toPixelCMYK = toPixelCMYK . dropAlpha {-# INLINE toPixelCMYK #-} -- ToCMYKA -- | Conversion to `CMYKA`. class ToCMYK cs e => ToCMYKA cs e where -- | Convert to a `CMYKA` pixel. toPixelCMYKA :: Pixel cs e -> Pixel CMYKA Double toPixelCMYKA = addAlpha 1 . toPixelCMYK {-# INLINE toPixelCMYKA #-} -- | Convert to a `CMYKA` image. toImageCMYKA :: (ToCMYKA cs e, Array arr cs e, Array arr CMYKA Double) => Image arr cs e -> Image arr CMYKA Double toImageCMYKA = I.map toPixelCMYKA {-# INLINE toImageCMYKA #-} instance ToCMYK Y e => ToCMYKA Y e instance Elevator e => ToCMYKA YA e where toPixelCMYKA !px = addAlpha (toDouble $ getAlpha px) (toPixelCMYK (dropAlpha px)) {-# INLINE toPixelCMYKA #-} instance ToCMYK RGB e => ToCMYKA RGB e instance Elevator e => ToCMYKA RGBA e where toPixelCMYKA !px = addAlpha (toDouble $ getAlpha px) (toPixelCMYK (dropAlpha px)) {-# INLINE toPixelCMYKA #-} instance ToCMYK HSI e => ToCMYKA HSI e instance Elevator e => ToCMYKA HSIA e where toPixelCMYKA !px = addAlpha (toDouble $ getAlpha px) (toPixelCMYK (dropAlpha px)) {-# INLINE toPixelCMYKA #-} instance ToCMYK CMYK e => ToCMYKA CMYK e instance Elevator e => ToCMYKA CMYKA e where toPixelCMYKA = fmap toDouble {-# INLINE toPixelCMYKA #-} instance ToCMYK YCbCr e => ToCMYKA YCbCr e instance Elevator e => ToCMYKA YCbCrA e where toPixelCMYKA !px = addAlpha (toDouble $ getAlpha px) (toPixelCMYK (dropAlpha px)) {-# INLINE toPixelCMYKA #-} -- ToYCbCr -- | Conversion to `YCbCr` color space. class ColorSpace cs e => ToYCbCr cs e where -- | Convert to an `YCbCr` pixel. toPixelYCbCr :: Pixel cs e -> Pixel YCbCr Double -- | Convert to an `YCbCr` image. toImageYCbCr :: (ToYCbCr cs e, Array arr cs e, Array arr YCbCr Double) => Image arr cs e -> Image arr YCbCr Double toImageYCbCr = I.map toPixelYCbCr {-# INLINE toImageYCbCr #-} instance Elevator e => ToYCbCr Y e where toPixelYCbCr = toPixelYCbCr . toPixelRGB {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr YA e where toPixelYCbCr = toPixelYCbCr . dropAlpha {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr RGB e where toPixelYCbCr (fmap toDouble -> PixelRGB r g b) = PixelYCbCr y cb cr where !y = clamp01 ( 0.299*r + 0.587*g + 0.114*b) !cb = clamp01 (0.5 - 0.168736*r - 0.331264*g + 0.5*b) !cr = clamp01 (0.5 + 0.5*r - 0.418688*g - 0.081312*b) {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr RGBA e where toPixelYCbCr = toPixelYCbCr . dropAlpha {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr HSI e where toPixelYCbCr = toPixelYCbCr . toPixelRGB {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr HSIA e where toPixelYCbCr = toPixelYCbCr . dropAlpha {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr YCbCr e where toPixelYCbCr = fmap toDouble {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr YCbCrA e where toPixelYCbCr = toPixelYCbCr . dropAlpha {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr CMYK e where toPixelYCbCr = toPixelYCbCr . toPixelRGB {-# INLINE toPixelYCbCr #-} instance Elevator e => ToYCbCr CMYKA e where toPixelYCbCr = toPixelYCbCr . dropAlpha {-# INLINE toPixelYCbCr #-} -- ToYCbCrA -- | Conversion to `YCbCrA` from another color space with Alpha channel. class ToYCbCr cs e => ToYCbCrA cs e where -- | Convert to an `YCbCrA` pixel. toPixelYCbCrA :: Pixel cs e -> Pixel YCbCrA Double toPixelYCbCrA = addAlpha 1 . toPixelYCbCr {-# INLINE toPixelYCbCrA #-} -- | Convert to an `YCbCrA` image. toImageYCbCrA :: (ToYCbCrA cs e, Array arr cs e, Array arr YCbCrA Double) => Image arr cs e -> Image arr YCbCrA Double toImageYCbCrA = I.map toPixelYCbCrA {-# INLINE toImageYCbCrA #-} instance ToYCbCr Y e => ToYCbCrA Y e instance Elevator e => ToYCbCrA YA e where toPixelYCbCrA !px = addAlpha (toDouble $ getAlpha px) (toPixelYCbCr (dropAlpha px)) {-# INLINE toPixelYCbCrA #-} instance ToYCbCr RGB e => ToYCbCrA RGB e instance ToYCbCr HSI e => ToYCbCrA HSI e instance Elevator e => ToYCbCrA HSIA e where toPixelYCbCrA !px = addAlpha (toDouble $ getAlpha px) (toPixelYCbCr (dropAlpha px)) {-# INLINE toPixelYCbCrA #-} instance Elevator e => ToYCbCrA RGBA e where toPixelYCbCrA !px = addAlpha (toDouble $ getAlpha px) (toPixelYCbCr (dropAlpha px)) {-# INLINE toPixelYCbCrA #-} instance ToYCbCr CMYK e => ToYCbCrA CMYK e instance Elevator e => ToYCbCrA CMYKA e where toPixelYCbCrA !px = addAlpha (toDouble $ getAlpha px) (toPixelYCbCr (dropAlpha px)) {-# INLINE toPixelYCbCrA #-} instance ToYCbCr YCbCr e => ToYCbCrA YCbCr e instance Elevator e => ToYCbCrA YCbCrA e where toPixelYCbCrA = fmap toDouble {-# INLINE toPixelYCbCrA #-} -- | Change image precision to `Word8`. toWord8I :: (Functor (Pixel cs), Array arr cs e, Array arr cs Word8) => Image arr cs e -> Image arr cs Word8 toWord8I = I.map (fmap toWord8) {-# INLINABLE toWord8I #-} {- {-# SPECIALIZE toWord8I :: (Array arr Y Double, Array arr Y Word8) => Image arr Y Double -> Image arr Y Word8 #-} {-# SPECIALIZE toWord8I :: (Array arr YA Double, Array arr YA Word8) => Image arr YA Double -> Image arr YA Word8 #-} {-# SPECIALIZE toWord8I :: (Array arr RGB Double, Array arr RGB Word8) => Image arr RGB Double -> Image arr RGB Word8 #-} {-# SPECIALIZE toWord8I :: (Array arr RGBA Double, Array arr RGBA Word8) => Image arr RGBA Double -> Image arr RGBA Word8 #-} -} -- | Change image precision to `Word16`. toWord16I :: (Functor (Pixel cs), Array arr cs e, Array arr cs Word16) => Image arr cs e -> Image arr cs Word16 toWord16I = I.map (fmap toWord16) {-# INLINABLE toWord16I #-} -- | Change image precision to `Word32`. toWord32I :: (Functor (Pixel cs), Array arr cs e, Array arr cs Word32) => Image arr cs e -> Image arr cs Word32 toWord32I = I.map (fmap toWord32) {-# INLINABLE toWord32I #-} -- | Change image precision to `Float`. toFloatI :: (Functor (Pixel cs), Array arr cs e, Array arr cs Float) => Image arr cs e -> Image arr cs Float toFloatI = I.map (fmap toFloat) {-# INLINABLE toFloatI #-} -- | Change image precision to `Double`. toDoubleI :: (Functor (Pixel cs), Array arr cs e, Array arr cs Double) => Image arr cs e -> Image arr cs Double toDoubleI = I.map (fmap toDouble) {-# INLINABLE toDoubleI #-} -- | Change pixel precision to `Word8`. toWord8Px :: (Functor (Pixel cs), Elevator e) => Pixel cs e -> Pixel cs Word8 toWord8Px = fmap toWord8 {-# INLINABLE toWord8Px #-}