hip-1.1.0.0: src/Graphics/Image/ColorSpace/Binary.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
-- |
-- Module : Graphics.Image.ColorSpace.Binary
-- Copyright : (c) Alexey Kuleshevich 2016
-- License : BSD3
-- Maintainer : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability : experimental
-- Portability : non-portable
--
module Graphics.Image.ColorSpace.Binary (
Binary(..), Bit(..), on, off, isOn, isOff, fromBool, complement
) where
import Prelude hiding (map)
import Data.Word (Word8)
import Graphics.Image.Interface
import Data.Typeable (Typeable)
import qualified Data.Monoid as M (mappend, mempty)
import qualified Data.Colour as C
-- | 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
-- <Binary:(1)>
-- >>> (on + on) * off -- equivalent to: (1 .|. 1) .&. 0
-- <Binary:(0)>
-- >>> (on + on) - on
-- <Binary:(0)>
--
data Binary = Binary deriving (Eq, Enum, Show, Typeable)
-- | Under the hood, Binary pixels are represented as 'Word8' that can only take
-- values of @0@ or @1@.
newtype Bit = Bit Word8 deriving (Ord, Eq, Typeable)
-- | Represents value 'True' or @1@ in binary. Often also called a foreground
-- pixel of an object.
on :: Pixel Binary Bit
on = PixelBinary (Bit 1)
{-# INLINE on #-}
-- | Represents value 'False' or @0@ in binary. Often also called a background
-- pixel.
off :: Pixel Binary Bit
off = PixelBinary (Bit 0)
{-# INLINE off #-}
-- | Convert a 'Bool' to a 'PixelBin' pixel.
--
-- >>> isOn (fromBool True)
-- True
--
fromBool :: Bool -> Pixel Binary Bit
fromBool False = off
fromBool True = on
{-# INLINE fromBool #-}
-- | Test if Pixel's value is 'on'.
isOn :: Pixel Binary Bit -> Bool
isOn (PixelBinary (Bit 0)) = False
isOn _ = True
{-# INLINE isOn #-}
-- | Test if Pixel's value is 'off'.
isOff :: Pixel Binary Bit -> Bool
isOff = not . isOn
{-# INLINE isOff #-}
-- | Invert value of a pixel. Equivalent of 'not' for Bool's.
complement :: Pixel Binary Bit -> Pixel Binary Bit
complement = fromBool . isOff
{-# INLINE complement #-}
instance ColorSpace Binary where
type PixelElt Binary e = e
data Pixel Binary e = PixelBinary !e deriving Eq
fromChannel = PixelBinary
{-# INLINE fromChannel #-}
fromElt = PixelBinary
{-# INLINE fromElt #-}
toElt (PixelBinary b) = b
{-# INLINE toElt #-}
getPxCh (PixelBinary b) _ = b
{-# INLINE getPxCh #-}
chOp !f (PixelBinary b) = PixelBinary (f Binary b)
{-# INLINE chOp #-}
pxOp !f (PixelBinary b) = PixelBinary (f b)
{-# INLINE pxOp #-}
chApp (PixelBinary f) (PixelBinary b) = PixelBinary (f b)
{-# INLINE chApp #-}
pxFoldMap f (PixelBinary b) = f b `M.mappend` M.mempty
{-# INLINE pxFoldMap #-}
csColour _ = C.opaque C.black
instance Show (Pixel Binary Bit) where
show (PixelBinary (Bit 0)) = "<Binary:(0)>"
show _ = "<Binary:(1)>"
instance Num Bit where
(Bit 0) + (Bit 0) = Bit 0
_ + _ = Bit 1
{-# INLINE (+) #-}
_ - (Bit 1) = Bit 0
_ - _ = Bit 1
{-# INLINE (-) #-}
_ * (Bit 0) = Bit 0
(Bit 0) * _ = Bit 0
_ * _ = Bit 1
{-# INLINE (*) #-}
abs = id
{-# INLINE abs #-}
signum = id
{-# INLINE signum #-}
fromInteger 0 = Bit 0
fromInteger _ = Bit 1
{-# INLINE fromInteger #-}