packages feed

prizm 0.3.1.0 → 0.3.1.1

raw patch · 13 files changed

+512/−210 lines, 13 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGES view
@@ -1,3 +1,11 @@+-*- mode: org -*-++0.3.1.1+=======++- Adding a little bit of documentation and better documentation in the+  Description field.+ 0.3.1.0 ======= 
− README.md
@@ -1,38 +0,0 @@-Welcome!-=====--Prizm is a haskell library for dealing with colors. Please contribute!--My inspiration for writing this was Sass and Bourbon, both implement interesting color handling functions for-use in stylesheets and I wanted the same thing for use in [Clay](http://fvisser.nl/clay/) (also for-[Bentonite](https://github.com/ixmatus/bentonite)).--## Colour Module--There is some overlap with the Haskell Colour Module that already exists; however, this library is filling a couple of-needs the other doesn't satisfy.--## Supported Algorithms--- sRGB <-> CIE XYZ-- CIE XYZ <-> CIE L\*ab-- CIE L\*ab <-> CIE L\*Ch--## Supported Functions--- Color interpolation-- Tinting / Darkening-- Lightness-- Hue-- Chroma/Saturation--All of these functions operate on color within the CIE L\*Ch representation. The percentage values may range between--100 and 100.--[General Color Formulas, Data, and Algorithms](http://www.brucelindbloom.com/index.html?Info.html)--[CIE Conversion Mathematics](http://rip94550.wordpress.com/2011/07/04/color-cielab-and-tristimulus-xyz/)--[Conversion Algorithm Sources](http://www.easyrgb.com/index.php?X=MATH&H=01)--[Good list of useful color manipulation](https://github.com/mikeemoo/ColorJizz-PHP/blob/master/src/MischiefCollective/ColorJizz/ColorJizz.php)
+ README.org view
@@ -0,0 +1,36 @@+* Welcome!+  `prizm` is a Haskell library for computing with colors. Specifically+  providing functions for transforming between different color spaces,+  interpolating colors and adjusting the tint, shade, hue, or+  lightness or a color.++  My inspiration for writing this was Sass and Bourbon, both implement+  interesting functions for computing with colors for use in+  stylesheets and I wanted the same thing for use in [[http://fvisser.nl/clay/][Clay]].++** Colour Module+   There is some overlap with the Haskell Colour Module that already+   exists; however, this library is filling a couple of needs the+   other doesn't satisfy. Primarily transformations and color+   mutations in the CIE L*Ch space.++** Supported Algorithms+   - sRGB <-> CIE XYZ+   - CIE XYZ <-> CIE L\*ab+   - CIE L\*ab <-> CIE L\*Ch++** Supported Functions+   - Color interpolation+   - Tinting / Darkening+   - Lightness+   - Hue+   - Chroma/Saturation++   All of these functions operate on color within the CIE L\*Ch+   representation. The percentage values may range between -100+   and 100.++[[http://www.brucelindbloom.com/index.html?Info.html][General Color Formulas, Data, and Algorithms]]+[[http://rip94550.wordpress.com/2011/07/04/color-cielab-and-tristimulus-xyz/][CIE Conversion Mathematics]]+[[http://www.easyrgb.com/index.php?X=MATH&H=01][Conversion Algorithm Sources]]+[[https://github.com/mikeemoo/ColorJizz-PHP/blob/master/src/MischiefCollective/ColorJizz/ColorJizz.php][Good list of useful color manipulation formulas]]
prizm.cabal view
@@ -1,29 +1,73 @@-Name:                prizm-Version:             0.3.1.0-Synopsis:            A haskell library for computing with colors+name:                prizm+version:             0.3.1.1+synopsis:            Compute with colors and differenct color spaces+homepage:            https://github.com/ixmatus/prizm+license:             BSD3+license-file:        LICENSE+author:              Parnell Springmeyer+maintainer:          parnell@ixmat.us+copyright:           (c) 2013 Parnell Springmeyer+category:            Graphics+build-type:          Simple+stability:           stable+bug-reports:         https://github.com/ixmatus/prizm/issues+package-url:         http://hackage.haskell.org/package/prizm+tested-with:         GHC == 7.6.3+cabal-version:       >=1.14.0 -Description:         Prizm is a library for converting between-                     different color representations and mutating-                     colors (interpolation, lightness, hue, chroma,-                     tint/shade). -Homepage:            https://github.com/ixmatus/prizm-License:             BSD3-License-file:        LICENSE-Author:              Parnell Springmeyer-Maintainer:          ixmatus@gmail.com-Copyright:           (c) 2013 Parnell Springmeyer-Category:            Graphics-Build-type:          Simple-Stability:           alpha-Bug-reports:         https://github.com/ixmatus/prizm/issues-Package-url:         http://hackage.haskell.org/package/prizm-Tested-with:         GHC == 7.4.2-Cabal-version:       >=1.14.0+description:+  `prizm` is a Haskell library for computing with colors. Specifically+  providing functions for transforming between different color spaces,+  interpolating colors and adjusting the tint, shade, hue, or+  lightness or a color.+  .+  My inspiration for writing this was Sass and Bourbon, both implement+  interesting functions for computing with colors for use in+  stylesheets and I wanted the same thing for use in <http://fvisser.nl/clay/ Clay>.+  .+  /Colour Module/+  .+  There is some overlap with the Haskell Colour Module that already+  exists; however, this library is filling a couple of needs the+  other doesn't satisfy. Primarily transformations and color+  mutations in the CIE L*Ch space.+  .+  /Supported Algorithms & Functions/+  .+  All of these functions operate on color within the CIE L\*Ch+  representation. The percentage values may range between -100+  and 100.+  .+  * sRGB <-> CIE XYZ+  .+  * CIE XYZ <-> CIE L\*ab+  .+  * CIE L\*ab <-> CIE L\*Ch+  .+  * Color interpolation+  .+  * Tinting / Darkening+  .+  * Lightness+  .+  * Hue+  .+  * Chroma/Saturation+  .+  /Formulas, Resources, and Links/+  .+  * <http://www.brucelindbloom.com/index.html?Info.html General Color Formulas, Data, and Algorithms>+  .+  * <http://rip94550.wordpress.com/2011/07/04/color-cielab-and-tristimulus-xyz/ CIE Conversion Mathematics>+  .+  * <http://www.easyrgb.com/index.php?X=MATH&H=01 Conversion Algorithm Sources>+  .+  * <https://github.com/mikeemoo/ColorJizz-PHP/blob/master/src/MischiefCollective/ColorJizz/ColorJizz.php Good list of useful color manipulation formulas>  extra-source-files:     LICENSE-    README.md+    README.org     CHANGES  source-repository head@@ -46,7 +90,7 @@     Data.Prizm.Color.Matrices.XYZ      ghc-options: -Wall-  +   build-depends: base >= 4.5 && < 5,                  text >= 0.11.2.3 @@ -54,7 +98,10 @@   type:           exitcode-stdio-1.0   hs-source-dirs: tests   main-is:        QC.hs-  other-modules:  QC.SRGB+  default-language: Haskell2010+  other-modules:+    QC.SRGB+    QC.CIE    ghc-options:     -Wall -threaded -rtsopts
src/Data/Prizm/Color.hs view
@@ -1,25 +1,67 @@-module Data.Prizm.Color (-  (<|>)+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- 'Data.Prizm.Color' provides functions for blending colors,+-- convenience blending ('tint' and 'shade'), and adjusting the 'hue',+-- 'lightness', or 'chroma' of a given color.+--+-- These functions require your color to be represented in @CIE+-- L*Ch@. The reason for this is because the @L*CH@ color space+-- represents colors closest to how the human eye sees them. Blending+-- and transforming a color in @L*Ch@ maintains the brightness of the+-- colors more accurately. Here is a link to a blog post by someone+-- detailing the differences and documenting them well:+-- <http://www.stuartdenman.com/improved-color-blending/ Improved Color Blending>.+--+-- NOTE: the transformations between color spaces are intensive, if+-- you have a HEX or RGB color it first needs to be transformed to the+-- 'CIEXYZ' color space, then the 'CIELAB' space, and finally to+-- 'CIELCH'.+--+-- I may at some point try to generalize the function's types but I+-- wanted to first support 'CIELCH' as the transformation format.+----------------------------------------------------------------------------+module Data.Prizm.Color+(+-- * Blending+  interpolate+, (<|>) , shade , tint+-- * Lightness, hue, and chroma , lightness , chroma , hue-, interpolate+-- * Types+, module Data.Prizm.Types ) where -import Control.Applicative hiding ((<|>))--import Data.Prizm.Types--pct :: Integer -> Double-pct = (/100) . fromIntegral . (max (-100)) . (min 100)+import           Control.Applicative hiding ((<|>))+import           Data.Prizm.Types -pctClamp :: Integer -> Integer-pctClamp i = max (min i 100) 0+------------------------------------------------------------------------------+-- Blending+------------------------------------------------------------------------------ -clamp :: Double -> Double -> Double-clamp i clmp = max (min i clmp) 0.0+-- | Interpolate two colors with a weight.+--+-- Weight is applied left to right, so if a weight of 25% is supplied,+-- then the color on the left will be multiplied by 25% and the second+-- color will be multiplied by 75%.+--+-- @CIE L*Ch@ is used because the interpolation between the colors is+-- more accurate than 'CIELAB', 'CIEXYZ', and S'RGB' color spaces.+interpolate :: Percent -> (CIELCH Double, CIELCH Double) -> CIELCH Double+interpolate w (a,b) =+    let w' = (pct (pctClamp w))+        (CIELCH l c h) = (-) <$> b <*> a+        a' = (*w') <$> (CIELCH l c (shortestPath h))+    in (+) <$> a' <*> a  -- | Blend two colors using an interpolation value of 50%. (<|>) :: CIELCH Double -> CIELCH Double -> CIELCH Double@@ -33,36 +75,39 @@ tint :: CIELCH Double -> Percent -> CIELCH Double tint c w = interpolate (pctClamp w) (c, CIELCH 100.0 0.0 360.0) --- | Darken a color.+------------------------------------------------------------------------------+-- Lightness, hue, and chroma+------------------------------------------------------------------------------++-- | Adjust the lightness / darkness of a color. lightness :: CIELCH Double -> Percent -> CIELCH Double lightness (CIELCH l c h) w = (CIELCH (clamp (l + (100*(pct (pctClamp w)))) 100.0) c h) --- | Change the hue of a color.+-- | Adjust the hue of a color. hue :: CIELCH Double -> Percent -> CIELCH Double hue (CIELCH l c h) w = (CIELCH l c (clamp (h + (360*(pct (pctClamp w)))) 360.0)) --- | Change the saturation/chroma of a color. A maximum chroma value--- of 120 is assumed here, anything more is generally considered out--- of gamut.+-- | Adjust the saturation/chroma of a color.+--+-- A maximum chroma value of 120 is assumed here, anything more is+-- generally considered out of gamut. chroma :: CIELCH Double -> Percent -> CIELCH Double chroma (CIELCH l c h) w = (CIELCH l (clamp (c + (120*(pct (pctClamp w)))) 120.0) h) --- | Interpolate two colors--- --- Weight is applied left to right, so if a weight of 25% is supplied,--- then the color on the left will be multiplied by 25% and the second--- color will be multiplied by 75%.--- --- CIE L*Ch is used because the interpolation between the colors is--- more accurate than L*ab, XYZ, and sRGB color spaces.-interpolate :: Percent -> (CIELCH Double, CIELCH Double) -> CIELCH Double-interpolate w (a,b) =-    let w' = (pct (pctClamp w))-        (CIELCH l c h) = (-) <$> b <*> a-        a' = (*w') <$> (CIELCH l c (shortestPath h))-    in (+) <$> a' <*> a+------------------------------------------------------------------------------+-- Utility Functions+------------------------------------------------------------------------------  shortestPath :: Double -> Double shortestPath h | h > 180    = h - 360                | h < (-180) = h + 360                | otherwise  = h++pct :: Integer -> Double+pct = (/100) . fromIntegral . (max (-100)) . (min 100)++pctClamp :: Integer -> Integer+pctClamp i = max (min i 100) 0++clamp :: Double -> Double -> Double+clamp i clmp = max (min i clmp) 0.0
src/Data/Prizm/Color/CIE.hs view
@@ -1,3 +1,13 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color.CIE+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- Some basic utility functions for the CIE transformations.+---------------------------------------------------------------------------- module Data.Prizm.Color.CIE (   v1@@ -6,16 +16,17 @@ , transformXYZ ) where --- | exact rational of the "0.008856" value.+-- | Exact rational of the "0.008856" value. v1 :: Double v1 = (6/29) ** 3 --- | exact rational of the "7.787" value.+-- | Exact rational of the "7.787" value. v2 :: Double v2 = 1/3 * ((29/6) ** 2)  -- 2deg observer, d65 illuminant -- [x,y,z]+-- | Reference white, 2deg observer, d65 illuminant. refWhite :: [Double] refWhite = [95.047, 100.000, 108.883] 
src/Data/Prizm/Color/CIE/LAB.hs view
@@ -1,40 +1,64 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color.CIE.LAB+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- Transformation functions and convenience functions, some imported+-- from the other modules to ease conversion between representations.+---------------------------------------------------------------------------- module Data.Prizm.Color.CIE.LAB (-  toLCH-, toXYZ-, toRGB+-- * Transform to+-- ** RGB or Hex+  toRGB , toHex-, fromXYZ+-- ** CIE LCH or XYZ+, toLCH+, toXYZ++-- * Transform from+-- ** RGB or Hex+ , fromRGB , fromHex++-- ** CIE XYZ or LCH+, fromXYZ , fromLCH ) where -import Control.Applicative+import           Control.Applicative -import Data.Prizm.Types-import Data.Prizm.Color.CIE             (refWhite, transformXYZ)+import           Data.Prizm.Color.CIE     (refWhite, transformXYZ)+import           Data.Prizm.Types -import qualified Data.Prizm.Color.SRGB      as S-import qualified Data.Prizm.Color.CIE.XYZ   as X-import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LCH   as LC+import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LCH as LC+import qualified Data.Prizm.Color.CIE.XYZ as X+import qualified Data.Prizm.Color.SRGB    as S -transformLCH :: Double -> Double-transformLCH v | v > 0      = (v / pi) * 180-               | otherwise  = 360 - ((abs v) / pi) * 180+------------------------------------------------------------------------------+-- Transform to+------------------------------------------------------------------------------ --- | @toLCH@ convert a LAB color to the LCH representation.+-- | Convenience function to convert LAB to RGB.+toRGB :: CIELAB Double -> RGB Integer+toRGB = X.toRGB . toXYZ++-- | Convenience function to convert LAB to HEX.+toHex :: CIELAB Double -> Hex+toHex = X.toHex . toXYZ++-- | Convert a LAB color to the LCH representation. toLCH :: CIELAB Double -> CIELCH Double toLCH (CIELAB l a b) =     let h = transformLCH (atan2 b a)-        c = sqrt ((a^2) + (b^2))+        c = sqrt ((a^(2 :: Int)) + (b^(2 :: Int)))     in CIELCH l c h --- | @fromLCH@ convert a LCH color to the LAB representation.-fromLCH :: CIELCH Double -> CIELAB Double-fromLCH = LC.toLAB---- | @toXYZ@ convert a LAB color to the XYZ representation.+-- | Convert a LAB color to the XYZ representation. toXYZ :: CIELAB Double -> CIEXYZ Double toXYZ (CIELAB l a b) =     let y = (l + 16) / 116@@ -43,22 +67,26 @@         [nx,ny,nz] = getZipList $ ((*) <$> ZipList ((transformXYZ) <$> [x,y,z])) <*> ZipList refWhite     in CIEXYZ nx ny nz --- | @fromXYZ@ convert an XYZ color straight to LAB.-fromXYZ :: CIEXYZ Double -> CIELAB Double-fromXYZ = X.toLAB---- | @toRGB@ convenience function for converting straight to RGB.-toRGB :: CIELAB Double -> RGB Integer-toRGB = X.toRGB . toXYZ+------------------------------------------------------------------------------+-- Transform from+------------------------------------------------------------------------------ --- | @fromRGB@ convenience function for converting to LAB from RGB.+-- | Convenience function to convert RGB to LAB. fromRGB :: RGB Integer -> CIELAB Double fromRGB = X.toLAB . S.toXYZ --- | @toHex@ convenience function for converting straight to HEX.-toHex :: CIELAB Double -> Hex-toHex = X.toHex . toXYZ---- | @fromHex@ convenience function for converting to LAB from HEX.+-- | Convenience function to convert HEX to LAB. fromHex :: Hex -> CIELAB Double fromHex = X.toLAB . X.fromHex++-- | Convert an LCH color to the LAB representation.+fromLCH :: CIELCH Double -> CIELAB Double+fromLCH = LC.toLAB++-- | Convert an XYZ color to LAB.+fromXYZ :: CIEXYZ Double -> CIELAB Double+fromXYZ = X.toLAB++transformLCH :: Double -> Double+transformLCH v | v > 0      = (v / pi) * 180+               | otherwise  = 360 - ((abs v) / pi) * 180
src/Data/Prizm/Color/CIE/LCH.hs view
@@ -1,48 +1,79 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color.CIE.LCH+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- Transformation functions and convenience functions, some imported+-- from the other modules to ease conversion between representations.+---------------------------------------------------------------------------- module Data.Prizm.Color.CIE.LCH (+-- * Transform to+-- ** RGB or Hex+   toRGB+, toHex++-- ** CIE LAB or XYZ , toLAB , toXYZ-, toHex++-- * Transform from+-- ** RGB or Hex , fromRGB , fromHex++-- ** CIE LAB or XYZ , fromLAB , fromXYZ ) where -import Data.Prizm.Types+import           Data.Prizm.Types -import qualified Data.Prizm.Color.CIE.LAB as LB+import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LAB as LB import qualified Data.Prizm.Color.CIE.XYZ as X --- | @toLAB@ convert an LCH color to a LAB representation.+------------------------------------------------------------------------------+-- Transform to+------------------------------------------------------------------------------++-- | Convert from LCH to RGB.+toRGB :: CIELCH Double -> RGB Integer+toRGB = X.toRGB . toXYZ++-- | Convert from LCH to Hex.+toHex :: CIELCH Double -> Hex+toHex = LB.toHex . toLAB++-- | Convert an LCH color to LAB. toLAB :: CIELCH Double -> CIELAB Double toLAB (CIELCH l c h) =     let v = h * pi / 180     in CIELAB l ((cos v)*c) ((sin v)*c) --- | @fromLAB@ convenience function for converting from LAB to LCH.-fromLAB :: CIELAB Double -> CIELCH Double-fromLAB = LB.toLCH---- | @toXYZ@ convert from LCH to XYZ.+-- | Convert from LCH to XYZ. toXYZ :: CIELCH Double -> CIEXYZ Double toXYZ = LB.toXYZ . toLAB --- | @fromXYZ@ convert from XYZ to LCH.-fromXYZ :: CIEXYZ Double -> CIELCH Double-fromXYZ = X.toLCH---- | @toRGB@ convert from LCH to RGB.-toRGB :: CIELCH Double -> RGB Integer-toRGB = X.toRGB . toXYZ+------------------------------------------------------------------------------+-- Transform from+------------------------------------------------------------------------------ --- | @fromRGB@ convert from RGB to LCH.+-- | Convenience function to convert from RGB to LCH. fromRGB :: RGB Integer -> CIELCH Double fromRGB = fromLAB . LB.fromRGB -toHex :: CIELCH Double -> Hex-toHex = LB.toHex . toLAB-+-- | Convenience function to convert from Hex to LCH. fromHex :: Hex -> CIELCH Double fromHex = LB.toLCH . LB.fromHex++-- | Convenience function to convert from LAB to LCH.+fromLAB :: CIELAB Double -> CIELCH Double+fromLAB = LB.toLCH++-- | Convert from XYZ to LCH.+fromXYZ :: CIEXYZ Double -> CIELCH Double+fromXYZ = X.toLCH
src/Data/Prizm/Color/CIE/XYZ.hs view
@@ -1,67 +1,89 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color.CIE.XYZ+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- Transformation functions and convenience functions, some imported+-- from the other modules to ease conversion between representations.+---------------------------------------------------------------------------- module Data.Prizm.Color.CIE.XYZ (+-- * Transform to+-- ** RGB or Hex   toRGB , toRGBMatrix+, toHex++-- ** CIE LAB or LCH , toLAB , toLCH-, toHex++-- * Transform from+-- ** RGB or Hex , fromRGB , fromHex++-- ** CIE LAB or LCH , fromLAB , fromLCH ) where -import Control.Applicative+import           Control.Applicative -import Data.Prizm.Types+import           Data.Prizm.Types -import Data.Prizm.Color.Transform-import Data.Prizm.Color.Matrices.XYZ-import Data.Prizm.Color.CIE                 (v1, v2, refWhite)+import           Data.Prizm.Color.CIE          (refWhite, v1, v2)+import           Data.Prizm.Color.Matrices.XYZ+import           Data.Prizm.Color.Transform -import qualified Data.Prizm.Color.SRGB      as S-import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LAB   as LB-import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LCH   as LC+import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LAB      as LB+import {-# SOURCE #-} qualified Data.Prizm.Color.CIE.LCH      as LC+import qualified Data.Prizm.Color.SRGB         as S +------------------------------------------------------------------------------+-- Utilities+------------------------------------------------------------------------------ --- | @transformRGB@ transform an XYZ integer to be computed against--- the xyzToRGB matrix.+-- | Transform an XYZ integer to be computed against the xyzToRGB+-- matrix. transformRGB :: Double -> Integer transformRGB v | v > 0.0031308 = min (round ((1.055 * (v ** (1 / 2.4)) - 0.055) * 255)) 255                | otherwise     = min (round ((12.92 * v) * 255)) 255 +-- | Transform an LAB integer. transformLAB :: Double -> Double transformLAB v | v > v1    = v ** (1/3)                | otherwise = (v2 * v) + (16 / 116) --- | @toRGB@ convert a CIE color to an SRGB color.--- +------------------------------------------------------------------------------+-- Transform to+------------------------------------------------------------------------------++-- | Convert a CIE color to an SRGB color.+-- -- This function uses the default d65 illuminant matrix. toRGB :: CIEXYZ Double -> RGB Integer toRGB = (toRGBMatrix d65SRGB) --- | @toRGBMatrix@ convert an XYZ color to an SRGB color using a--- provided matrix.+-- | Convert an XYZ color to an SRGB color.+--+-- 'XYZtoRGB' is the pre-calculated illuminant matrix, it is+-- preferable to use 'toRG' as it uses the most "common" one. toRGBMatrix :: XYZtoRGB -> CIEXYZ Double -> RGB Integer toRGBMatrix (XYZtoRGB m) (CIEXYZ x y z) =     let t = ZipList ((/100) <$> [x,y,z])         [r,g,b] = (transformRGB) <$> ((zipTransform t) <$> m)     in (S.clamp) <$> RGB r g b --- | @fromRGB@ convenience function for converting to XYZ from RGB.-fromRGB :: RGB Integer -> CIEXYZ Double-fromRGB = S.toXYZ---- | @toHex@ convenience function for converting XYZ straight to HEX.+-- | Convenience function to convert XYZ to HEX. toHex :: CIEXYZ Double -> Hex toHex = S.toHex . toRGB --- | @fromHex@ convenience function for converting to XYZ from HEX.-fromHex :: Hex -> CIEXYZ Double-fromHex = S.toXYZ . S.fromHex---- | @toLAB@ convert an XYZ color to a LAB color.--- +-- | Convert an XYZ color to a LAB color.+-- -- This function uses the default reference white (2deg observer, d65 -- illuminant). toLAB :: CIEXYZ Double -> CIELAB Double@@ -73,13 +95,26 @@         b = 200 * (ty - tz)     in CIELAB l a b --- | @fromLAB@ convenience function for converting to XYZ from LAB.-fromLAB :: CIELAB Double -> CIEXYZ Double-fromLAB = LB.toXYZ---- | @toLCH@ convenience function for converting XYZ straight to LAB.+-- | Convenience function to convert XYZ to LAB. toLCH :: CIEXYZ Double -> CIELCH Double toLCH = LB.toLCH . toLAB +------------------------------------------------------------------------------+-- Transform from+------------------------------------------------------------------------------++-- | Convenience function to convert RGB to XYZ.+fromRGB :: RGB Integer -> CIEXYZ Double+fromRGB = S.toXYZ++-- | Convenience function to convert HEX to XYZ.+fromHex :: Hex -> CIEXYZ Double+fromHex = S.toXYZ . S.fromHex++-- | Convenience function to convert LAB to XYZ.+fromLAB :: CIELAB Double -> CIEXYZ Double+fromLAB = LB.toXYZ++-- | Convenience function to convert LCH to XYZ. fromLCH :: CIELCH Double -> CIEXYZ Double fromLCH = LC.toXYZ
src/Data/Prizm/Color/SRGB.hs view
@@ -1,26 +1,44 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Prizm.Color.SRGB+-- Copyright   :  (C) 2013 Parnell Springmeyer+-- License     :  BSD3+-- Maintainer  :  Parnell Springmeyer <parnell@ixmat.us>+-- Stability   :  stable+--+-- Transformation functions and convenience functions to do the base+-- conversion between S'RGB' and 'CIEXYZ'.+---------------------------------------------------------------------------- module Data.Prizm.Color.SRGB (+-- * Convert to CIEXYZ   toXYZ , toXYZMatrix++-- * Convert to Hex , toHex , fromHex , clamp ) where -import Numeric (showHex)+import           Numeric                       (showHex) -import Data.Monoid-import Data.Prizm.Types-import Data.Prizm.Color.Transform-import Data.Prizm.Color.Matrices.RGB+import           Data.Monoid+import           Data.Prizm.Color.Matrices.RGB+import           Data.Prizm.Color.Transform+import           Data.Prizm.Types -import Data.String-import qualified Data.Text as T-import Data.Text.Read as R+import           Data.String+import qualified Data.Text                     as T+import           Data.Text.Read                as R -import Control.Applicative+import           Control.Applicative --- | @rgbTransform@ transform an RGB integer to be computed against+------------------------------------------------------------------------------+-- Utilities+------------------------------------------------------------------------------++-- | Transform an RGB integer to be computed against -- a matrix. transform :: Integer -> Double transform v | dv > 0.04045 = (((dv + 0.055) / ap) ** 2.4) * 100@@ -28,13 +46,23 @@     where dv = fromIntegral v / 255           ap = 1.0 + 0.055 --- | @toHex@ convert an sRGB value to hexadecimal.-toHex :: RGB Integer -> Hex-toHex = showRGB+-- | Clamp an integer with an upper-bound of 255 (the maximum RGB+-- value).+clamp :: Integer -> Integer+clamp i = max (min i 255) 0 -fromHex :: Hex -> RGB Integer-fromHex = parse . fromString+-- All credit for the below three functions go to the HSColour module. +-- | Show a colour in hexadecimal form, e.g. \"#00aaff\"+showRGB :: RGB Integer -> Hex+showRGB c =+  (("#"++) . showHex2 r' . showHex2 g' . showHex2 b') ""+ where+  RGB r' g' b' = c+  showHex2 x | x <= 0xf = ("0"++) . showHex x+             | otherwise = showHex x++-- | Parse a 'Hex' into an 'RGB' type. parse :: T.Text -> RGB Integer parse t =   case T.uncons t of@@ -52,27 +80,38 @@     isHex a = (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F') || (a >= '0' && a <= '9')     err     = error "Invalid color string" --- | @toXYZ@ convert an sRGB value to a CIE XYZ value.+------------------------------------------------------------------------------+-- Convert to XYZ+------------------------------------------------------------------------------++-- | Convert an S'RGB' value to a 'CIEXYZ' value. toXYZ :: RGB Integer -> CIEXYZ Double toXYZ = (toXYZMatrix d65SRGB) +-- | Convert an S'RGB' value to a 'CIEXYZ' given a pre-calculated+-- illuminant matrix.+--+-- It is recommended to use 'toXYZ' as it uses the most common+-- illuminant matrix. toXYZMatrix :: RGBtoXYZ -> RGB Integer -> CIEXYZ Double toXYZMatrix (RGBtoXYZ m) (RGB r g b) =     let t = ZipList (transform <$> (clamp <$> [r,g,b]))         [x,y,z] = (roundN 3) <$> ((zipTransform t) <$> m)     in CIEXYZ x y z -clamp :: Integer -> Integer-clamp i = max (min i 255) 0+------------------------------------------------------------------------------+-- Convert to Hex+------------------------------------------------------------------------------ -{- All credit for the below three functions go to the HSColour-   module-}+-- | Convert an S'RGB' value to 'Hex'.+toHex :: RGB Integer -> Hex+toHex = showRGB --- |Show a colour in hexadecimal form, e.g. \"#00aaff\"-showRGB :: RGB Integer -> Hex-showRGB c =-  (("#"++) . showHex2 r' . showHex2 g' . showHex2 b') ""- where-  RGB r' g' b' = c-  showHex2 x | x <= 0xf = ("0"++) . showHex x-             | otherwise = showHex x+-- | Convert a 'Hex' to an S'RGB'.+fromHex :: Hex -> RGB Integer+fromHex = parse . fromString+++++
src/Data/Prizm/Color/Transform.hs view
@@ -2,13 +2,15 @@  module Data.Prizm.Color.Transform where -import Control.Applicative+import           Control.Applicative +-- | Round a number to the Nth place. roundN :: Integer -> Double -> Double roundN n num = (fromInteger $ round $ num * (10^n)) / (10.0^^n) +-- | Truncate a number to the Nth place. truncateN :: Integer -> Double -> Double-truncateN n num = (fromInteger $ truncate $ num * (10^n)) / (10.0^^n)+truncateN = roundN  zipTransform :: ZipList Double -> [Double] -> Double zipTransform tv m = sum $ getZipList $ (*) <$> ZipList m <*> tv
src/Data/Prizm/Types.hs view
@@ -1,10 +1,14 @@ module Data.Prizm.Types where -import Control.Applicative+import           Control.Applicative +-- | Working space matrix to convert from sRGB to CIE XYZ newtype RGBtoXYZ = RGBtoXYZ [[Double]] deriving (Eq, Ord, Show)++-- | Working space matrix to convert from CIE XYZ to sRGB newtype XYZtoRGB = XYZtoRGB [[Double]] deriving (Eq, Ord, Show) +-- | Hex format color code, eg '#AB9D92' type Hex = String  type Percent = Integer@@ -22,6 +26,7 @@     deriving (Eq, Ord, Show)  -- | Functor instances+ instance Functor RGB where     fmap f (RGB r g b) = (RGB (f r) (f g) (f b)) 
+ tests/QC/CIE.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module QC.CIE (tests) where++import           Test.Framework                       (Test)+import           Test.Framework.Providers.QuickCheck2 (testProperty)+import           Test.QuickCheck++import           Control.Applicative+import           Control.Monad++import           Data.Prizm.Color.CIE.LAB             as LB+import           Data.Prizm.Color.CIE.LCH             as LC+import           Data.Prizm.Color.CIE.XYZ             as X+import           Data.Prizm.Color.Transform+import           Data.Prizm.Types++instance Arbitrary (CIEXYZ Double) where+    arbitrary = liftM3 CIEXYZ (choose (0, 95.047)) (choose (0, 100.000)) (choose (0, 108.883))++instance Arbitrary (CIELAB Double) where+    arbitrary = liftM3 CIELAB (choose (0, 100)) (choose ((-129), 129)) (choose ((-129), 129))++rN :: Double -> Double+rN = roundN 11++-- | This really needs applicatives here - I need to redefine the+-- types so that I can fmap functions over the color values.+--+-- This QuickCheck test guarantees a lossless conversion between CIE+-- XYZ and CIE L*a*b* at a precision of 11 decimal places.+xyz2LAB :: CIEXYZ Double -> Bool+xyz2LAB v =+    let nv = rN <$> v+    in (rN <$> LB.toXYZ(X.toLAB nv)) == nv++lab2XYZ :: CIELAB Double -> Bool+lab2XYZ v =+    let nv = rN <$> v+    in (rN <$> X.toLAB(LB.toXYZ nv)) == nv++lab2LCH :: CIELAB Double -> Bool+lab2LCH v =+    let nv = rN <$> v+    in (rN <$> LC.toLAB(LB.toLCH nv)) == nv++tests :: [Test]+tests = [+    testProperty "CIE XYZ <-> CIE L*a*b*" xyz2LAB,+    testProperty "CIE L*ab <-> CIE XYZ" lab2XYZ,+    testProperty "CIE L*ab <-> CIE L*Ch" lab2LCH+      ]