packages feed

hip 1.4.0.1 → 1.5.0.0

raw patch · 36 files changed

+1237/−911 lines, 36 filesdep ~bytestringbinary-addedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: bytestring

API changes (from Hackage documentation)

- Graphics.Image.ColorSpace: Gray :: Gray
- Graphics.Image.ColorSpace: data Gray
- Graphics.Image.ColorSpace: fromGrayImages :: forall arr cs e. (Array arr Gray e, Array arr cs e) => [Image arr Gray e] -> [cs] -> Image arr cs e
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.HSI.ToHSI Graphics.Image.ColorSpace.Luma.Y
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.HSI.ToHSIA Graphics.Image.ColorSpace.Luma.YA
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToY Graphics.Image.ColorSpace.CMYK.CMYK
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToY Graphics.Image.ColorSpace.Gray.Gray
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToY Graphics.Image.ColorSpace.HSI.HSI
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToY Graphics.Image.ColorSpace.RGB.RGB
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToY Graphics.Image.ColorSpace.YCbCr.YCbCr
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToYA Graphics.Image.ColorSpace.HSI.HSIA
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToYA Graphics.Image.ColorSpace.RGB.RGBA
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Luma.ToYA Graphics.Image.ColorSpace.YCbCr.YCbCrA
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.RGB.ToRGB Graphics.Image.ColorSpace.Luma.Y
- Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.RGB.ToRGBA Graphics.Image.ColorSpace.Luma.YA
- Graphics.Image.ColorSpace: toGrayImages :: (Array arr cs e, Array arr Gray e) => Image arr cs e -> [Image arr Gray e]
- Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.Gray.Gray
- Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.Luma.Y
- Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.Luma.YA
- Graphics.Image.Interface: broadcastC :: ColorSpace cs e => e -> Pixel cs e
- Graphics.Image.Interface: mapPx :: ColorSpace cs e => (e -> e) -> Pixel cs e -> Pixel cs e
- Graphics.Image.Interface: singleton :: Array arr cs e => Pixel cs e -> Image arr cs e
- Graphics.Image.Interface: zipWithPx :: ColorSpace cs e => (e -> e -> e) -> Pixel cs e -> Pixel cs e -> Pixel cs e
- Graphics.Image.Processing: downsampleF :: Array arr cs e => (Int, Int) -> Image arr cs e -> Image arr cs e
- Graphics.Image.Processing: upsampleF :: Array arr cs e => (Int, Int) -> Image arr cs e -> Image arr cs e
+ Graphics.Image: eqTol :: (Array arr Binary Bit, Array arr cs e, Ord e, Num e) => e -> Image arr cs e -> Image arr cs e -> Bool
+ Graphics.Image.ColorSpace: X :: X
+ Graphics.Image.ColorSpace: data X
+ Graphics.Image.ColorSpace: eqTolPx :: (ColorSpace cs e, Num e, Ord e) => e -> Pixel cs e -> Pixel cs e -> Bool
+ Graphics.Image.ColorSpace: fromImagesX :: forall arr cs e. (Array arr X e, Array arr cs e) => [(cs, Image arr X e)] -> Image arr cs e
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.HSI.ToHSI Graphics.Image.ColorSpace.Y.Y
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.HSI.ToHSIA Graphics.Image.ColorSpace.Y.YA
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.RGB.ToRGB Graphics.Image.ColorSpace.Y.Y
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.RGB.ToRGBA Graphics.Image.ColorSpace.Y.YA
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToY Graphics.Image.ColorSpace.CMYK.CMYK
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToY Graphics.Image.ColorSpace.HSI.HSI
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToY Graphics.Image.ColorSpace.RGB.RGB
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToY Graphics.Image.ColorSpace.X.X
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToY Graphics.Image.ColorSpace.YCbCr.YCbCr
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToYA Graphics.Image.ColorSpace.HSI.HSIA
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToYA Graphics.Image.ColorSpace.RGB.RGBA
+ Graphics.Image.ColorSpace: instance Graphics.Image.ColorSpace.Y.ToYA Graphics.Image.ColorSpace.YCbCr.YCbCrA
+ Graphics.Image.ColorSpace: toImagesX :: (Array arr cs e, Array arr X e) => Image arr cs e -> [Image arr X e]
+ Graphics.Image.IO.Formats: InputBMP :: InputFormat
+ Graphics.Image.IO.Formats: InputGIF :: InputFormat
+ Graphics.Image.IO.Formats: InputHDR :: InputFormat
+ Graphics.Image.IO.Formats: InputJPG :: InputFormat
+ Graphics.Image.IO.Formats: InputPNG :: InputFormat
+ Graphics.Image.IO.Formats: InputPNM :: InputFormat
+ Graphics.Image.IO.Formats: InputTGA :: InputFormat
+ Graphics.Image.IO.Formats: InputTIF :: InputFormat
+ Graphics.Image.IO.Formats: OutputBMP :: OutputFormat
+ Graphics.Image.IO.Formats: OutputGIF :: OutputFormat
+ Graphics.Image.IO.Formats: OutputHDR :: OutputFormat
+ Graphics.Image.IO.Formats: OutputJPG :: OutputFormat
+ Graphics.Image.IO.Formats: OutputPNG :: OutputFormat
+ Graphics.Image.IO.Formats: OutputTGA :: OutputFormat
+ Graphics.Image.IO.Formats: OutputTIF :: OutputFormat
+ Graphics.Image.IO.Formats: instance GHC.Enum.Bounded Graphics.Image.IO.Formats.InputFormat
+ Graphics.Image.IO.Formats: instance GHC.Enum.Bounded Graphics.Image.IO.Formats.OutputFormat
+ Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.X.X
+ Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.Y.Y
+ Graphics.Image.IO.Histogram: instance Graphics.Image.IO.Histogram.ChannelColour Graphics.Image.ColorSpace.Y.YA
+ Graphics.Image.Interface: exchangeThrough :: (Exchangable arr2 arr1, Exchangable arr1 arr, Array arr2 cs e, Array arr1 cs e, Array arr cs e) => arr1 -> arr -> Image arr2 cs e -> Image arr cs e
+ Graphics.Image.Interface: foldlPx2 :: ColorSpace cs e => (b -> e -> e -> b) -> b -> Pixel cs e -> Pixel cs e -> b
+ Graphics.Image.Interface: liftPx :: ColorSpace cs e => (e -> e) -> Pixel cs e -> Pixel cs e
+ Graphics.Image.Interface: liftPx2 :: ColorSpace cs e => (e -> e -> e) -> Pixel cs e -> Pixel cs e -> Pixel cs e
+ Graphics.Image.Interface: promote :: ColorSpace cs e => e -> Pixel cs e
+ Graphics.Image.Interface: scalar :: Array arr cs e => Pixel cs e -> Image arr cs e
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Repa.Storable.RPS Graphics.Image.Interface.Vector.Unboxed.VU
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Repa.Storable.RSS Graphics.Image.Interface.Vector.Unboxed.VU
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Repa.Unboxed.RPU Graphics.Image.Interface.Vector.Storable.VS
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Repa.Unboxed.RSU Graphics.Image.Interface.Vector.Storable.VS
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Vector.Storable.VS Graphics.Image.Interface.Repa.Unboxed.RPU
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Vector.Storable.VS Graphics.Image.Interface.Repa.Unboxed.RSU
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Vector.Unboxed.VU Graphics.Image.Interface.Repa.Storable.RPS
+ Graphics.Image.Interface.Repa: instance Graphics.Image.Interface.Exchangable Graphics.Image.Interface.Vector.Unboxed.VU Graphics.Image.Interface.Repa.Storable.RSS
+ Graphics.Image.Processing.Binary: and :: Array arr Binary Bit => Image arr Binary Bit -> Bool
+ Graphics.Image.Processing.Binary: or :: Array arr Binary Bit => Image arr Binary Bit -> Bool
- Graphics.Image: normalize :: (Array arr cs e, Array arr Gray e, Fractional e, Fractional (Pixel cs e), Ord e) => Image arr cs e -> Image arr cs e
+ Graphics.Image: normalize :: (Array arr cs e, Array arr X e, Fractional e, Ord e) => Image arr cs e -> Image arr cs e
- Graphics.Image.ColorSpace: class (Eq cs, Enum cs, Show cs, Typeable cs, Elevator e, Typeable e) => ColorSpace cs e where foldrPx f !z0 !xs = foldlPx f' id xs z0 where f' k x !z = k $! f x z foldlPx f !z0 !xs = foldrPx f' id xs z0 where f' x k !z = k $! f z x foldl1Px f !xs = fromMaybe (error "foldl1: empty Pixel") (foldlPx mf Nothing xs) where mf m !y = Just (case m of { Nothing -> y Just x -> f x y }) toListPx !px = foldr' f [] (enumFrom (toEnum 0)) where f !cs !ls = getPxC px cs : ls
+ Graphics.Image.ColorSpace: class (Eq cs, Enum cs, Show cs, Bounded cs, Typeable cs, Elevator e, Typeable e) => ColorSpace cs e where foldrPx f !z0 !xs = foldlPx f' id xs z0 where f' k x !z = k $! f x z foldlPx f !z0 !xs = foldrPx f' id xs z0 where f' x k !z = k $! f z x foldl1Px f !xs = fromMaybe (error "foldl1Px: empty Pixel") (foldlPx mf Nothing xs) where mf m !y = Just (case m of { Nothing -> y Just x -> f x y }) toListPx !px = foldr' f [] (enumFrom (toEnum 0)) where f !cs !ls = getPxC px cs : ls
- Graphics.Image.ColorSpace: complement :: Pixel Binary Bit -> Pixel Binary Bit
+ Graphics.Image.ColorSpace: complement :: Bits a => a -> a
- Graphics.Image.IO.Histogram: getHistogram :: MArray arr Gray e => Image arr Gray e -> Histogram
+ Graphics.Image.IO.Histogram: getHistogram :: MArray arr X e => Image arr X e -> Histogram
- Graphics.Image.IO.Histogram: getHistograms :: forall arr cs e. (ChannelColour cs, MArray arr Gray e, Array arr Gray e, MArray arr cs e, Array arr cs e) => Image arr cs e -> Histograms
+ Graphics.Image.IO.Histogram: getHistograms :: forall arr cs e. (ChannelColour cs, MArray arr X e, Array arr X e, MArray arr cs e, Array arr cs e) => Image arr cs e -> Histograms
- Graphics.Image.Interface: class (Eq cs, Enum cs, Show cs, Typeable cs, Elevator e, Typeable e) => ColorSpace cs e where type Components cs e foldrPx f !z0 !xs = foldlPx f' id xs z0 where f' k x !z = k $! f x z foldlPx f !z0 !xs = foldrPx f' id xs z0 where f' x k !z = k $! f z x foldl1Px f !xs = fromMaybe (error "foldl1: empty Pixel") (foldlPx mf Nothing xs) where mf m !y = Just (case m of { Nothing -> y Just x -> f x y }) toListPx !px = foldr' f [] (enumFrom (toEnum 0)) where f !cs !ls = getPxC px cs : ls where {
+ Graphics.Image.Interface: class (Eq cs, Enum cs, Show cs, Bounded cs, Typeable cs, Elevator e, Typeable e) => ColorSpace cs e where type Components cs e foldrPx f !z0 !xs = foldlPx f' id xs z0 where f' k x !z = k $! f x z foldlPx f !z0 !xs = foldrPx f' id xs z0 where f' x k !z = k $! f z x foldl1Px f !xs = fromMaybe (error "foldl1Px: empty Pixel") (foldlPx mf Nothing xs) where mf m !y = Just (case m of { Nothing -> y Just x -> f x y }) toListPx !px = foldr' f [] (enumFrom (toEnum 0)) where f !cs !ls = getPxC px cs : ls where {
- Graphics.Image.Processing: downsample :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image.Processing: downsample :: Array arr cs e => (Int -> Bool) -> (Int -> Bool) -> Image arr cs e -> Image arr cs e
- Graphics.Image.Processing: upsample :: Array arr cs e => Image arr cs e -> Image arr cs e
+ Graphics.Image.Processing: upsample :: Array arr cs e => (Int -> (Int, Int)) -> (Int -> (Int, Int)) -> Image arr cs e -> Image arr cs e

Files

CHANGELOG.md view
@@ -1,3 +1,15 @@+1.5.0.0+=======++* Refactored `Gray` color space to be `X`, in order to reflect it's generality+* Renamed few core functions:+  * `mapPx` -> `liftPx`,+  * `zipWithPx` -> `liftPx2`,+  * `broadcastC` -> `promote`,+  * `singleton` -> `scalar`.+* `upsample`/`downsample` functions are now a lot more general.++ 1.4.0.1 ======= 
hip.cabal view
@@ -1,5 +1,5 @@ Name:              hip-Version:           1.4.0.1+Version:           1.5.0.0 License:           BSD3 License-File:      LICENSE Author:            Alexey Kuleshevich@@ -68,10 +68,10 @@   Other-Modules:   Graphics.Image.ColorSpace.Binary                  , Graphics.Image.ColorSpace.CMYK                  , Graphics.Image.ColorSpace.Complex-                 , Graphics.Image.ColorSpace.Gray                  , Graphics.Image.ColorSpace.HSI-                 , Graphics.Image.ColorSpace.Luma                  , Graphics.Image.ColorSpace.RGB+                 , Graphics.Image.ColorSpace.X+                 , Graphics.Image.ColorSpace.Y                  , Graphics.Image.ColorSpace.YCbCr                  , Graphics.Image.IO.Base                  , Graphics.Image.IO.Formats.JuicyPixels@@ -107,7 +107,9 @@                     , Graphics.Image.Processing.BinarySpec                     , Graphics.Image.InterfaceSpec                     , Graphics.Image.Interface.VectorSpec+                    , Graphics.Image.IO.FormatsSpec   Build-Depends:      base            >= 4.5 && < 5+                    , bytestring                     , hip                     , hspec                     , QuickCheck
+ images/frog_downsampled.jpg view

binary file changed (absent → 59035 bytes)

+ images/frog_upsampled.jpg view

binary file changed (absent → 210887 bytes)

src/Graphics/Image.hs view
@@ -23,9 +23,6 @@ -- constant time and allows monadic operations and mutation on -- __@`MImage`@ @st@ @arr@ @cs@ @e@__, which is `Image`'s mutable cousin. ----- Array representation type and the above classes it is installed in determine--- operations that can be done on the image with that representation.--- -- Representations using <http://hackage.haskell.org/package/vector Vector> and -- <http://hackage.haskell.org/package/repa Repa> packages: --@@ -36,11 +33,11 @@ -- * `RSS` - Repa Sequential Storable array representation (computation is done sequentially). -- * `RPS` - Repa Parallel Storable array representation (computation is done in parallel). ----- Images with `RSU` and `RPU` types, most of the time hold functions rather then--- actual data, this way computation can be fused together, and later changed to--- `VU` using `toManifest`, which in turn performs the fused computation. If at--- any time computation needs to be forced, `compute` can be used for that--- purpose.+-- Images with `RSU`, `RSS`, `RPU` and `RPS` types, most of the time, hold+-- functions rather than an actual data, this way computation can be fused+-- together, and later changed to `VU` or `VS` using `toManifest`, which in turn+-- performs the fused computation. If at any time computation needs to be+-- forced, `compute` can be used for that purpose. -- -- Many of the function names exported by this module will clash with the ones -- from "Prelude", hence it can be more convenient to import like this:@@ -102,7 +99,7 @@   transpose, backpermute,   (|*|),    -- * Reduction-  fold, sum, product, maximum, minimum, normalize,+  fold, sum, product, maximum, minimum, normalize, eqTol,   -- * Representations   exchange,   module IP@@ -226,20 +223,26 @@   -- | Scales all of the pixels to be in the range @[0, 1]@.-normalize :: (Array arr cs e, Array arr Gray e, Fractional e,-              Fractional (Pixel cs e), Ord e) =>+normalize :: (Array arr cs e, Array arr X e, Fractional e, Ord e) =>              Image arr cs e -> Image arr cs e normalize !img = if l == s                  then (if s < 0 then (*0) else if s > 1 then (*1) else id) img-                 else I.map normalizer img+                 else I.map (liftPx (\ !e -> (e - s) / (l - s))) img   where-    !(PixelGray l, PixelGray s) = (maximum (I.map (PixelGray . foldl1Px max) img),-                                   minimum (I.map (PixelGray . foldl1Px min) img))-    normalizer !px = (px - broadcastC s) / broadcastC (l - s)-    {-# INLINE normalizer #-}+    !(PixelX l, PixelX s) = (maximum (I.map (PixelX . foldl1Px max) img),+                             minimum (I.map (PixelX . foldl1Px min) img)) {-# INLINE normalize #-}  +-- | Check weather two images are equal within a tolerance. Useful for comparing+-- images with `Float` or `Double` precision.+eqTol+  :: (Array arr Binary Bit, Array arr cs e, Ord e, Num e) =>+     e -> Image arr cs e -> Image arr cs e -> Bool+eqTol !tol !img1 = IP.and . toImageBinaryUsing2 (eqTolPx tol) img1+{-# INLINE eqTol #-}++ -- | Type restricted version of `fromLists` that constructs an image using -- supplied representation. fromListsR :: Array arr cs e => arr -> [[Pixel cs e]] -> Image arr cs e@@ -269,7 +272,7 @@ --       ------------------------------------------------------------------------------------------ --     * __'Pixel' 'Binary' 'Bit'     = 'on' | 'off'__ - Bi-tonal. --     * __'Pixel' cs ('Complex' e) = ('Pixel' cs e) '+:' ('Pixel' cs e)__ - Complex pixels with any color space.---     * __'Pixel' 'Gray' e         = PixelGray g__ - Used for separating channels from other color spaces.+--     * __'Pixel' 'X' e         = PixelX g__ - Used for separating channels from other color spaces. -- @ -- -- Every 'Pixel' is an instance of 'Functor', 'Applicative', 'F.Foldable' and
src/Graphics/Image/ColorSpace.hs view
@@ -19,8 +19,10 @@ module Graphics.Image.ColorSpace (   -- * ColorSpace   ColorSpace, Pixel(..), AlphaSpace(..), Elevator(..),+  -- * Operations on Pixels+  eqTolPx,   -- * Luma-  module Graphics.Image.ColorSpace.Luma,+  module Graphics.Image.ColorSpace.Y,   -- * RGB   module Graphics.Image.ColorSpace.RGB,   -- * HSI@@ -29,8 +31,8 @@   module Graphics.Image.ColorSpace.CMYK,   -- * YCbCr   module Graphics.Image.ColorSpace.YCbCr,-  -- * Gray-  module Graphics.Image.ColorSpace.Gray,+  -- * Gray level+  module Graphics.Image.ColorSpace.X,   -- * Binary   Binary, Bit, on, off, isOn, isOff, fromBool, complement,   toPixelBinary, fromPixelBinary, toImageBinary, fromImageBinary,@@ -46,11 +48,11 @@ import GHC.Float import Graphics.Image.Interface hiding (map) import Graphics.Image.ColorSpace.Binary-import Graphics.Image.ColorSpace.Gray-import Graphics.Image.ColorSpace.Luma import Graphics.Image.ColorSpace.RGB import Graphics.Image.ColorSpace.HSI import Graphics.Image.ColorSpace.CMYK+import Graphics.Image.ColorSpace.X+import Graphics.Image.ColorSpace.Y import Graphics.Image.ColorSpace.YCbCr import Graphics.Image.ColorSpace.Complex import qualified Graphics.Image.Interface as I (map)@@ -86,11 +88,18 @@ {-# INLINE fromImageBinary #-}  --- Conversion:+-- | Check weather two Pixels are equal within a tolerance. Useful for comparing+-- pixels with `Float` or `Double` precision.+eqTolPx :: (ColorSpace cs e, Num 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 #-}  -instance ToY Gray where-  toPixelY (PixelGray y) = PixelY y+instance ToY X where+  toPixelY (PixelX y) = PixelY y   {-# INLINE toPixelY #-}  -- | Computes Luma: @ Y' = 0.299 * R' + 0.587 * G' + 0.114 * B' @@@ -118,7 +127,7 @@ instance ToYA YCbCrA where    instance ToRGB Y where-  toPixelRGB (PixelY g) = broadcastC g+  toPixelRGB (PixelY g) = promote g   {-# INLINE toPixelRGB #-}  instance ToRGBA YA where
src/Graphics/Image/ColorSpace/Binary.hs view
@@ -14,10 +14,12 @@ -- Portability : non-portable -- module Graphics.Image.ColorSpace.Binary (-  Binary(..), Bit(..), on, off, isOn, isOff, fromBool, complement+  Binary(..), Bit(..), on, off, isOn, isOff, fromBool,+  module Data.Bits   ) where  import Prelude hiding (map)+import Data.Bits import Data.Word (Word8) import Graphics.Image.Interface import Data.Typeable (Typeable)@@ -46,20 +48,92 @@ -- >>> (on + on) - on -- <Binary:(0)> ---data Binary = Binary deriving (Eq, Enum, Show, Typeable)+data Binary = Binary deriving (Eq, Enum, Bounded, Show, Typeable)  --- | Under the hood, Binary pixels are represented as 'Word8' that can only take+-- | Under the hood, Binary pixels are represented as 'Word8', but can only take -- values of @0@ or @1@. newtype Bit = Bit Word8 deriving (Ord, Eq, Typeable) -data instance Pixel Binary e = PixelBinary !e deriving (Ord, Eq)+data instance Pixel Binary Bit = PixelBinary {-# UNPACK #-} !Bit deriving (Ord, Eq)  instance Show (Pixel Binary Bit) where   show (PixelBinary (Bit 0)) = "<Binary:(0)>"   show _                     = "<Binary:(1)>"  +instance Bits Bit where+  (.&.) = (*)+  {-# INLINE (.&.) #-}++  (.|.) = (+)+  {-# INLINE (.|.) #-}++  (Bit 0) `xor` (Bit 0) = Bit 0+  (Bit 1) `xor` (Bit 1) = Bit 0+  _       `xor` _       = Bit 1+  {-# INLINE xor #-}++  complement (Bit 0) = Bit 1+  complement       _ = Bit 0++  shift !b 0 = b+  shift  _ _ = Bit 0+  +  rotate !b _ = b++  zeroBits = Bit 0++  bit 0 = Bit 1+  bit _ = Bit 0++  testBit (Bit 1) 0 = True+  testBit _       _ = False++  bitSizeMaybe _ = Just 1++  bitSize _ = 1++  isSigned _ = False++  popCount (Bit 0) = 0+  popCount _       = 1++++instance Bits (Pixel Binary Bit) where+  (.&.) = liftPx2 (.&.)+  {-# INLINE (.&.) #-}++  (.|.) = liftPx2 (.|.)+  {-# INLINE (.|.) #-}++  xor = liftPx2 xor+  {-# INLINE xor #-}++  complement = liftPx complement++  shift !b !n = liftPx (`shift` n) b+  +  rotate !b !n = liftPx (`rotate` n) b++  zeroBits = promote zeroBits++  bit = promote . bit++  testBit (PixelBinary (Bit 1)) 0 = True+  testBit _                     _ = False++  bitSizeMaybe _ = Just 1++  bitSize _ = 1++  isSigned _ = False++  popCount (PixelBinary (Bit 0)) = 0+  popCount _                     = 1++ -- | Represents value 'True' or @1@ in binary. Often also called a foreground -- pixel of an object. on :: Pixel Binary Bit@@ -98,17 +172,12 @@ {-# 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 Bit where   type Components Binary Bit = Bit -  broadcastC = PixelBinary-  {-# INLINE broadcastC #-}+  promote = PixelBinary+  {-# INLINE promote #-}   fromComponents = PixelBinary   {-# INLINE fromComponents #-}   toComponents (PixelBinary b) = b@@ -119,12 +188,14 @@   {-# INLINE setPxC #-}     mapPxC f (PixelBinary b) = PixelBinary (f Binary b)   {-# INLINE mapPxC #-}-  mapPx f (PixelBinary b) = PixelBinary (f b)-  {-# INLINE mapPx #-}-  zipWithPx f (PixelBinary b1) (PixelBinary b2) = PixelBinary (f b1 b2)-  {-# INLINE zipWithPx #-}+  liftPx f (PixelBinary b) = PixelBinary (f b)+  {-# INLINE liftPx #-}+  liftPx2 f (PixelBinary b1) (PixelBinary b2) = PixelBinary (f b1 b2)+  {-# INLINE liftPx2 #-}   foldrPx f z (PixelBinary b) = f b z   {-# INLINE foldrPx #-}+  foldlPx2 f !z (PixelBinary b1) (PixelBinary b2) = f z b1 b2+  {-# INLINE foldlPx2 #-}   instance Elevator Bit where@@ -156,6 +227,10 @@   (Bit 0) + (Bit 0) = Bit 0   _       + _       = Bit 1   {-# INLINE (+) #-}+  -- 0 - 0 = 0+  -- 0 - 1 = 0+  -- 1 - 0 = 1+  -- 1 - 1 = 0   _ - (Bit 1) = Bit 0   _ - _       = Bit 1   {-# INLINE (-) #-}@@ -173,17 +248,17 @@   instance Num (Pixel Binary Bit) where-  (+)         = zipWithPx (+)+  (+)         = liftPx2 (+)   {-# INLINE (+) #-}-  (-)         = zipWithPx (-)+  (-)         = liftPx2 (-)   {-# INLINE (-) #-}-  (*)         = zipWithPx (*)+  (*)         = liftPx2 (*)   {-# INLINE (*) #-}-  abs         = mapPx abs+  abs         = liftPx abs   {-# INLINE abs #-}-  signum      = mapPx signum+  signum      = liftPx signum   {-# INLINE signum #-}-  fromInteger = broadcastC . fromInteger+  fromInteger = promote . fromInteger   {-# INLINE fromInteger #-}  
src/Graphics/Image/ColorSpace/CMYK.hs view
@@ -36,13 +36,7 @@           | MagCMYK  -- ^ Magenta           | YelCMYK  -- ^ Yellow           | KeyCMYK  -- ^ Key (Black)-          deriving (Eq, Enum, Typeable)--instance Show CMYK where-  show CyanCMYK = "Cyan"-  show MagCMYK  = "Magenta"-  show YelCMYK  = "Yellow"-  show KeyCMYK  = "Black"+          deriving (Eq, Enum, Show, Bounded, Typeable)   instance Show e => Show (Pixel CMYK e) where@@ -58,8 +52,8 @@   {-# INLINE fromComponents #-}   toComponents (PixelCMYK c m y k) = (c, m, y, k)   {-# INLINE toComponents #-}-  broadcastC !e = PixelCMYK e e e e-  {-# INLINE broadcastC #-}+  promote !e = PixelCMYK e e e e+  {-# INLINE promote #-}   getPxC (PixelCMYK c _ _ _) CyanCMYK = c   getPxC (PixelCMYK _ m _ _) MagCMYK  = m   getPxC (PixelCMYK _ _ y _) YelCMYK  = y@@ -73,12 +67,15 @@   mapPxC f (PixelCMYK c m y k) =     PixelCMYK (f CyanCMYK c) (f MagCMYK m) (f YelCMYK y) (f KeyCMYK k)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelCMYK c1 m1 y1 k1) (PixelCMYK c2 m2 y2 k2) =+    f (f (f (f z c1 c2) m1 m2) y1 y2) k1 k2+  {-# INLINE foldlPx2 #-}   instance Functor (Pixel CMYK) where@@ -179,7 +176,7 @@            | YelCMYKA   -- ^ Yellow            | KeyCMYKA   -- ^ Key (Black)            | AlphaCMYKA -- ^ Alpha -           deriving (Eq, Enum, Typeable)+           deriving (Eq, Enum, Show, Bounded, Typeable)   -- | Conversion to `CMYK` color space.@@ -215,14 +212,6 @@ data instance Pixel CMYKA e = PixelCMYKA !e !e !e !e !e deriving Eq  -instance Show CMYKA where-  show CyanCMYKA  = "Cyan"-  show MagCMYKA   = "Magenta"-  show YelCMYKA   = "Yellow"-  show KeyCMYKA   = "Black"-  show AlphaCMYKA = "Alpha"- - instance Show e => Show (Pixel CMYKA e) where   show (PixelCMYKA c m y k a) =     "<CMYKA:("++show c++"|"++show m++"|"++show y++"|"++show k++"|"++show a++")>"@@ -235,8 +224,8 @@   {-# INLINE fromComponents #-}   toComponents (PixelCMYKA c m y k a) = (c, m, y, k, a)   {-# INLINE toComponents #-}-  broadcastC !e = PixelCMYKA e e e e e-  {-# INLINE broadcastC #-}+  promote !e = PixelCMYKA e e e e e+  {-# INLINE promote #-}   getPxC (PixelCMYKA c _ _ _ _) CyanCMYKA  = c   getPxC (PixelCMYKA _ m _ _ _) MagCMYKA   = m   getPxC (PixelCMYKA _ _ y _ _) YelCMYKA   = y@@ -252,12 +241,15 @@   mapPxC f (PixelCMYKA c m y k a) =     PixelCMYKA (f CyanCMYKA c) (f MagCMYKA m) (f YelCMYKA y) (f KeyCMYKA k) (f AlphaCMYKA a)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelCMYKA c1 m1 y1 k1 a1) (PixelCMYKA c2 m2 y2 k2 a2) =+    f (f (f (f (f z c1 c2) m1 m2) y1 y2) k1 k2) a1 a2+  {-# INLINE foldlPx2 #-}   instance (Elevator e, Typeable e) => AlphaSpace CMYKA e where
− src/Graphics/Image/ColorSpace/Gray.hs
@@ -1,205 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}--- |--- Module      : Graphics.Image.ColorSpace.Gray--- Copyright   : (c) Alexey Kuleshevich 2016--- License     : BSD3--- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>--- Stability   : experimental--- Portability : non-portable----module Graphics.Image.ColorSpace.Gray (-  Gray(..), Pixel(..), toGrayImages, fromGrayImages-  ) where--import Prelude as P-import Control.Applicative-import Data.Foldable-import Data.Typeable (Typeable)-import Foreign.Ptr-import Foreign.Storable--import Graphics.Image.Interface as I---- ^ This is a single channel colorspace, that is designed to separate Gray--- level values from other types of colorspace, hence it is not convertible to--- or from, but rather is here to allow operation on arbirtary single channel--- images. If you are looking for a true grayscale colorspace--- 'Graphics.Image.ColorSpace.Luma.Y' should be used instead.-data Gray = Gray deriving (Eq, Enum, Show, Typeable)---data instance Pixel Gray e = PixelGray !e deriving (Ord, Eq)---instance Show e => Show (Pixel Gray e) where-  show (PixelGray g) = "<Gray:("++show g++")>"---instance (Elevator e, Typeable e) => ColorSpace Gray e where-  type Components Gray e = e--  broadcastC = PixelGray-  {-# INLINE broadcastC #-}-  fromComponents = PixelGray-  {-# INLINE fromComponents #-}-  toComponents (PixelGray g) = g-  {-# INLINE toComponents #-}-  getPxC (PixelGray g) Gray = g-  {-# INLINE getPxC #-}-  setPxC (PixelGray _) Gray g = PixelGray g-  {-# INLINE setPxC #-}-  mapPxC f (PixelGray g) = PixelGray (f Gray g)-  {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}-  foldlPx = foldl'-  {-# INLINE foldlPx #-}---instance Functor (Pixel Gray) where-  fmap f (PixelGray g) = PixelGray (f g)-  {-# INLINE fmap #-}---instance Applicative (Pixel Gray) where-  pure = PixelGray-  {-# INLINE pure #-}-  (PixelGray fg) <*> (PixelGray g) = PixelGray (fg g)-  {-# INLINE (<*>) #-}---instance Foldable (Pixel Gray) where-  foldr f !z (PixelGray g) = f g z-  {-# INLINE foldr #-}---instance Monad (Pixel Gray) where--  return = PixelGray-  {-# INLINE return #-}--  (>>=) (PixelGray g) f = f g-  {-# INLINE (>>=) #-}---instance Num e => Num (Pixel Gray e) where-  (+)         = liftA2 (+)-  {-# INLINE (+) #-}-  -  (-)         = liftA2 (-)-  {-# INLINE (-) #-}-  -  (*)         = liftA2 (*)-  {-# INLINE (*) #-}-  -  abs         = liftA abs-  {-# INLINE abs #-}-  -  signum      = liftA signum-  {-# INLINE signum #-}-  -  fromInteger = pure . fromInteger-  {-# INLINE fromInteger #-}---instance Fractional e => Fractional (Pixel Gray e) where-  (/)          = liftA2 (/)-  {-# INLINE (/) #-}-  recip        = liftA recip-  {-# INLINE recip #-}-  fromRational = pure . fromRational-  {-# INLINE fromRational #-}---instance Floating e => Floating (Pixel Gray e) where-  pi      = pure pi-  {-# INLINE pi #-}-  exp     = liftA exp-  {-# INLINE exp #-}-  log     = liftA log-  {-# INLINE log #-}-  sin     = liftA sin-  {-# INLINE sin #-}-  cos     = liftA cos-  {-# INLINE cos #-}-  asin    = liftA asin-  {-# INLINE asin #-}-  atan    = liftA atan-  {-# INLINE atan #-}-  acos    = liftA acos-  {-# INLINE acos #-}-  sinh    = liftA sinh-  {-# INLINE sinh #-}-  cosh    = liftA cosh-  {-# INLINE cosh #-}-  asinh   = liftA asinh-  {-# INLINE asinh #-}-  atanh   = liftA atanh-  {-# INLINE atanh #-}-  acosh   = liftA acosh-  {-# INLINE acosh #-}---instance Storable e => Storable (Pixel Gray e) where--  sizeOf _ = sizeOf (undefined :: e)-  alignment _ = alignment (undefined :: e)-  peek p = do-    q <- return $ castPtr p-    g <- peek q-    return (PixelGray g)-  poke p (PixelGray g) = do-    q <- return $ castPtr p-    poke q g---- | Separate an image into a list of images with 'Gray' pixels containing every--- channel from the source image.------ >>> frog <- readImageRGB "images/frog.jpg"--- >>> let [frog_red, frog_green, frog_blue] = toGrayImages frog--- >>> writeImage "images/frog_red.png" $ toImageY frog_red--- >>> writeImage "images/frog_green.jpg" $ toImageY frog_green--- >>> writeImage "images/frog_blue.jpg" $ toImageY frog_blue------ <<images/frog_red.jpg>> <<images/frog_green.jpg>> <<images/frog_blue.jpg>>----toGrayImages :: (Array arr cs e, Array arr Gray e) => Image arr cs e -> [Image arr Gray e]-toGrayImages !img = P.map getCh (enumFrom (toEnum 0)) where-  getCh !ch = I.map (PixelGray . (`getPxC` ch)) img-  {-# INLINE getCh #-}-{-# INLINE toGrayImages #-}----- | Combine a list of images with 'Gray' pixels into an image of any color--- space, by supplying an order of color space channels.------ For example here is a frog with swapped 'BlueRGB' and 'GreenRGB' channels.------ >>> writeImage "images/frog_rbg.jpg" $ fromGrayImages [frog_red, frog_green, frog_blue] [RedRGB, BlueRGB, GreenRGB]------ <<images/frog.jpg>> <<images/frog_rbg.jpg>>------ It is worth noting though, despite that separating image channels can be sometimes--- pretty useful, the same effect as above can be achieved in a much simpler and--- a more efficient way:------ @ map (\(PixelRGB r g b) -> PixelRGB r b g) frog @----fromGrayImages :: forall arr cs e . (Array arr Gray e, Array arr cs e) =>-                  [Image arr Gray e] -> [cs] -> Image arr cs e-fromGrayImages = fromGrays 0 where-  updateCh ch px (PixelGray e) = setPxC px ch e-  {-# INLINE updateCh #-}-  fromGrays img []     _      = img-  fromGrays img _      []     = img-  fromGrays img (i:is) (c:cs) = fromGrays (I.zipWith (updateCh c) img i) is cs-  {-# INLINE fromGrays #-}-{-# INLINE fromGrayImages #-}
src/Graphics/Image/ColorSpace/HSI.hs view
@@ -35,15 +35,10 @@ data HSI = HueHSI -- ^ Hue          | SatHSI -- ^ Saturation           | IntHSI -- ^ Intensity-         deriving (Eq, Enum, Typeable)+         deriving (Eq, Enum, Show, Bounded, Typeable)  data instance Pixel HSI e = PixelHSI !e !e !e deriving Eq --instance Show HSI where-  show HueHSI = "Hue"-  show SatHSI = "Saturation"-  show IntHSI = "Intensity"    instance Show e => Show (Pixel HSI e) where   show (PixelHSI h s i) = "<HSI:("++show h++"|"++show s++"|"++show i++")>"@@ -56,8 +51,8 @@   {-# INLINE toComponents #-}   fromComponents !(h, s, i) = PixelHSI h s i   {-# INLINE fromComponents #-}-  broadcastC = pure-  {-# INLINE broadcastC #-}+  promote = pure+  {-# INLINE promote #-}   getPxC (PixelHSI h _ _) HueHSI = h   getPxC (PixelHSI _ s _) SatHSI = s   getPxC (PixelHSI _ _ i) IntHSI = i@@ -68,12 +63,15 @@   {-# INLINE setPxC #-}   mapPxC f (PixelHSI h s i) = PixelHSI (f HueHSI h) (f SatHSI s) (f IntHSI i)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelHSI h1 s1 i1) (PixelHSI h2 s2 i2) =+    f (f (f z h1 h2) s1 s2) i1 i2+  {-# INLINE foldlPx2 #-}   instance Functor (Pixel HSI) where@@ -170,7 +168,7 @@           | SatHSIA   -- ^ Saturation           | IntHSIA   -- ^ Intensity           | AlphaHSIA -- ^ Alpha-          deriving (Eq, Enum, Typeable)+          deriving (Eq, Enum, Show, Bounded, Typeable)   data instance Pixel HSIA e = PixelHSIA !e !e !e !e deriving Eq@@ -190,14 +188,7 @@   {-# INLINE toImageHSI #-}  --instance Show HSIA where-  show HueHSIA   = "Hue"-  show SatHSIA   = "Saturation"-  show IntHSIA   = "Intensity"-  show AlphaHSIA = "Alpha"--  +  instance Show e => Show (Pixel HSIA e) where   show (PixelHSIA h s i a) = "<HSIA:("++show h++"|"++show s++"|"++show i++"|"++show a++")>" @@ -209,8 +200,8 @@   {-# INLINE toComponents #-}   fromComponents !(h, s, i, a) = PixelHSIA h s i a   {-# INLINE fromComponents #-}-  broadcastC = pure-  {-# INLINE broadcastC #-}+  promote = pure+  {-# INLINE promote #-}   getPxC (PixelHSIA h _ _ _) HueHSIA   = h   getPxC (PixelHSIA _ s _ _) SatHSIA   = s   getPxC (PixelHSIA _ _ i _) IntHSIA   = i@@ -224,12 +215,15 @@   mapPxC f (PixelHSIA h s i a) =     PixelHSIA (f HueHSIA h) (f SatHSIA s) (f IntHSIA i) (f AlphaHSIA a)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelHSIA h1 s1 i1 a1) (PixelHSIA h2 s2 i2 a2) =+    f (f (f (f z h1 h2) s1 s2) i1 i2) a1 a2+  {-# INLINE foldlPx2 #-}   instance (Elevator e, Typeable e) => AlphaSpace HSIA e where
− src/Graphics/Image/ColorSpace/Luma.hs
@@ -1,328 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}--- |--- Module      : Graphics.Image.ColorSpace.Luma--- Copyright   : (c) Alexey Kuleshevich 2016--- License     : BSD3--- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>--- Stability   : experimental--- Portability : non-portable----module Graphics.Image.ColorSpace.Luma (-  Y(..), YA(..), Pixel(..), -  ToY(..), ToYA(..)-  ) where--import Prelude hiding (map)-import Control.Applicative-import Data.Foldable-import Data.Typeable (Typeable)-import Foreign.Ptr-import Foreign.Storable--import Graphics.Image.Interface--------------- Y ----------------- | Luma or brightness, which is usually denoted as @Y'@.-data Y = LumaY deriving (Eq, Enum, Typeable)---data instance Pixel Y e = PixelY !e deriving (Ord, Eq)---- | Conversion to Luma color space.-class ColorSpace cs Double => ToY cs where--  -- | Convert a pixel to Luma pixel.-  toPixelY :: Pixel cs Double -> Pixel Y Double--  -- | Convert an image to Luma image.-  toImageY :: (Array arr cs Double, Array arr Y Double) =>-              Image arr cs Double-           -> Image arr Y Double-  toImageY = map toPixelY-  {-# INLINE toImageY #-}--instance Show Y where-  show LumaY = "Luma"--instance Show e => Show (Pixel Y e) where-  show (PixelY g) = "<Luma:("++show g++")>"--instance (Elevator e, Typeable e) => ColorSpace Y e where-  type Components Y e = e-  broadcastC = PixelY-  {-# INLINE broadcastC #-}-  fromComponents = PixelY-  {-# INLINE fromComponents #-}-  toComponents (PixelY y) = y-  {-# INLINE toComponents #-}-  getPxC (PixelY y) LumaY = y-  {-# INLINE getPxC #-}-  setPxC _ LumaY y = PixelY y-  {-# INLINE setPxC #-}-  mapPxC f (PixelY y) = PixelY (f LumaY y)-  {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}-  foldlPx = foldl'-  {-# INLINE foldlPx #-}---instance Functor (Pixel Y) where-  fmap f (PixelY y) = PixelY (f y)-  {-# INLINE fmap #-}---instance Applicative (Pixel Y) where-  pure = PixelY-  {-# INLINE pure #-}-  (PixelY fy) <*> (PixelY y) = PixelY (fy y)-  {-# INLINE (<*>) #-}---instance Foldable (Pixel Y) where-  foldr f !z (PixelY y) = f y z-  {-# INLINE foldr #-}---instance Monad (Pixel Y) where--  return = PixelY-  {-# INLINE return #-}--  (>>=) (PixelY y) f = f y-  {-# INLINE (>>=) #-}---instance Num e => Num (Pixel Y e) where-  (+)         = liftA2 (+)-  {-# INLINE (+) #-}-  (-)         = liftA2 (-)-  {-# INLINE (-) #-}-  (*)         = liftA2 (*)-  {-# INLINE (*) #-}-  abs         = liftA abs-  {-# INLINE abs #-}-  signum      = liftA signum-  {-# INLINE signum #-}-  fromInteger = pure . fromInteger-  {-# INLINE fromInteger #-}-  --instance Fractional e => Fractional (Pixel Y e) where-  (/)          = liftA2 (/)-  {-# INLINE (/) #-}-  recip        = liftA recip-  {-# INLINE recip #-}-  fromRational = pure . fromRational-  {-# INLINE fromRational #-}---instance Floating e => Floating (Pixel Y e) where-  pi      = pure pi-  {-# INLINE pi #-}-  exp     = liftA exp-  {-# INLINE exp #-}-  log     = liftA log-  {-# INLINE log #-}-  sin     = liftA sin-  {-# INLINE sin #-}-  cos     = liftA cos-  {-# INLINE cos #-}-  asin    = liftA asin-  {-# INLINE asin #-}-  atan    = liftA atan-  {-# INLINE atan #-}-  acos    = liftA acos-  {-# INLINE acos #-}-  sinh    = liftA sinh-  {-# INLINE sinh #-}-  cosh    = liftA cosh-  {-# INLINE cosh #-}-  asinh   = liftA asinh-  {-# INLINE asinh #-}-  atanh   = liftA atanh-  {-# INLINE atanh #-}-  acosh   = liftA acosh-  {-# INLINE acosh #-}---instance Storable e => Storable (Pixel Y e) where--  sizeOf _ = sizeOf (undefined :: e)-  alignment _ = alignment (undefined :: e)-  peek p = do-    q <- return $ castPtr p-    y <- peek q-    return (PixelY y)-  poke p (PixelY y) = do-    q <- return $ castPtr p-    poke q y------------------- YA ------------------ | Luma with Alpha channel.-data YA = LumaYA  -- ^ Luma-        | AlphaYA -- ^ Alpha channel-        deriving (Eq, Enum, Typeable)--data instance Pixel YA e = PixelYA !e !e deriving Eq---- | Conversion to Luma from another color space with Alpha channel.-class (ToY (Opaque cs), AlphaSpace cs Double) => ToYA cs where--  -- | Convert a pixel to Luma pixel with Alpha.-  toPixelYA :: Pixel cs Double -> Pixel YA Double-  toPixelYA px = addAlpha (getAlpha px) (toPixelY (dropAlpha px))-  {-# INLINE toPixelYA #-}--  -- | Convert an image to Luma image with Alpha.-  toImageYA :: (Array arr cs Double, Array arr YA Double) =>-               Image arr cs Double-            -> Image arr YA Double-  toImageYA = map toPixelYA-  {-# INLINE toImageYA #-}---instance Show YA where-  show LumaYA  = "Luma"-  show AlphaYA = "Alpha"--instance (Elevator e, Typeable e) => ColorSpace YA e where-  type Components YA e = (e, e)-  broadcastC e = PixelYA e e-  {-# INLINE broadcastC #-}-  fromComponents (y, a) = PixelYA y a-  {-# INLINE fromComponents #-}-  toComponents (PixelYA y a) = (y, a)-  {-# INLINE toComponents #-}-  getPxC (PixelYA y _)  LumaYA = y-  getPxC (PixelYA _ a) AlphaYA = a-  {-# INLINE getPxC #-}-  setPxC (PixelYA _ a) LumaYA  y = PixelYA y a-  setPxC (PixelYA y _) AlphaYA a = PixelYA y a-  {-# INLINE setPxC #-}-  mapPxC f (PixelYA y a) = PixelYA (f LumaYA y) (f AlphaYA a)-  {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}-  foldlPx = foldl'-  {-# INLINE foldlPx #-}-  -  -instance (Elevator e, Typeable e) => AlphaSpace YA e where-  type Opaque YA = Y--  getAlpha (PixelYA _ a) = a-  {-# INLINE getAlpha  #-}-  addAlpha !a (PixelY y) = PixelYA y a-  {-# INLINE addAlpha #-}-  dropAlpha (PixelYA y _) = PixelY y-  {-# INLINE dropAlpha #-}--  -instance Functor (Pixel YA) where-  fmap f (PixelYA y a) = PixelYA (f y) (f a)-  {-# INLINE fmap #-}---instance Applicative (Pixel YA) where-  pure !e = PixelYA e e-  {-# INLINE pure #-}-  (PixelYA fy fa) <*> (PixelYA y a) = PixelYA (fy y) (fa a)-  {-# INLINE (<*>) #-}---instance Foldable (Pixel YA) where-  foldr f !z (PixelYA y a) = f y (f a z)-  {-# INLINE foldr #-}---instance Num e => Num (Pixel YA e) where-  (+)         = liftA2 (+)-  {-# INLINE (+) #-}-  -  (-)         = liftA2 (-)-  {-# INLINE (-) #-}-  -  (*)         = liftA2 (*)-  {-# INLINE (*) #-}-  -  abs         = liftA abs-  {-# INLINE abs #-}-  -  signum      = liftA signum-  {-# INLINE signum #-}-  -  fromInteger = pure . fromInteger-  {-# INLINE fromInteger #-}--instance Fractional e => Fractional (Pixel YA e) where-  (/)          = liftA2 (/)-  {-# INLINE (/) #-}-  recip        = liftA recip-  {-# INLINE recip #-}-  fromRational = pure . fromRational-  {-# INLINE fromRational #-}---instance Floating e => Floating (Pixel YA e) where-  pi      = pure pi-  {-# INLINE pi #-}-  exp     = liftA exp-  {-# INLINE exp #-}-  log     = liftA log-  {-# INLINE log #-}-  sin     = liftA sin-  {-# INLINE sin #-}-  cos     = liftA cos-  {-# INLINE cos #-}-  asin    = liftA asin-  {-# INLINE asin #-}-  atan    = liftA atan-  {-# INLINE atan #-}-  acos    = liftA acos-  {-# INLINE acos #-}-  sinh    = liftA sinh-  {-# INLINE sinh #-}-  cosh    = liftA cosh-  {-# INLINE cosh #-}-  asinh   = liftA asinh-  {-# INLINE asinh #-}-  atanh   = liftA atanh-  {-# INLINE atanh #-}-  acosh   = liftA acosh-  {-# INLINE acosh #-}---instance Storable e => Storable (Pixel YA e) where--  sizeOf _ = 2 * sizeOf (undefined :: e)-  alignment _ = alignment (undefined :: e)-  peek p = do-    q <- return $ castPtr p-    y <- peekElemOff q 0-    a <- peekElemOff q 1-    return (PixelYA y a)-  poke p (PixelYA y a) = do-    q <- return $ castPtr p-    pokeElemOff q 0 y-    pokeElemOff q 1 a-
src/Graphics/Image/ColorSpace/RGB.hs view
@@ -16,7 +16,6 @@ module Graphics.Image.ColorSpace.RGB (   RGB(..), RGBA(..), Pixel(..),   ToRGB(..), ToRGBA(..),-  -- RGB16 -- Experimental     ) where  import Prelude hiding (map)@@ -35,12 +34,7 @@ -- | Red, Green and Blue color space. data RGB = RedRGB          | GreenRGB-         | BlueRGB deriving (Eq, Enum, Typeable)--instance Show RGB where-  show RedRGB   = "Red"-  show GreenRGB = "Green"-  show BlueRGB  = "Blue"+         | BlueRGB deriving (Eq, Enum, Show, Bounded, Typeable)   data instance Pixel RGB e = PixelRGB !e !e !e deriving Eq@@ -69,34 +63,29 @@    toComponents (PixelRGB r g b) = (r, g, b)   {-# INLINE toComponents #-}-     fromComponents !(r, g, b) = PixelRGB r g b   {-# INLINE fromComponents #-}--  broadcastC = pure-  {-# INLINE broadcastC #-}-+  promote = pure+  {-# INLINE promote #-}   getPxC (PixelRGB r _ _) RedRGB   = r   getPxC (PixelRGB _ g _) GreenRGB = g   getPxC (PixelRGB _ _ b) BlueRGB  = b   {-# INLINE getPxC #-}-   setPxC (PixelRGB _ g b) RedRGB   r = PixelRGB r g b   setPxC (PixelRGB r _ b) GreenRGB g = PixelRGB r g b   setPxC (PixelRGB r g _) BlueRGB  b = PixelRGB r g b   {-# INLINE setPxC #-}-   mapPxC f (PixelRGB r g b) = PixelRGB (f RedRGB r) (f GreenRGB g) (f BlueRGB b)   {-# INLINE mapPxC #-}--  mapPx = fmap-  {-# INLINE mapPx #-}--  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}-+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelRGB r1 g1 b1) (PixelRGB r2 g2 b2) =+    f (f (f z r1 r2) g1 g2) b1 b2+  {-# INLINE foldlPx2 #-}   @@ -199,13 +188,7 @@ data RGBA = RedRGBA           | GreenRGBA           | BlueRGBA-          | AlphaRGBA deriving (Eq, Enum, Typeable)--instance Show RGBA where-  show RedRGBA   = "Red"-  show GreenRGBA = "Green"-  show BlueRGBA  = "Blue"-  show AlphaRGBA = "Alpha"+          | AlphaRGBA deriving (Eq, Enum, Show, Bounded, Typeable)  data instance Pixel RGBA e = PixelRGBA !e !e !e !e deriving Eq @@ -235,37 +218,32 @@    toComponents (PixelRGBA r g b a) = (r, g, b, a)   {-# INLINE toComponents #-}-     fromComponents !(r, g, b, a) = PixelRGBA r g b a   {-# INLINE fromComponents #-}--  broadcastC = pure-  {-# INLINE broadcastC #-}-+  promote = pure+  {-# INLINE promote #-}   getPxC (PixelRGBA r _ _ _) RedRGBA   = r   getPxC (PixelRGBA _ g _ _) GreenRGBA = g   getPxC (PixelRGBA _ _ b _) BlueRGBA  = b   getPxC (PixelRGBA _ _ _ a) AlphaRGBA = a   {-# INLINE getPxC #-}-   setPxC (PixelRGBA _ g b a) RedRGBA   r = PixelRGBA r g b a   setPxC (PixelRGBA r _ b a) GreenRGBA g = PixelRGBA r g b a   setPxC (PixelRGBA r g _ a) BlueRGBA  b = PixelRGBA r g b a   setPxC (PixelRGBA r g b _) AlphaRGBA a = PixelRGBA r g b a   {-# INLINE setPxC #-}-   mapPxC f (PixelRGBA r g b a) =     PixelRGBA (f RedRGBA r) (f GreenRGBA g) (f BlueRGBA b) (f AlphaRGBA a)   {-# INLINE mapPxC #-}--  mapPx = fmap-  {-# INLINE mapPx #-}--  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}-+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelRGBA r1 g1 b1 a1) (PixelRGBA r2 g2 b2 a2) =+    f (f (f (f z r1 r2) g1 g2) b1 b2) a1 a2+  {-# INLINE foldlPx2 #-}   instance (Elevator e, Typeable e) => AlphaSpace RGBA e where@@ -389,8 +367,8 @@ -- instance ColorSpace RGB16 Word16 where --   type Components RGB16 Word16 = (Word16, Word16, Word16) ---   broadcastC !e = PixelRGB16 e e e---   {-# INLINE broadcastC #-}+--   promote !e = PixelRGB16 e e e+--   {-# INLINE promote #-}  --   toComponents (PixelRGB16 r g b) = (r, g, b) --   {-# INLINE toComponents #-}@@ -412,84 +390,84 @@ --   mapPxC f (PixelRGB16 r g b) = PixelRGB16 (f RedRGB16 r) (f GreenRGB16 g) (f BlueRGB16 b) --   {-# INLINE mapPxC #-} ---   mapPx f (PixelRGB16 r g b) = PixelRGB16 (f r) (f g) (f b)---   {-# INLINE mapPx #-}+--   liftPx f (PixelRGB16 r g b) = PixelRGB16 (f r) (f g) (f b)+--   {-# INLINE liftPx #-} ---   zipWithPx f (PixelRGB16 r1 g1 b1) (PixelRGB16 r2 g2 b2) =+--   liftPx2 f (PixelRGB16 r1 g1 b1) (PixelRGB16 r2 g2 b2) = --     PixelRGB16 (f r1 r2) (f g1 g2) (f b1 b2)---   {-# INLINE zipWithPx #-}+--   {-# INLINE liftPx2 #-}  --   foldlPx f !acc (PixelRGB16 r g b) = f (f (f acc r) g) b   -- instance Num (Pixel RGB16 Word16) where---   (+)         = zipWithPx (+)+--   (+)         = liftPx2 (+)   ---   (-)         = zipWithPx (-)+--   (-)         = liftPx2 (-) --   {-# INLINE (-) #-}   ---   (*)         = zipWithPx (*)+--   (*)         = liftPx2 (*) --   {-# INLINE (*) #-}   ---   abs         = mapPx abs+--   abs         = liftPx abs --   {-# INLINE abs #-}   ---   signum      = mapPx signum+--   signum      = liftPx signum --   {-# INLINE signum #-}   ---   fromInteger = broadcastC . fromInteger+--   fromInteger = promote . fromInteger --   {-# INLINE fromInteger #-}   -- -- instance Fractional (Pixel RGB16 Word16) where--- --   (/)          = zipWithPx (/)+-- --   (/)          = liftPx2 (/) -- --   {-# INLINE (/) #-}   --- --   recip        = mapPx recip+-- --   recip        = liftPx recip -- --   {-# INLINE recip #-} --- --   fromRational = broadcastC . fromRational+-- --   fromRational = promote . fromRational -- --   {-# INLINE fromRational #-}   -- -- instance Floating (Pixel RGB16 Word16) where--- --   pi      = broadcastC pi+-- --   pi      = promote pi -- --   {-# INLINE pi #-} --- --   exp     = mapPx exp+-- --   exp     = liftPx exp -- --   {-# INLINE exp #-} --- --   log     = mapPx log+-- --   log     = liftPx log -- --   {-# INLINE log #-}   --- --   sin     = mapPx sin+-- --   sin     = liftPx sin -- --   {-# INLINE sin #-}   --- --   cos     = mapPx cos+-- --   cos     = liftPx cos -- --   {-# INLINE cos #-}   --- --   asin    = mapPx asin+-- --   asin    = liftPx asin -- --   {-# INLINE asin #-}   --- --   atan    = mapPx atan+-- --   atan    = liftPx atan -- --   {-# INLINE atan #-}   --- --   acos    = mapPx acos+-- --   acos    = liftPx acos -- --   {-# INLINE acos #-}   --- --   sinh    = mapPx sinh+-- --   sinh    = liftPx sinh -- --   {-# INLINE sinh #-}   --- --   cosh    = mapPx cosh+-- --   cosh    = liftPx cosh -- --   {-# INLINE cosh #-}   --- --   asinh   = mapPx asinh+-- --   asinh   = liftPx asinh -- --   {-# INLINE asinh #-}   --- --   atanh   = mapPx atanh+-- --   atanh   = liftPx atanh -- --   {-# INLINE atanh #-}   --- --   acosh   = mapPx acosh+-- --   acosh   = liftPx acosh -- --   {-# INLINE acosh #-}  
+ src/Graphics/Image/ColorSpace/X.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+-- |+-- Module      : Graphics.Image.ColorSpace.X+-- Copyright   : (c) Alexey Kuleshevich 2017+-- License     : BSD3+-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>+-- Stability   : experimental+-- Portability : non-portable+--+module Graphics.Image.ColorSpace.X (+  X(..), Pixel(..), toImagesX, fromImagesX+  ) where++import Prelude as P+import Control.Applicative+import Data.Foldable+import Data.Typeable (Typeable)+import Foreign.Ptr+import Foreign.Storable++import Graphics.Image.Interface as I++-- ^ This is a single channel colorspace, that is designed to separate Gray+-- level values from other types of colorspace, hence it is not convertible to+-- or from, but rather is here to allow operation on arbirtary single channel+-- images. If you are looking for a true grayscale colorspace+-- 'Graphics.Image.ColorSpace.Luma.Y' should be used instead.+data X = X deriving (Eq, Enum, Bounded, Show, Typeable)+++data instance Pixel X e = PixelX !e deriving (Ord, Eq)+++instance Show e => Show (Pixel X e) where+  show (PixelX g) = "<X:("++show g++")>"+++instance (Elevator e, Typeable e) => ColorSpace X e where+  type Components X e = e++  promote = PixelX+  {-# INLINE promote #-}+  fromComponents = PixelX+  {-# INLINE fromComponents #-}+  toComponents (PixelX g) = g+  {-# INLINE toComponents #-}+  getPxC (PixelX g) X = g+  {-# INLINE getPxC #-}+  setPxC (PixelX _) X g = PixelX g+  {-# INLINE setPxC #-}+  mapPxC f (PixelX g) = PixelX (f X g)+  {-# INLINE mapPxC #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}+  foldlPx = foldl'+  {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelX g1) (PixelX g2) = f z g1 g2+  {-# INLINE foldlPx2 #-}+++instance Functor (Pixel X) where+  fmap f (PixelX g) = PixelX (f g)+  {-# INLINE fmap #-}+++instance Applicative (Pixel X) where+  pure = PixelX+  {-# INLINE pure #-}+  (PixelX fg) <*> (PixelX g) = PixelX (fg g)+  {-# INLINE (<*>) #-}+++instance Foldable (Pixel X) where+  foldr f !z (PixelX g) = f g z+  {-# INLINE foldr #-}+++instance Monad (Pixel X) where++  return = PixelX+  {-# INLINE return #-}++  (>>=) (PixelX g) f = f g+  {-# INLINE (>>=) #-}+++instance Num e => Num (Pixel X e) where+  (+)         = liftA2 (+)+  {-# INLINE (+) #-}+  +  (-)         = liftA2 (-)+  {-# INLINE (-) #-}+  +  (*)         = liftA2 (*)+  {-# INLINE (*) #-}+  +  abs         = liftA abs+  {-# INLINE abs #-}+  +  signum      = liftA signum+  {-# INLINE signum #-}+  +  fromInteger = pure . fromInteger+  {-# INLINE fromInteger #-}+++instance Fractional e => Fractional (Pixel X e) where+  (/)          = liftA2 (/)+  {-# INLINE (/) #-}+  recip        = liftA recip+  {-# INLINE recip #-}+  fromRational = pure . fromRational+  {-# INLINE fromRational #-}+++instance Floating e => Floating (Pixel X e) where+  pi      = pure pi+  {-# INLINE pi #-}+  exp     = liftA exp+  {-# INLINE exp #-}+  log     = liftA log+  {-# INLINE log #-}+  sin     = liftA sin+  {-# INLINE sin #-}+  cos     = liftA cos+  {-# INLINE cos #-}+  asin    = liftA asin+  {-# INLINE asin #-}+  atan    = liftA atan+  {-# INLINE atan #-}+  acos    = liftA acos+  {-# INLINE acos #-}+  sinh    = liftA sinh+  {-# INLINE sinh #-}+  cosh    = liftA cosh+  {-# INLINE cosh #-}+  asinh   = liftA asinh+  {-# INLINE asinh #-}+  atanh   = liftA atanh+  {-# INLINE atanh #-}+  acosh   = liftA acosh+  {-# INLINE acosh #-}+++instance Storable e => Storable (Pixel X e) where++  sizeOf _ = sizeOf (undefined :: e)+  alignment _ = alignment (undefined :: e)+  peek p = do+    q <- return $ castPtr p+    g <- peek q+    return (PixelX g)+  poke p (PixelX g) = do+    q <- return $ castPtr p+    poke q g++-- | Separate an image into a list of images with 'X' pixels containing every+-- channel from the source image.+--+-- >>> frog <- readImageRGB "images/frog.jpg"+-- >>> let [frog_red, frog_green, frog_blue] = toImagesX frog+-- >>> writeImage "images/frog_red.png" $ toImageY frog_red+-- >>> writeImage "images/frog_green.jpg" $ toImageY frog_green+-- >>> writeImage "images/frog_blue.jpg" $ toImageY frog_blue+--+-- <<images/frog_red.jpg>> <<images/frog_green.jpg>> <<images/frog_blue.jpg>>+--+toImagesX :: (Array arr cs e, Array arr X e) => Image arr cs e -> [Image arr X e]+toImagesX !img = P.map getCh (enumFrom minBound) where+  getCh !ch = I.map (PixelX . (`getPxC` ch)) img+  {-# INLINE getCh #-}+{-# INLINE toImagesX #-}+++-- | Combine a list of images with 'X' pixels into an image of any color+-- space, by supplying an order of color space channels.+--+-- For example here is a frog with swapped 'BlueRGB' and 'GreenRGB' channels.+--+-- >>> writeImage "images/frog_rbg.jpg" $ fromImagesX [frog_red, frog_green, frog_blue] [RedRGB, BlueRGB, GreenRGB]+--+-- <<images/frog.jpg>> <<images/frog_rbg.jpg>>+--+-- It is worth noting though, despite that separating image channels can be+-- sometimes pretty useful, exactly the same effect as in example above can be+-- achieved in a much simpler and a more efficient way:+--+-- @ map (\(PixelRGB r g b) -> PixelRGB r b g) frog @+--+fromImagesX :: forall arr cs e . (Array arr X e, Array arr cs e) =>+                  [(cs, Image arr X e)] -> Image arr cs e+fromImagesX = fromXs 0 where+  updateCh ch px (PixelX e) = setPxC px ch e+  {-# INLINE updateCh #-}+  fromXs img []      = img+  fromXs img ((c, i):xs) = fromXs (I.zipWith (updateCh c) img i) xs+  {-# INLINE fromXs #-}+{-# INLINE fromImagesX #-}
+ src/Graphics/Image/ColorSpace/Y.hs view
@@ -0,0 +1,325 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+-- |+-- Module      : Graphics.Image.ColorSpace.Y+-- Copyright   : (c) Alexey Kuleshevich 2017+-- License     : BSD3+-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>+-- Stability   : experimental+-- Portability : non-portable+--+module Graphics.Image.ColorSpace.Y (+  Y(..), YA(..), Pixel(..), +  ToY(..), ToYA(..)+  ) where++import Prelude hiding (map)+import Control.Applicative+import Data.Foldable+import Data.Typeable (Typeable)+import Foreign.Ptr+import Foreign.Storable++import Graphics.Image.Interface++---------+--- Y ---+---------++-- | Luma or brightness, which is usually denoted as @Y'@.+data Y = LumaY deriving (Eq, Enum, Show, Bounded, Typeable)+++data instance Pixel Y e = PixelY !e deriving (Ord, Eq)++-- | Conversion to Luma color space.+class ColorSpace cs Double => ToY cs where++  -- | Convert a pixel to Luma pixel.+  toPixelY :: Pixel cs Double -> Pixel Y Double++  -- | Convert an image to Luma image.+  toImageY :: (Array arr cs Double, Array arr Y Double) =>+              Image arr cs Double+           -> Image arr Y Double+  toImageY = map toPixelY+  {-# INLINE toImageY #-}++instance Show e => Show (Pixel Y e) where+  show (PixelY g) = "<Luma:("++show g++")>"++instance (Elevator e, Typeable e) => ColorSpace Y e where+  type Components Y e = e+  promote = PixelY+  {-# INLINE promote #-}+  fromComponents = PixelY+  {-# INLINE fromComponents #-}+  toComponents (PixelY y) = y+  {-# INLINE toComponents #-}+  getPxC (PixelY y) LumaY = y+  {-# INLINE getPxC #-}+  setPxC _ LumaY y = PixelY y+  {-# INLINE setPxC #-}+  mapPxC f (PixelY y) = PixelY (f LumaY y)+  {-# INLINE mapPxC #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}+  foldlPx = foldl'+  {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelY y1) (PixelY y2) = f z y1 y2+  {-# INLINE foldlPx2 #-}+++instance Functor (Pixel Y) where+  fmap f (PixelY y) = PixelY (f y)+  {-# INLINE fmap #-}+++instance Applicative (Pixel Y) where+  pure = PixelY+  {-# INLINE pure #-}+  (PixelY fy) <*> (PixelY y) = PixelY (fy y)+  {-# INLINE (<*>) #-}+++instance Foldable (Pixel Y) where+  foldr f !z (PixelY y) = f y z+  {-# INLINE foldr #-}+++instance Monad (Pixel Y) where++  return = PixelY+  {-# INLINE return #-}++  (>>=) (PixelY y) f = f y+  {-# INLINE (>>=) #-}+++instance Num e => Num (Pixel Y e) where+  (+)         = liftA2 (+)+  {-# INLINE (+) #-}+  (-)         = liftA2 (-)+  {-# INLINE (-) #-}+  (*)         = liftA2 (*)+  {-# INLINE (*) #-}+  abs         = liftA abs+  {-# INLINE abs #-}+  signum      = liftA signum+  {-# INLINE signum #-}+  fromInteger = pure . fromInteger+  {-# INLINE fromInteger #-}+  ++instance Fractional e => Fractional (Pixel Y e) where+  (/)          = liftA2 (/)+  {-# INLINE (/) #-}+  recip        = liftA recip+  {-# INLINE recip #-}+  fromRational = pure . fromRational+  {-# INLINE fromRational #-}+++instance Floating e => Floating (Pixel Y e) where+  pi      = pure pi+  {-# INLINE pi #-}+  exp     = liftA exp+  {-# INLINE exp #-}+  log     = liftA log+  {-# INLINE log #-}+  sin     = liftA sin+  {-# INLINE sin #-}+  cos     = liftA cos+  {-# INLINE cos #-}+  asin    = liftA asin+  {-# INLINE asin #-}+  atan    = liftA atan+  {-# INLINE atan #-}+  acos    = liftA acos+  {-# INLINE acos #-}+  sinh    = liftA sinh+  {-# INLINE sinh #-}+  cosh    = liftA cosh+  {-# INLINE cosh #-}+  asinh   = liftA asinh+  {-# INLINE asinh #-}+  atanh   = liftA atanh+  {-# INLINE atanh #-}+  acosh   = liftA acosh+  {-# INLINE acosh #-}+++instance Storable e => Storable (Pixel Y e) where++  sizeOf _ = sizeOf (undefined :: e)+  alignment _ = alignment (undefined :: e)+  peek p = do+    q <- return $ castPtr p+    y <- peek q+    return (PixelY y)+  poke p (PixelY y) = do+    q <- return $ castPtr p+    poke q y+++++----------+--- YA ---+----------++-- | Luma with Alpha channel.+data YA = LumaYA  -- ^ Luma+        | AlphaYA -- ^ Alpha channel+        deriving (Eq, Enum, Show, Bounded, Typeable)++data instance Pixel YA e = PixelYA !e !e deriving Eq++-- | Conversion to Luma from another color space with Alpha channel.+class (ToY (Opaque cs), AlphaSpace cs Double) => ToYA cs where++  -- | Convert a pixel to Luma pixel with Alpha.+  toPixelYA :: Pixel cs Double -> Pixel YA Double+  toPixelYA px = addAlpha (getAlpha px) (toPixelY (dropAlpha px))+  {-# INLINE toPixelYA #-}++  -- | Convert an image to Luma image with Alpha.+  toImageYA :: (Array arr cs Double, Array arr YA Double) =>+               Image arr cs Double+            -> Image arr YA Double+  toImageYA = map toPixelYA+  {-# INLINE toImageYA #-}+++instance (Elevator e, Typeable e) => ColorSpace YA e where+  type Components YA e = (e, e)+  promote e = PixelYA e e+  {-# INLINE promote #-}+  fromComponents (y, a) = PixelYA y a+  {-# INLINE fromComponents #-}+  toComponents (PixelYA y a) = (y, a)+  {-# INLINE toComponents #-}+  getPxC (PixelYA y _)  LumaYA = y+  getPxC (PixelYA _ a) AlphaYA = a+  {-# INLINE getPxC #-}+  setPxC (PixelYA _ a) LumaYA  y = PixelYA y a+  setPxC (PixelYA y _) AlphaYA a = PixelYA y a+  {-# INLINE setPxC #-}+  mapPxC f (PixelYA y a) = PixelYA (f LumaYA y) (f AlphaYA a)+  {-# INLINE mapPxC #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}+  foldlPx = foldl'+  {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelYA y1 a1) (PixelYA y2 a2) = f (f z y1 y2) a1 a2+  {-# INLINE foldlPx2 #-}++  +instance (Elevator e, Typeable e) => AlphaSpace YA e where+  type Opaque YA = Y++  getAlpha (PixelYA _ a) = a+  {-# INLINE getAlpha  #-}+  addAlpha !a (PixelY y) = PixelYA y a+  {-# INLINE addAlpha #-}+  dropAlpha (PixelYA y _) = PixelY y+  {-# INLINE dropAlpha #-}++  +instance Functor (Pixel YA) where+  fmap f (PixelYA y a) = PixelYA (f y) (f a)+  {-# INLINE fmap #-}+++instance Applicative (Pixel YA) where+  pure !e = PixelYA e e+  {-# INLINE pure #-}+  (PixelYA fy fa) <*> (PixelYA y a) = PixelYA (fy y) (fa a)+  {-# INLINE (<*>) #-}+++instance Foldable (Pixel YA) where+  foldr f !z (PixelYA y a) = f y (f a z)+  {-# INLINE foldr #-}+++instance Num e => Num (Pixel YA e) where+  (+)         = liftA2 (+)+  {-# INLINE (+) #-}+  +  (-)         = liftA2 (-)+  {-# INLINE (-) #-}+  +  (*)         = liftA2 (*)+  {-# INLINE (*) #-}+  +  abs         = liftA abs+  {-# INLINE abs #-}+  +  signum      = liftA signum+  {-# INLINE signum #-}+  +  fromInteger = pure . fromInteger+  {-# INLINE fromInteger #-}++instance Fractional e => Fractional (Pixel YA e) where+  (/)          = liftA2 (/)+  {-# INLINE (/) #-}+  recip        = liftA recip+  {-# INLINE recip #-}+  fromRational = pure . fromRational+  {-# INLINE fromRational #-}+++instance Floating e => Floating (Pixel YA e) where+  pi      = pure pi+  {-# INLINE pi #-}+  exp     = liftA exp+  {-# INLINE exp #-}+  log     = liftA log+  {-# INLINE log #-}+  sin     = liftA sin+  {-# INLINE sin #-}+  cos     = liftA cos+  {-# INLINE cos #-}+  asin    = liftA asin+  {-# INLINE asin #-}+  atan    = liftA atan+  {-# INLINE atan #-}+  acos    = liftA acos+  {-# INLINE acos #-}+  sinh    = liftA sinh+  {-# INLINE sinh #-}+  cosh    = liftA cosh+  {-# INLINE cosh #-}+  asinh   = liftA asinh+  {-# INLINE asinh #-}+  atanh   = liftA atanh+  {-# INLINE atanh #-}+  acosh   = liftA acosh+  {-# INLINE acosh #-}+++instance Storable e => Storable (Pixel YA e) where++  sizeOf _ = 2 * sizeOf (undefined :: e)+  alignment _ = alignment (undefined :: e)+  peek p = do+    q <- return $ castPtr p+    y <- peekElemOff q 0+    a <- peekElemOff q 1+    return (PixelYA y a)+  poke p (PixelYA y a) = do+    q <- return $ castPtr p+    pokeElemOff q 0 y+    pokeElemOff q 1 a+
src/Graphics/Image/ColorSpace/YCbCr.hs view
@@ -37,17 +37,11 @@ data YCbCr = LumaYCbCr  -- ^ Luma component (commonly denoted as __Y'__)            | CBlueYCbCr -- ^ Blue difference chroma component            | CRedYCbCr  -- ^ Red difference chroma component-           deriving (Eq, Enum, Typeable)+           deriving (Eq, Enum, Show, Bounded, Typeable)  data instance Pixel YCbCr e = PixelYCbCr !e !e !e deriving Eq  -instance Show YCbCr where-  show LumaYCbCr  = "Luma"-  show CBlueYCbCr = "Blue Chroma"-  show CRedYCbCr  = "Red Chroma"-- instance Show e => Show (Pixel YCbCr e) where   show (PixelYCbCr y b r) = "<YCbCr:("++show y++"|"++show b++"|"++show r++")>" @@ -55,8 +49,8 @@ instance (Elevator e, Typeable e) => ColorSpace YCbCr e where   type Components YCbCr e = (e, e, e) -  broadcastC !e = PixelYCbCr e e e-  {-# INLINE broadcastC #-}+  promote !e = PixelYCbCr e e e+  {-# INLINE promote #-}   fromComponents !(y, b, r) = PixelYCbCr y b r   {-# INLINE fromComponents #-}   toComponents (PixelYCbCr y b r) = (y, b, r)@@ -71,12 +65,15 @@   {-# INLINE setPxC #-}   mapPxC f (PixelYCbCr y b r) = PixelYCbCr (f LumaYCbCr y) (f CBlueYCbCr b) (f CRedYCbCr r)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelYCbCr y1 b1 r1) (PixelYCbCr y2 b2 r2) =+    f (f (f z y1 y2) b1 b2) r1 r2+  {-# INLINE foldlPx2 #-}   instance Functor (Pixel YCbCr) where@@ -177,17 +174,10 @@             | CBlueYCbCrA -- ^ Blue difference chroma component             | CRedYCbCrA  -- ^ Red difference chroma component             | AlphaYCbCrA -- ^ Alpha component.-            deriving (Eq, Enum, Typeable)+            deriving (Eq, Enum, Show, Bounded, Typeable)  data instance Pixel YCbCrA e = PixelYCbCrA !e !e !e !e deriving Eq --instance Show YCbCrA where-  show LumaYCbCrA  = "Luma"-  show CBlueYCbCrA = "Blue Chroma"-  show CRedYCbCrA  = "Red Chroma"-  show AlphaYCbCrA = "Alpha"-   instance Show e => Show (Pixel YCbCrA e) where   show (PixelYCbCrA y b r a) = "<YCbCrA:("++show y++"|"++show b++"|"++show r++"|"++show a++")>"@@ -196,8 +186,8 @@ instance (Elevator e, Typeable e) => ColorSpace YCbCrA e where   type Components YCbCrA e = (e, e, e, e) -  broadcastC !e = PixelYCbCrA e e e e-  {-# INLINE broadcastC #-}+  promote !e = PixelYCbCrA e e e e+  {-# INLINE promote #-}   fromComponents !(y, b, r, a) = PixelYCbCrA y b r a   {-# INLINE fromComponents #-}   toComponents (PixelYCbCrA y b r a) = (y, b, r, a)@@ -215,12 +205,15 @@   mapPxC f (PixelYCbCrA y b r a) =     PixelYCbCrA (f LumaYCbCrA y) (f CBlueYCbCrA b) (f CRedYCbCrA r) (f AlphaYCbCrA a)   {-# INLINE mapPxC #-}-  mapPx = fmap-  {-# INLINE mapPx #-}-  zipWithPx = liftA2-  {-# INLINE zipWithPx #-}+  liftPx = fmap+  {-# INLINE liftPx #-}+  liftPx2 = liftA2+  {-# INLINE liftPx2 #-}   foldlPx = foldl'   {-# INLINE foldlPx #-}+  foldlPx2 f !z (PixelYCbCrA y1 b1 r1 a1) (PixelYCbCrA y2 b2 r2 a2) =+    f (f (f (f z y1 y2) b1 b2) r1 r2) a1 a2+  {-# INLINE foldlPx2 #-}     -- | Conversion to `YCbCr` color space.
src/Graphics/Image/IO/Formats.hs view
@@ -15,7 +15,7 @@ module Graphics.Image.IO.Formats (   module Graphics.Image.IO.Formats.JuicyPixels,   module Graphics.Image.IO.Formats.Netpbm,-  InputFormat, OutputFormat,+  InputFormat(..), OutputFormat(..),   Readable(..), Writable(..), ImageFormat(..),   ) where @@ -37,7 +37,7 @@                  | InputPNG                  | InputTIF                  | InputPNM-                 | InputTGA  deriving (Show, Enum, Eq)+                 | InputTGA  deriving (Eq, Show, Enum, Bounded)   instance ImageFormat InputFormat where@@ -90,7 +90,7 @@                   | OutputJPG                   | OutputPNG                   | OutputTIF-                  | OutputTGA  deriving (Show, Enum, Eq)+                  | OutputTGA  deriving (Eq, Show, Enum, Bounded)   instance ImageFormat OutputFormat where
src/Graphics/Image/IO/Formats/JuicyPixels.hs view
@@ -208,13 +208,13 @@ -- Y -> RGB (Double)  instance Convertible JP.Pixel8 (Pixel RGB Double) where-  convert = broadcastC . toDouble+  convert = promote . toDouble  instance Convertible JP.Pixel16 (Pixel RGB Double) where-  convert = broadcastC . toDouble+  convert = promote . toDouble  instance Convertible JP.PixelF (Pixel RGB Double) where-  convert = broadcastC . toDouble+  convert = promote . toDouble  instance Convertible JP.PixelYA8 (Pixel RGB Double) where   convert = convert . JP.dropTransparency
src/Graphics/Image/IO/Histogram.hs view
@@ -65,24 +65,24 @@ type Histograms = [Histogram]  -- | Create a histogram per channel with 256 bins each.-getHistograms :: forall arr cs e . (ChannelColour cs, MArray arr Gray e, Array arr Gray e, +getHistograms :: forall arr cs e . (ChannelColour cs, MArray arr X e, Array arr X e,                                      MArray arr cs e, Array arr cs e) =>                  Image arr cs e               -> Histograms-getHistograms = P.zipWith setCh (enumFrom (toEnum 0) :: [cs]) . P.map getHistogram . toGrayImages+getHistograms = P.zipWith setCh (enumFrom (toEnum 0) :: [cs]) . P.map getHistogram . toImagesX   where setCh cs h = h { hName = show cs                        , hColour = csColour cs }  -- | Generate a histogram with 256 bins for a single channel Gray image.-getHistogram :: MArray arr Gray e =>-                Image arr Gray e+getHistogram :: MArray arr X e =>+                Image arr X e              -> Histogram getHistogram img = Histogram { hBins = V.modify countBins $                                        V.replicate                                        (1 + fromIntegral (maxBound :: Word8)) (0 :: Int)-                             , hName = show Gray-                             , hColour = csColour Gray } where-  incBin v (PixelGray g) = modify v (+1) $ fromIntegral (toWord8 g)+                             , hName = show X+                             , hColour = csColour X } where+  incBin v (PixelX g) = modify v (+1) $ fromIntegral (toWord8 g)   countBins v = I.mapM_ (incBin v) img    @@ -128,7 +128,7 @@     then display     else void $ forkIO display -instance ChannelColour Gray where+instance ChannelColour X where   csColour _ = C.opaque C.darkgray  instance ChannelColour Y where
src/Graphics/Image/Interface.hs view
@@ -23,7 +23,7 @@ module Graphics.Image.Interface (   Pixel, ColorSpace(..), AlphaSpace(..), Elevator(..),   BaseArray(..), Array(..), MArray(..),-  Exchangable(..), exchangeFrom,+  Exchangable(..), exchangeFrom, exchangeThrough,   defaultIndex, borderIndex, maybeIndex, Border(..), handleBorderIndex,   fromIx, toIx, checkDims #if !MIN_VERSION_base(4,8,0)@@ -50,7 +50,8 @@ data family Pixel cs e :: *  -class (Eq cs, Enum cs, Show cs, Typeable cs, Elevator e, Typeable e) => ColorSpace cs e where+class (Eq cs, Enum cs, Show cs, Bounded cs, Typeable cs, Elevator e, Typeable e)+      => ColorSpace cs e where      type Components cs e @@ -61,8 +62,8 @@   -- | Convert from an elemnt representation back to a Pixel.   fromComponents :: Components cs e -> Pixel cs e -  -- | Construt a pixel by replicating a same value among all of the components.-  broadcastC :: e -> Pixel cs e+  -- | Construt a Pixel by replicating the same value across all of the components.+  promote :: e -> Pixel cs e    -- | Retrieve Pixel's component value   getPxC :: Pixel cs e -> cs -> e@@ -74,11 +75,13 @@   mapPxC :: (cs -> e -> e) -> Pixel cs e -> Pixel cs e     -- | Map a function over all Pixel's componenets.-  mapPx :: (e -> e) -> Pixel cs e -> Pixel cs e+  liftPx :: (e -> e) -> Pixel cs e -> Pixel cs e    -- | Zip two Pixels with a function.-  zipWithPx :: (e -> e -> e) -> Pixel cs e -> Pixel cs e -> Pixel cs e+  liftPx2 :: (e -> e -> e) -> Pixel cs e -> Pixel cs e -> Pixel cs e +  foldlPx2 :: (b -> e -> e -> b) -> b -> Pixel cs e -> Pixel cs e -> b+   -- | Right fold over all Pixel's components.   foldrPx :: (e -> b -> b) -> b -> Pixel cs e -> b   foldrPx f !z0 !xs = foldlPx f' id xs z0@@ -90,7 +93,7 @@       where f' x k !z = k $! f z x    foldl1Px :: (e -> e -> e) -> Pixel cs e -> e-  foldl1Px f !xs = fromMaybe (error "foldl1: empty Pixel")+  foldl1Px f !xs = fromMaybe (error "foldl1Px: empty Pixel")                   (foldlPx mf Nothing xs)       where         mf m !y = Just (case m of@@ -197,9 +200,9 @@                        -- ^ Function that generates border pixels                     -> Image arr cs e -  -- | Create a singleton image, required for various operations on images with+  -- | Create a scalar image, required for various operations on images with   -- a scalar.-  singleton :: Pixel cs e -> Image arr cs e+  scalar :: Pixel cs e -> Image arr cs e    -- | Retrieves a pixel at @(0, 0)@ index. Useful together with `fold`, when   -- arbitrary initial pixel is needed.@@ -411,6 +414,17 @@ {-# INLINE exchangeFrom #-}  +-- | `exchange` an image representation through an intermediate one.+exchangeThrough :: (Exchangable arr2 arr1, Exchangable arr1 arr,+                    Array arr2 cs e, Array arr1 cs e, Array arr cs e) =>+                arr1+             -> arr -- ^ New representation of an image.+             -> Image arr2 cs e -- ^ Source image.+             -> Image arr cs e+exchangeThrough through to = exchange to . exchange through+{-# INLINE exchangeThrough #-}++ -- | Approach to be used near the borders during various transformations. -- Whenever a function needs information not only about a pixel of interest, but -- also about it's neighbours, it will go out of bounds around the image edges,@@ -453,32 +467,109 @@               --   deriving Show +-- handleBorderIndex' :: Border px -- ^ Border handling strategy.+--                   -> (Int, Int) -- ^ Image dimensions+--                   -> ((Int, Int) -> px) -- ^ Image's indexing function.+--                   -> (Int, Int) -- ^ @(i, j)@ location of a pixel lookup.+--                   -> px+-- handleBorderIndex' border !(m, n) !getPx !(i, j) =+--   if i >= 0 && j >= 0 && i < m && j < n then getPx (i, j) else getPxB border where+--     getPxB (Fill px) = px+--     getPxB Wrap      = getPx (i `mod` m, j `mod` n)+--     getPxB Edge      = getPx (if i < 0 then 0 else if i >= m then m - 1 else i,+--                               if j < 0 then 0 else if j >= n then n - 1 else j)+--     getPxB Reflect   = getPx (if i < 0 then (abs i - 1) `mod` m else+--                                 if i >= m then (m - (i - m + 1)) `mod` m else i,+--                               if j < 0 then (abs j - 1) `mod` n else+--                                 if j >= n then (n - (j - n + 1)) `mod` n else j)+--     getPxB Continue  = getPx (if i < 0 then abs i `mod` m else+--                                 if i >= m then (m - (i - m + 2)) `mod` m else i,+--                               if j < 0 then abs j `mod` n else+--                                 if j >= n then (n - (j - n + 2)) `mod` n else j)+--     {-# INLINE getPxB #-}+-- {-# INLINE handleBorderIndex' #-}++++ -- | Border handling function. If @(i, j)@ location is within bounds, then supplied -- lookup function will be used, otherwise it will be handled according to a -- supplied border strategy. handleBorderIndex :: Border px -- ^ Border handling strategy.-            -> (Int, Int) -- ^ Image dimensions-            -> ((Int, Int) -> px) -- ^ Image's indexing function.-            -> (Int, Int) -- ^ @(i, j)@ location of a pixel lookup.-            -> px+                   -> (Int, Int) -- ^ Image dimensions+                   -> ((Int, Int) -> px) -- ^ Image's indexing function.+                   -> (Int, Int) -- ^ @(i, j)@ location of a pixel lookup.+                   -> px handleBorderIndex border !(m, n) !getPx !(i, j) =-  if i >= 0 && j >= 0 && i < m && j < n then getPx (i, j) else getPxB border where-    getPxB (Fill px) = px-    getPxB Wrap      = getPx (i `mod` m, j `mod` n)-    getPxB Edge      = getPx (if i < 0 then 0 else if i >= m then m - 1 else i,-                              if j < 0 then 0 else if j >= n then n - 1 else j)-    getPxB Reflect   = getPx (if i < 0 then (abs i - 1) `mod` m else-                                if i >= m then (m - (i - m + 1)) `mod` m else i,-                              if j < 0 then (abs j - 1) `mod` n else-                                if j >= n then (n - (j - n + 1)) `mod` n else j)-    getPxB Continue  = getPx (if i < 0 then abs i `mod` m else-                                if i >= m then (m - (i - m + 2)) `mod` m else i,-                              if j < 0 then abs j `mod` n else-                                if j >= n then (n - (j - n + 2)) `mod` n else j)-    {-# INLINE getPxB #-}+  if north || east || south || west+  then case border of+    Fill px  -> px+    Wrap     -> getPx (i `mod` m, j `mod` n)+    Edge     -> getPx (if north then 0 else if south then m - 1 else i,+                       if west then 0 else if east then n - 1 else j)+    Reflect  -> getPx (if north then (abs i - 1) `mod` m else+                         if south then (-i - 1) `mod` m else i,+                       if west then (abs j - 1) `mod` n else+                         if east then (-j - 1) `mod` n else j)+    Continue -> getPx (if north then abs i `mod` m else+                         if south then (-i - 2) `mod` m else i,+                       if west then abs j `mod` n else+                         if east then (-j - 2) `mod` n else j)+    -- Reflect  -> getPx (if north then (abs i - 1) `mod` m else+    --                      if south then (m - (i - m + 1)) `mod` m else i,+    --                    if west then (abs j - 1) `mod` n else+    --                      if east then (n - (j - n + 1)) `mod` n else j)+    -- Continue -> getPx (if north then abs i `mod` m else+    --                      if south then (m - (i - m + 2)) `mod` m else i,+    --                    if west then abs j `mod` n else+    --                      if east then (n - (j - n + 2)) `mod` n else j)+  else getPx (i, j)+  where+    north = i < 0+    {-# INLINE north #-}+    south = i >= m+    {-# INLINE south #-}+    west = j < 0+    {-# INLINE west #-}+    east = j >= n+    {-# INLINE east #-} {-# INLINE handleBorderIndex #-}  ++-- handleBorderIndex' border !(m, n) getPx !(i, j) =+--   case (i < 0, i >= m, j < 0, j >= n) of+--     (False, False, False, False) -> getPx (i, j)+--     (False, False, False,  True) ->+--       case border of+--         Fill px -> px+--         Wrap -> getPx (i, j `mod` n)+--         Edge -> getPx (i, n-1)+--         Reflect -> getPx (i, (n - (j - n + 1)) `mod` n)+--         Continue -> getPx (i, (n - (j - n + 2)) `mod` n)+--     (False, False, True,  False) ->+--       case border of+--         Fill px -> px+--         Wrap -> getPx (i, j `mod` n)+--         Edge -> getPx (i, 0)+--         Reflect -> getPx (i, (abs j - 1) `mod` n)+--         Continue -> getPx (i, abs j `mod` n)+--     (False, True, False,  False) ->+--       case border of+--         Fill px -> px+--         Wrap -> getPx (i, j `mod` n)+--         Edge -> getPx (i, 0)+--         Reflect -> getPx (i, (abs j - 1) `mod` n)+--         Continue -> getPx (i, abs j `mod` n)+    --((False, False, False,  True), Edge) -> getPx (i, j `mod` n)+      +  -- case (i >= 0, j >= 0, i < m, j < n) of+  --   (True, True, True, True) -> getPx (i, j)+  --   (True, True, True, True) -> getPx (i, j)+  --   then getPx (i, j) else getPxB border where+++ -- | Image indexing function that returns a default pixel if index is out of bounds. defaultIndex :: MArray arr cs e =>                 Pixel cs e -> Image arr cs e -> (Int, Int) -> Pixel cs e@@ -525,7 +616,7 @@ checkDims err !ds@(m, n)   | m <= 0 || n <= 0 =      error $-    show err ++ ": Image dimensions are expected to be non-negative: " ++ show ds+    show err ++ ": Image dimensions are expected to be positive: " ++ show ds   | otherwise = ds {-# INLINE checkDims #-} @@ -565,7 +656,7 @@   signum      = map signum   {-# INLINE signum #-}   -  fromInteger = singleton . fromInteger+  fromInteger = scalar . fromInteger   {-# INLINE fromInteger #-}  @@ -574,13 +665,13 @@   (/)          = zipWith (/)   {-# INLINE (/) #-}   -  fromRational = singleton . fromRational +  fromRational = scalar . fromRational    {-# INLINE fromRational #-}   instance (Floating (Pixel cs e), Array arr cs e) =>          Floating (Image arr cs e) where-  pi    = singleton pi+  pi    = scalar pi   {-# INLINE pi #-}      exp   = map exp
src/Graphics/Image/Interface/Repa.hs view
@@ -24,9 +24,57 @@ import Graphics.Image.Interface.Repa.Generic import Graphics.Image.Interface.Repa.Storable import Graphics.Image.Interface.Repa.Unboxed+import Graphics.Image.Interface.Vector  +-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable VU RSS where+  exchange = exchangeThrough VS+  {-# INLINE exchange #-} ++-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable VU RPS where+  exchange = exchangeThrough VS+  {-# INLINE exchange #-}++++-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable VS RSU where+  exchange = exchangeThrough VU+  {-# INLINE exchange #-}+++-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable VS RPU where+  exchange = exchangeThrough VU+  {-# INLINE exchange #-}+++-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable RSU VS where+  exchange _ = exchange VS . toManifest+  {-# INLINE exchange #-}+++-- | Makes a copy of an image into a Storable Vector representation.+instance Exchangable RPU VS where+  exchange _ = exchange VS . toManifest+  {-# INLINE exchange #-}++++-- | Makes a copy of an image into a Unboxed Vector representation.+instance Exchangable RSS VU where+  exchange _ = exchange VU . toManifest+  {-# INLINE exchange #-}+++-- | Makes a copy of an image into a Unboxed Vector representation.+instance Exchangable RPS VU where+  exchange _ = exchange VU . toManifest+  {-# INLINE exchange #-}   -- | Makes a copy of an image into a Storable representation sequentially.
src/Graphics/Image/Interface/Repa/Generic.hs view
@@ -84,8 +84,8 @@     (R.fromFunction (Z :. m :. n) (getWindowPx . sh2ix))      (R.fromFunction (Z :. m :. n) (getBorderPx . sh2ix))     -  singleton = SScalar-  {-# INLINE singleton #-}+  scalar = SScalar+  {-# INLINE scalar #-}    index00 (SScalar px)  = px   index00 (STImage arr) = R.index arr (Z :. 0 :. 0)@@ -132,7 +132,7 @@   backpermute !newDims g !img = SDImage (backpermuteR (getDelayedS img) newDims g)   {-# INLINE backpermute #-} -  fromLists = STImage . fromListsR+  fromLists = STImage . fromListsRepa   {-# INLINE fromLists #-}    fold f !px0 (SDImage arr) = R.foldAllS f px0 arr@@ -158,8 +158,8 @@      SDImage (multR (show img1 ++ " X " ++ show img2) arr1 arr2)   (|*|) img1@(SDImage _) !img2            = compute img1 |*| img2   (|*|) !img1            img2@(SDImage _) = img1 |*| compute img2-  (|*|) (SScalar px1)    !img2            = STImage (singletonR px1) |*| img2-  (|*|) !img1            (SScalar px2)    = img1 |*| STImage (singletonR px2)+  (|*|) (SScalar px1)    !img2            = STImage (scalarR px1) |*| img2+  (|*|) !img1            (SScalar px2)    = img1 |*| STImage (scalarR px2)   {-# INLINE (|*|) #-}    toManifest _ = error $ "RS.toManifest: Cannot convert generic Repa " ++@@ -203,8 +203,8 @@     (R.fromFunction (Z :. m :. n) (getWindowPx . sh2ix))      (R.fromFunction (Z :. m :. n) (getBorderPx . sh2ix))     -  singleton = PScalar-  {-# INLINE singleton #-}+  scalar = PScalar+  {-# INLINE scalar #-}    index00 (PScalar px)  = px   index00 (PTImage arr) = R.index arr (Z :. 0 :. 0)@@ -251,7 +251,7 @@   backpermute !newDims g !img = PDImage (backpermuteR (getDelayedP img) newDims g)   {-# INLINE backpermute #-} -  fromLists = PTImage . fromListsR+  fromLists = PTImage . fromListsRepa   {-# INLINE fromLists #-}    fold f !px0 (PScalar px) = f px0 px@@ -286,8 +286,8 @@      PDImage (multR (show img1 ++ " X " ++ show img2) arr1 arr2)   (|*|) img1@(PDImage _) !img2            = compute img1 |*| img2   (|*|) !img1            img2@(PDImage _) = img1 |*| compute img2-  (|*|) (PScalar px1)    !img2            = PTImage (singletonR px1) |*| img2-  (|*|) !img1            (PScalar px2)    = img1 |*| PTImage (singletonR px2)+  (|*|) (PScalar px1)    !img2            = PTImage (scalarR px1) |*| img2+  (|*|) !img1            (PScalar px2)    = img1 |*| PTImage (scalarR px2)   {-# INLINE (|*|) #-}    toManifest _ = error $ "RP.toManifest: Cannot convert generic Repa " ++@@ -386,14 +386,14 @@ {-# INLINE backpermuteR #-}  -fromListsR :: (R.Target r e) => [[e]] -> R.Array r DIM2 e-fromListsR ls =+fromListsRepa :: (R.Target r e) => [[e]] -> R.Array r DIM2 e+fromListsRepa ls =   if all (== n) (P.map length ls)     then R.fromList (Z :. m :. n) . concat $ ls-    else error "fromListsR: Inner lists do not all have an equal length."+    else error "fromListsRepa: Inner lists do not all have an equal length."   where-    !(m, n) = checkDims "fromListsR" (length ls, length $ head ls)-{-# INLINE fromListsR #-}+    !(m, n) = checkDims "fromListsRepa" (length ls, length $ head ls)+{-# INLINE fromListsRepa #-}   @@ -417,8 +417,8 @@ {-# INLINE multR #-}  -singletonR :: (IVU.Unbox a, R.Target r a) => a -> R.Array r DIM2 a-singletonR !px = R.computeS $ R.fromFunction (Z :. 1 :. 1) $ const px+scalarR :: (IVU.Unbox a, R.Target r a) => a -> R.Array r DIM2 a+scalarR !px = R.computeS $ R.fromFunction (Z :. 1 :. 1) $ const px   getDelayedS :: Array (RS r) cs e => Image (RS r) cs e -> R.Array R.D DIM2 (Pixel cs e)
src/Graphics/Image/Interface/Repa/Storable.hs view
@@ -75,8 +75,8 @@   makeImageWindowed !sz !w f = SSImage . makeImageWindowed sz w f   {-# INLINE makeImageWindowed #-}  -  singleton = SSImage . I.singleton-  {-# INLINE singleton #-}+  scalar = SSImage . I.scalar+  {-# INLINE scalar #-}    index00 (SSImage img) = index00 img   {-# INLINE index00 #-}@@ -123,7 +123,7 @@   (|*|) (SSImage img1) (SSImage img2) = SSImage (img1 |*| img2)   {-# INLINE (|*|) #-} -  toManifest (SSImage (SScalar px)) = I.singleton px+  toManifest (SSImage (SScalar px)) = I.scalar px   toManifest (SSImage (STImage arr)) = fromRepaArrayStorable arr   toManifest !img = toManifest (compute img)   {-# INLINE toManifest #-}@@ -153,8 +153,8 @@   makeImageWindowed !sz !w f = PSImage . makeImageWindowed sz w f   {-# INLINE makeImageWindowed #-}  -  singleton = PSImage . singleton-  {-# INLINE singleton #-}+  scalar = PSImage . scalar+  {-# INLINE scalar #-}    index00 (PSImage img) = index00 img   {-# INLINE index00 #-}@@ -201,7 +201,7 @@   (|*|) (PSImage img1) (PSImage img2) = PSImage (img1 |*| img2)   {-# INLINE (|*|) #-} -  toManifest (PSImage (PScalar px)) = singleton px+  toManifest (PSImage (PScalar px)) = scalar px   toManifest (PSImage (PTImage arr)) = fromRepaArrayStorable arr   toManifest !img = toManifest (compute img)   {-# INLINE toManifest #-}@@ -223,7 +223,7 @@  -- | O(1) - Changes to Repa representation. instance Exchangable IVS.VS RSS where-  exchange _ !img@(dims -> (1, 1)) = singleton (index00 img)+  exchange _ !img@(dims -> (1, 1)) = scalar (index00 img)   exchange _ !img =     SSImage . STImage . toRepaArrayStorable $ img   {-# INLINE exchange #-}@@ -231,7 +231,7 @@  -- | O(1) - Changes to Repa representation. instance Exchangable IVS.VS RPS where-  exchange _ !img@(dims -> (1, 1)) = singleton (index00 img)+  exchange _ !img@(dims -> (1, 1)) = scalar (index00 img)   exchange _ !img =     PSImage . PTImage . toRepaArrayStorable $ img   {-# INLINE exchange #-}
src/Graphics/Image/Interface/Repa/Unboxed.hs view
@@ -68,8 +68,8 @@   makeImageWindowed !sz !w f = SUImage . makeImageWindowed sz w f   {-# INLINE makeImageWindowed #-}  -  singleton = SUImage . singleton-  {-# INLINE singleton #-}+  scalar = SUImage . scalar+  {-# INLINE scalar #-}    index00 (SUImage img) = index00 img   {-# INLINE index00 #-}@@ -116,7 +116,7 @@   (|*|) (SUImage img1) (SUImage img2) = SUImage (img1 |*| img2)   {-# INLINE (|*|) #-} -  toManifest (SUImage (SScalar px)) = singleton px+  toManifest (SUImage (SScalar px)) = scalar px   toManifest (SUImage (STImage arr)) =     IVU.fromUnboxedVector (sh2ix (R.extent arr)) (R.toUnboxed arr)   toManifest !img = toManifest (compute img)@@ -146,8 +146,8 @@   makeImageWindowed !sz !w f = PUImage . makeImageWindowed sz w f   {-# INLINE makeImageWindowed #-}  -  singleton = PUImage . singleton-  {-# INLINE singleton #-}+  scalar = PUImage . scalar+  {-# INLINE scalar #-}    index00 (PUImage img) = index00 img   {-# INLINE index00 #-}@@ -194,7 +194,7 @@   (|*|) (PUImage img1) (PUImage img2) = PUImage (img1 |*| img2)   {-# INLINE (|*|) #-} -  toManifest (PUImage (PScalar px)) = singleton px+  toManifest (PUImage (PScalar px)) = scalar px   toManifest (PUImage (PTImage arr)) =     IVU.fromUnboxedVector (sh2ix (R.extent arr)) (R.toUnboxed arr)   toManifest !img = toManifest (compute img)@@ -217,7 +217,7 @@  -- | O(1) - Changes to Repa representation. instance Exchangable IVU.VU RSU where-  exchange _ img@(dims -> (1, 1)) = singleton (index00 img)+  exchange _ img@(dims -> (1, 1)) = scalar (index00 img)   exchange _ img =     SUImage . STImage . R.fromUnboxed (ix2sh $ dims img) . IVU.toUnboxedVector $ img   {-# INLINE exchange #-}@@ -225,7 +225,7 @@  -- | O(1) - Changes to Repa representation. instance Exchangable IVU.VU RPU where-  exchange _ img@(dims -> (1, 1)) = singleton (index00 img)+  exchange _ img@(dims -> (1, 1)) = scalar (index00 img)   exchange _ img =     PUImage . PTImage . R.fromUnboxed (ix2sh $ dims img) . IVU.toUnboxedVector $ img   {-# INLINE exchange #-}
src/Graphics/Image/Interface/Vector/Generic.hs view
@@ -4,7 +4,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}@@ -41,7 +41,7 @@ type family Repr arr :: * -> *  instance Show r => Show (V r) where-  show r = "Vector " ++ show r+  show (V r) = "Vector " ++ show r  instance SuperClass (V r) cs e => BaseArray (V r) cs e where   type SuperClass (V r) cs e = (Show r, ColorSpace cs e, Num (Pixel cs e),@@ -90,8 +90,8 @@       {-# INLINE generate #-}   {-# INLINE makeImageWindowed #-}   -  singleton = VScalar-  {-# INLINE singleton #-}+  scalar = VScalar+  {-# INLINE scalar #-}    index00 (VScalar px) = px   index00 (VImage _ _ v) = v VG.! 0
src/Graphics/Image/Interface/Vector/Storable.hs view
@@ -65,8 +65,8 @@   makeImageWindowed !sh !window f g = VSImage $ makeImageWindowed sh window f g   {-# INLINE makeImageWindowed #-}   -  singleton = VSImage . singleton-  {-# INLINE singleton #-}+  scalar = VSImage . scalar+  {-# INLINE scalar #-}    index00 (VSImage img) = index00 img   {-# INLINE index00 #-}
src/Graphics/Image/Interface/Vector/Unboxed.hs view
@@ -66,8 +66,8 @@   makeImageWindowed !sh !window f g = VUImage $ makeImageWindowed sh window f g   {-# INLINE makeImageWindowed #-}   -  singleton = VUImage . singleton-  {-# INLINE singleton #-}+  scalar = VUImage . scalar+  {-# INLINE scalar #-}    index00 (VUImage img) = index00 img   {-# INLINE index00 #-}
src/Graphics/Image/Processing.hs view
@@ -47,7 +47,7 @@   getNewDims !(m, n) = (1 + m*k, 1 + n*k)   {-# INLINE getNewDims #-}   getNewPx !getPx !(i, j) = if i `mod` k == 0 || j `mod` k == 0-                            then broadcastC $ fromDouble 0.5+                            then promote $ fromDouble 0.5                             else getPx ((i - 1) `div` k, (j - 1) `div` k)   {-# INLINE getNewPx #-} {-# INLINE pixelGrid #-}
src/Graphics/Image/Processing/Binary.hs view
@@ -20,7 +20,7 @@   toImageBinaryUsing, toImageBinaryUsing2,   thresholdWith, compareWith,   -- * Bitwise operations-  (.&&.), (.||.), invert,+  or, and, (.&&.), (.||.), invert,   -- * Thresholding   Thresholding(..),   -- * Binary Morphology@@ -28,10 +28,8 @@   erode, dialate, open, close   ) where -import Prelude hiding (map, zipWith)-#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<*>))-#endif+import Prelude hiding (map, zipWith, and, or)+import Data.Bits import Graphics.Image.Interface import Graphics.Image.ColorSpace import Graphics.Image.Processing.Convolution@@ -146,7 +144,7 @@                       (Pixel cs e -> Bool) -- ^ Predicate                    -> Image arr cs e -- ^ Source image.                    -> Image arr Binary Bit-toImageBinaryUsing !f = map (fromBool . f)+toImageBinaryUsing f = map (fromBool . f) {-# INLINE toImageBinaryUsing #-}  @@ -156,7 +154,7 @@                     -> Image arr cs e -- ^ First source image.                     -> Image arr cs e -- ^ Second source image.                     -> Image arr Binary Bit-toImageBinaryUsing2 !f =  zipWith (((.).(.)) fromBool f)+toImageBinaryUsing2 f =  zipWith (((.).(.)) fromBool f) {-# INLINE toImageBinaryUsing2 #-}  @@ -173,7 +171,7 @@                  -- ^ Pixel containing a thresholding function per channel.               -> Image arr cs e -- ^ Source image.               -> Image arr Binary Bit-thresholdWith !f = map (fromBool . F.and . (f <*>))+thresholdWith f = map (fromBool . F.and . (f <*>)) {-# INLINE thresholdWith #-}  @@ -188,6 +186,18 @@             -> Image arr Binary Bit compareWith !f = zipWith (\ !px1 !px2 -> fromBool . F.and $ (f <*> px1 <*> px2)) {-# INLINE compareWith #-}+++-- | Disjunction of all pixels in a Binary image+or :: Array arr Binary Bit => Image arr Binary Bit -> Bool+or = isOn . fold (.|.) off+{-# INLINE or #-}+++-- | Conjunction of all pixels in a Binary image+and :: Array arr Binary Bit => Image arr Binary Bit -> Bool+and = isOn . fold (.&.) on+{-# INLINE and #-}   {- $morphology In order to demonstrate how morphological operations work, a
src/Graphics/Image/Processing/Convolution.hs view
@@ -72,7 +72,7 @@ -- -- Example using <https://en.wikipedia.org/wiki/Sobel_operator Sobel operator>: ----- >>> frog <- readImageY RP "images/frog.jpg"+-- >>> frog <- readImageY RPU "images/frog.jpg" -- >>> let frogX = convolve Edge (fromLists [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) frog -- >>> let frogY = convolve Edge (fromLists [[-1,-2,-1], [ 0, 0, 0], [ 1, 2, 1]]) frog -- >>> displayImage $ normalize $ sqrt (frogX ^ 2 + frogY ^ 2)
src/Graphics/Image/Processing/Geometric.hs view
@@ -11,8 +11,8 @@ -- module Graphics.Image.Processing.Geometric (   -- ** Sampling-  downsampleRows, downsampleCols, downsample, downsampleF,-  upsampleRows, upsampleCols, upsample, upsampleF,+  downsampleRows, downsampleCols, downsample,+  upsampleRows, upsampleCols, upsample,   -- ** Concatenation   leftToRight, topToBottom,   -- ** Canvas@@ -31,69 +31,104 @@  import Graphics.Image.Interface import Graphics.Image.Processing.Interpolation+import qualified Data.Vector as V  -downsampleF :: Array arr cs e => (Int, Int) -> Image arr cs e -> Image arr cs e-downsampleF !(fm, fn) !img =-  traverse-    img-    (\ !(m, n) -> (m `div` fm, n `div` fn))-    (\ !getPx !(i, j) -> getPx (i * fm, j * fn))-{-# INLINE downsampleF #-} +-- | Downsample an image. Drop all rows and colums that satisfy the+-- predicates. For example, in order to discard every 5th row and keep every+-- even indexed column:+--+-- >>> frog <- readImageRGB RPU "images/frog.jpg"+-- >>> displayImage $ downsample ((0 ==) . (`mod` 5)) odd frog+-- +-- <<images/frog.jpg>> <<images/frog_downsampled.jpg>>+-- +downsample :: Array arr cs e =>+              (Int -> Bool) -- ^ Rows predicate+           -> (Int -> Bool) -- ^ Columns predicate+           -> Image arr cs e -- ^ Source image+           -> Image arr cs e+downsample mPred nPred !img =+  traverse img (const (V.length rowsIx, V.length colsIx)) getNewPx where+    !(m, n) = dims img+    !rowsIx = V.filter (not . mPred) $ V.enumFromN 0 m+    !colsIx = V.filter (not . nPred) $ V.enumFromN 0 n+    getNewPx getPx !(i, j) = getPx (V.unsafeIndex rowsIx i, V.unsafeIndex colsIx j)+{-# INLINE downsample #-} --- | Upsample an image by a positive factor. Every -upsampleF :: Array arr cs e => (Int, Int) -> Image arr cs e -> Image arr cs e-upsampleF !(fm, fn) !img =-  traverse-    img-    (\ !(m, n) -> (m * fm, n * fn))-    (\ !getPx !(i, j) ->-        if i `mod` fm == 0 && j `mod` fn == 0-          then getPx (i `div` fm, j `div` fn)-          else 0)-{-# INLINE upsampleF #-} +-- | Upsample an image by inserting rows and columns with zero valued pixels+-- into an image. Supplied functions specify how many rows/columns shoud be+-- inserted @(before, after)@ a particular row/column. Returning a negative+-- value in a tuple will result in an error. E.g. insert 2 columns before and 4+-- columns after every 10th column, while leaving rows count unchanged:+--+-- >>> frog <- readImageRGB RPU "images/frog.jpg"+-- >>> displayImage $ upsample (const (0, 0)) (\ k -> if k `mod` 10 == 0 then (2, 4) else (0, 0)) frog+--+-- <<images/frog.jpg>> <<images/frog_upsampled.jpg>>+--+upsample :: Array arr cs e =>+             (Int -> (Int, Int))+          -> (Int -> (Int, Int))             +          -> Image arr cs e+          -> Image arr cs e+upsample mAdd nAdd !img = traverse img (const (newM, newN)) getNewPx where+  !(m, n) = dims img+  validate !p@(pre, post)+    | pre < 0 || post < 0 =+      error $ "upsample: negative values are not accepted: " ++ show p+    | otherwise = p+  !rowsIx = V.unfoldr (spread (V.map (validate . mAdd) $ V.enumFromN 0 m)) (0, Nothing, Nothing)+  !colsIx = V.unfoldr (spread (V.map (validate . nAdd) $ V.enumFromN 0 n)) (0, Nothing, Nothing)+  !newM = V.length rowsIx+  !newN = V.length colsIx+  spread !v !params =+    case params of+      (k, Nothing, Nothing) | k == V.length v -> Nothing+      (k, Nothing, Nothing) ->+        let (pre, post) = v V.! k in spread v (k, Just pre, Just post)+      (k, Just 0, my)      -> Just (Just k, (k, Nothing, my))+      (k, Just x, my)      -> Just (Nothing, (k, Just (x-1), my))+      (k, Nothing, Just 0) -> spread v (k+1, Nothing, Nothing)+      (k, Nothing, Just y) -> Just (Nothing, (k, Nothing, Just (y-1)))+  {-# INLINE spread #-}+  getNewPx getPx !(i, j) =+    case (V.unsafeIndex rowsIx i, V.unsafeIndex colsIx j) of+      (Just i', Just j') -> getPx (i', j')+      _                  -> 0+  {-# INLINE getNewPx #-}+{-# INLINE upsample #-} + -- | Downsample an image by discarding every odd row. downsampleRows :: Array arr cs e => Image arr cs e -> Image arr cs e-downsampleRows = downsampleF (2, 1)+downsampleRows = downsample odd (const False) {-# INLINE downsampleRows #-}   -- | Downsample an image by discarding every odd column. downsampleCols :: Array arr cs e => Image arr cs e -> Image arr cs e-downsampleCols = downsampleF (1, 2)+downsampleCols = downsample (const False) odd {-# INLINE downsampleCols #-}  --- | Downsample an image by discarding every odd row and column.-downsample :: Array arr cs e => Image arr cs e -> Image arr cs e-downsample = downsampleF (2, 2)-{-# INLINE downsample #-}-- -- | Upsample an image by inserting a row of back pixels after each row of a -- source image. upsampleRows :: Array arr cs e => Image arr cs e -> Image arr cs e-upsampleRows = upsampleF (2, 1)+upsampleRows = upsample (const (0, 1)) (const (0, 0))-- upsampleF (2, 1) {-# INLINE upsampleRows #-}   -- | Upsample an image by inserting a column of back pixels after each column of a -- source image. upsampleCols :: Array arr cs e => Image arr cs e -> Image arr cs e-upsampleCols = upsampleF (1, 2)+upsampleCols = upsample (const (0, 0)) (const (0, 1))-- upsampleF (2, 1) {-# INLINE upsampleCols #-}  --- | Upsample an image by inserting a row and a column of back pixels after each--- row and a column of a source image.-upsample :: Array arr cs e => Image arr cs e -> Image arr cs e-upsample = upsampleF (2, 2)-{-# INLINE upsample #-} - -- | Concatenate two images together into one. Both input images must have the -- same number of rows. leftToRight :: Array arr cs e => Image arr cs e -> Image arr cs e -> Image arr cs e@@ -150,7 +185,7 @@ -- except the ones outside the border, which are handled according to supplied -- resolution strategy. ----- <<images/haskell_40.png>>+-- <<images/logo_40.png>> -- -- For example, it can be used to make a tile from the image above, or simply -- scale the canvas and place it in a middle:
src/Graphics/Image/Processing/Interpolation.hs view
@@ -52,8 +52,8 @@     {-# INLINE getPx' #-}     !(i0, j0) = (floor i, floor j)     !(i1, j1) = (i0 + 1, j0 + 1)-    !iPx = broadcastC $ fromDouble (i - fromIntegral i0)-    !jPx = broadcastC $ fromDouble (j - fromIntegral j0)+    !iPx = promote $ fromDouble (i - fromIntegral i0)+    !jPx = promote $ fromDouble (j - fromIntegral j0)     !f00 = getPx' (i0, j0)     !f10 = getPx' (i1, j0)     !f01 = getPx' (i0, j1) 
tests/Graphics/Image/ColorSpaceSpec.hs view
@@ -1,34 +1,42 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} module Graphics.Image.ColorSpaceSpec (spec) where -#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif import Test.Hspec import Test.QuickCheck    import Graphics.Image as I import Graphics.Image.Interface as II-import Graphics.Image.ColorSpace  -instance Arbitrary RGB where-  arbitrary = do-    NonNegative c <- arbitrary-    return $ toEnum (c `mod` 3)+instance Arbitrary (Pixel Binary Bit) where+  arbitrary = elements [on, off] -instance Arbitrary e => Arbitrary (Pixel RGB e) where-  arbitrary = PixelRGB <$> arbitrary <*> arbitrary <*> arbitrary+instance (ColorSpace Y e, Arbitrary e) => Arbitrary (Pixel Y e) where+  arbitrary = fromComponents <$> arbitrary +instance (ColorSpace YA e, Arbitrary e) => Arbitrary (Pixel YA e) where+  arbitrary = fromComponents <$> arbitrary -instance (MArray VU RGB e, Arbitrary e) => Arbitrary (Image VU RGB e) where+instance (ColorSpace RGB e, Arbitrary e) => Arbitrary (Pixel RGB e) where+  arbitrary = fromComponents <$> arbitrary++instance (ColorSpace RGBA e, Arbitrary e) => Arbitrary (Pixel RGBA e) where+  arbitrary = fromComponents <$> arbitrary+++instance (MArray VU cs e, Arbitrary (Pixel cs e)) => Arbitrary (Image VU cs e) where   arbitrary = do     (Positive m, Positive n) <- arbitrary-    II.mapM (const arbitrary) $ I.makeImage (m, n) (const $ PixelGray (0 :: Double))-  +    II.makeImageM (m, n) (const arbitrary)+++instance (MArray VS cs e, Arbitrary (Pixel cs e)) => Arbitrary (Image VS cs e) where+  arbitrary = do+    (Positive m, Positive n) <- arbitrary+    II.makeImageM (m, n) (const arbitrary)+  prop_ToFromComponents :: (ColorSpace cs e, Eq (Pixel cs e)) =>                          Pixel cs e -> Bool
+ tests/Graphics/Image/IO/FormatsSpec.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Graphics.Image.IO.FormatsSpec+  ( spec ) where++import Prelude as P+import qualified Data.ByteString.Lazy as BL+import Test.Hspec+import Test.QuickCheck hiding (Result(..))+import Test.QuickCheck.Property++import Graphics.Image as I++import Graphics.Image.InterfaceSpec()+++data EncDec a b = EncDec a b deriving Show++instance Arbitrary (EncDec InputFormat OutputFormat) where+  arbitrary = elements $ fmap (uncurry EncDec)+              [ (InputBMP, OutputBMP)+              , (InputHDR, OutputHDR)+              , (InputPNG, OutputPNG)+              , (InputTIF, OutputTIF)+              , (InputTGA, OutputTGA)+              ]++++prop_EncodeDecode :: Image VS RGB Word8 -> EncDec InputFormat OutputFormat -> Result+prop_EncodeDecode imgWord8 (EncDec input output) =+  case decode input (BL.toStrict (encode output [] (I.map (fmap toDouble) imgWord8))) of+    Left err ->+      failed+      { reason = err+      }+    Right (img' :: Image VS RGB Double) ->+      let imgWord8' = I.map (fmap toWord8) img' in+      if eqTol 2 imgWord8 imgWord8'+        then succeeded+        else failed+             { reason =+               "Original img <" ++ show input ++ ">: \n" +++               show (toLists imgWord8) +++               "\n differes from decoded img: \n" ++ show (toLists imgWord8')+             }+          ++spec :: Spec+spec = do+  describe "Encode/Decode" $ do+    it "Input/Output Formats" $ property prop_EncodeDecode
tests/Graphics/Image/InterfaceSpec.hs view
@@ -30,13 +30,9 @@  -- | Generator for values in range @[0, 1]@ arbitraryDouble :: Gen Double-arbitraryDouble = do-  Positive v <- arbitrary-  let v' = v - fromInteger (floor v)-  if v' == 0-    then choose (0, 1)-    else return v'+arbitraryDouble = toDouble <$> (arbitrary :: Gen Word64) + instance Arbitrary (Pixel Y Word8) where   arbitrary = PixelY <$> arbitrary @@ -49,11 +45,16 @@ instance Arbitrary (Pixel RGB Double) where   arbitrary = PixelRGB <$> arbitraryDouble <*> arbitraryDouble <*> arbitraryDouble -instance (MArray arr cs e, Arbitrary (Pixel cs e)) => Arbitrary (Image arr cs e) where+instance (Array arr cs e, MArray arr cs e, Arbitrary (Pixel cs e)) =>+         Arbitrary (Image arr cs e) where   arbitrary = do     (Positive (Small m), Positive (Small n)) <- arbitrary     I.makeImageM (m, n) (const arbitrary) +  shrink img | dims img == (1,1) = []+             | rows img == 1 = [downsampleCols img]+             | cols img == 1 = [downsampleRows img]+             | otherwise = [downsample even even img, downsample odd odd img]  instance (Array arr1 cs e, Array arr2 cs e, Arbitrary (Pixel cs e)) =>          Arbitrary (Identical arr1 arr2 cs e) where@@ -62,8 +63,8 @@     getPx <- arbitrary     if (m, n) == (1, 1)       then do-        img1 <- elements [I.makeImage (m, n) getPx, I.singleton (getPx (0, 0))]-        img2 <- elements [I.makeImage (m, n) getPx, I.singleton (getPx (0, 0))]+        img1 <- elements [I.makeImage (m, n) getPx, I.scalar (getPx (0, 0))]+        img2 <- elements [I.makeImage (m, n) getPx, I.scalar (getPx (0, 0))]         return $ Identical img1 img2       else return $            Identical (I.makeImage (m, n) getPx) (I.makeImage (m, n) getPx)
tests/Graphics/Image/Processing/BinarySpec.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE FlexibleContexts #-}-module Graphics.Image.Processing.BinarySpec (spec) where+module Graphics.Image.Processing.BinarySpec (spec, struct) where  import Test.Hspec @@ -27,6 +27,8 @@     , [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]     , [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]     ]++ struct :: Image VU Binary Bit struct = fromLists [[0,1,0],[1,1,0],[0,1,0]] 
tests/Graphics/Image/ProcessingSpec.hs view
@@ -1,15 +1,14 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} module Graphics.Image.ProcessingSpec (spec) where  import Test.Hspec import Test.QuickCheck -import qualified Graphics.Image.Interface as I-import Graphics.Image.Types-import Graphics.Image.Processing+import Graphics.Image as I  import Graphics.Image.InterfaceSpec (translateWrap, dummyImage10x20)---import Graphics.Image.Processing.BinarySpec+import Graphics.Image.Processing.BinarySpec (struct)  data Interpol   = I1 Nearest@@ -34,9 +33,25 @@ prop_sampleCols :: Image VU Y Double -> Bool prop_sampleCols img = img == downsampleCols (upsampleCols img) -prop_sample :: Image VU Y Double -> Bool-prop_sample img = img == downsample (upsample img)+prop_upsampleNegative :: NonNegative Int -> NonNegative Int+                      -> NonNegative Int -> NonNegative Int+                      -> Image VU Y Double -> Property+prop_upsampleNegative (NonNegative p1) (NonNegative p2) (NonNegative p3) (NonNegative p4) img =+  p1 /= 0 && p2 /= 0 && p3 /= 0 && p4 /= 0 ==>+  expectFailure (upsample (const (-p1, -p2)) (const (-p3, -p4)) img `seq` True) +prop_upsampleId :: Image VU Y Double -> Bool+prop_upsampleId img = img == upsample (const (0,0)) (const (0,0)) img++prop_downsampleId :: Image VU Y Double -> Bool+prop_downsampleId img = img == downsample (const False) (const False) img++prop_sampleEven :: Image VU Y Double -> Bool+prop_sampleEven img = img == downsample even even (upsample (const (1,0)) (const (1,0)) img)++prop_sampleOdd :: Image VU Y Double -> Bool+prop_sampleOdd img = img == downsample odd odd (upsample (const (0,1)) (const (0,1)) img)+ prop_translateWrap :: (Int, Int) -> Image VU RGB Double -> Bool prop_translateWrap shift img = translateWrap shift img == translate Wrap shift img @@ -76,9 +91,11 @@ spec :: Spec spec = do   describe "Processing Properties" $-    do it "sampleRows" $ property prop_sampleRows-       it "sampleCols" $ property prop_sampleCols-       it "sample" $ property prop_sample+    do it "[up/down]sampleRows" $ property prop_sampleRows+       it "[up/down]sampleCols" $ property prop_sampleCols+       it "[up/down]sampleId" $ property $ conjoin [prop_upsampleId, prop_downsampleId]+       it "[up/down]sampleEven" $ property prop_sampleEven+       it "[up/down]sampleOdd" $ property prop_sampleOdd        it "translateWrap" $ property prop_translateWrap        it "cropSuperimpose" $ property prop_cropSuperimpose        it "concatRotate" $ property prop_concatRotate@@ -86,6 +103,13 @@        it "rotate180" $ property prop_rotate180        it "rotate270" $ property prop_rotate270        it "rotate360" $ property prop_rotate360+  describe "Processing Unit Tests" $+    do it "upsampleRows" $ upsampleRows struct `shouldBe`+         I.fromLists [[0,1,0],[0,0,0],[1,1,0],[0,0,0],[0,1,0],[0,0,0]]+       it "upsampleCols" $ upsampleCols struct `shouldBe`+         I.fromLists [[0,0,1,0,0,0],[1,0,1,0,0,0],[0,0,1,0,0,0]]+       it "downsampleRows" $ downsampleRows struct `shouldBe` I.fromLists [[0,1,0],[0,1,0]]+       it "downsampleCols" $ downsampleCols struct `shouldBe` I.fromLists [[0,0],[1,0],[0,0]]   describe "Processing Errors" $     do it "crop start index outside" $          do shouldThrow (return $! crop (-1, -1) (1, 1) dummyImage10x20) anyException@@ -98,14 +122,12 @@        it "crop negative dimensions" $          do shouldThrow (return $! crop (1, 1) (-5, 15) dummyImage10x20) anyException             shouldThrow (return $! crop (1, 1) (5, -15) dummyImage10x20) anyException-       it "upsample non-positive" $-         do shouldThrow (return $! upsampleF (0, 1) dummyImage10x20) anyException-            shouldThrow (return $! upsampleF (1, 0) dummyImage10x20) anyException-            shouldThrow (return $! upsampleF (-1, -1) dummyImage10x20) anyException-       it "downsample non-positive" $-         do shouldThrow (return $! downsampleF (0, 1) dummyImage10x20) anyException-            shouldThrow (return $! downsampleF (1, 0) dummyImage10x20) anyException-            shouldThrow (return $! downsampleF (-1, -1) dummyImage10x20) anyException+       it "upsampleNegative" $ property prop_upsampleNegative+       it "downsample all" $+         do shouldThrow (return $! downsample (const True) even dummyImage10x20) anyException+            shouldThrow (return $! downsample even (const True) dummyImage10x20) anyException+            shouldThrow (return $! downsample (const True) (const True) dummyImage10x20)+                        anyException        it "concat dimension mismatch" $          do shouldThrow               (return $! leftToRight dummyImage10x20 $ I.transpose dummyImage10x20)