packages feed

colour 2.0.0 → 2.1.0

raw patch · 14 files changed

+494/−176 lines, 14 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Colour: instance (Fractional a) => Show (AlphaColour a)
+ Data.Colour: instance (Fractional a) => Show (Colour a)
+ Data.Colour: instance (Fractional a, Read a) => Read (AlphaColour a)
+ Data.Colour: instance (Fractional a, Read a) => Read (Colour a)
+ Data.Colour.CIE: chromaColour :: (Fractional a) => Chromaticity a -> a -> Colour a
+ Data.Colour.CIE: chromaConvert :: (Fractional b, Real a) => Chromaticity a -> Chromaticity b
+ Data.Colour.CIE: chromaCoords :: (Fractional a) => Chromaticity a -> (a, a, a)
+ Data.Colour.CIE: chromaX :: (Fractional a) => Chromaticity a -> a
+ Data.Colour.CIE: chromaY :: (Fractional a) => Chromaticity a -> a
+ Data.Colour.CIE: chromaZ :: (Fractional a) => Chromaticity a -> a
+ Data.Colour.CIE: cieXYZ :: (Fractional a) => a -> a -> a -> Colour a
+ Data.Colour.CIE: data Chromaticity a
+ Data.Colour.CIE: data Colour a
+ Data.Colour.CIE: instance AffineSpace Chromaticity
+ Data.Colour.CIE: luminance :: (Fractional a) => Colour a -> a
+ Data.Colour.CIE: mkChromaticity :: (Fractional a) => a -> a -> Chromaticity a
+ Data.Colour.CIE: toCIEXYZ :: (Fractional a) => Colour a -> (a, a, a)
+ Data.Colour.CIE.Illuminant: a :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: b :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: c :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: d50 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: d55 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: d65 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: d75 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: e :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f1 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f10 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f11 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f12 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f2 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f3 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f4 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f5 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f6 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f7 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f8 :: (Fractional a) => Chromaticity a
+ Data.Colour.CIE.Illuminant: f9 :: (Fractional a) => Chromaticity a
+ Data.Colour.RGBSpace: TransferFunction :: (a -> a) -> (a -> a) -> a -> TransferFunction a
+ Data.Colour.RGBSpace: data Colour a
+ Data.Colour.RGBSpace: data RGBGamut
+ Data.Colour.RGBSpace: data RGBSpace a
+ Data.Colour.RGBSpace: data TransferFunction a
+ Data.Colour.RGBSpace: gamut :: RGBSpace a -> RGBGamut
+ Data.Colour.RGBSpace: inGamut :: (Ord a, Fractional a) => RGBGamut -> Colour a -> Bool
+ Data.Colour.RGBSpace: instance (Num a) => Monoid (TransferFunction a)
+ Data.Colour.RGBSpace: inverseTransferFunction :: (Fractional a) => TransferFunction a -> TransferFunction a
+ Data.Colour.RGBSpace: linearRGBSpace :: (Num a) => RGBGamut -> RGBSpace a
+ Data.Colour.RGBSpace: linearTransferFunction :: (Num a) => TransferFunction a
+ Data.Colour.RGBSpace: mkRGBGamut :: RGB (Chromaticity Rational) -> Chromaticity Rational -> RGBGamut
+ Data.Colour.RGBSpace: mkRGBSpace :: RGBGamut -> TransferFunction a -> RGBSpace a
+ Data.Colour.RGBSpace: powerTransferFunction :: (Floating a) => a -> TransferFunction a
+ Data.Colour.RGBSpace: primaries :: RGBGamut -> (RGB (Chromaticity Rational))
+ Data.Colour.RGBSpace: rgbUsingSpace :: (Fractional a) => RGBSpace a -> a -> a -> a -> Colour a
+ Data.Colour.RGBSpace: toRGBUsingSpace :: (Fractional a) => RGBSpace a -> Colour a -> RGB a
+ Data.Colour.RGBSpace: transfer :: TransferFunction a -> a -> a
+ Data.Colour.RGBSpace: transferFunction :: RGBSpace a -> TransferFunction a
+ Data.Colour.RGBSpace: transferGamma :: TransferFunction a -> a
+ Data.Colour.RGBSpace: transferInverse :: TransferFunction a -> a -> a
+ Data.Colour.RGBSpace: whitePoint :: RGBGamut -> (Chromaticity Rational)
+ Data.Colour.SRGB: RGB :: !a -> !a -> !a -> RGB a
+ Data.Colour.SRGB: channelBlue :: RGB a -> !a
+ Data.Colour.SRGB: channelGreen :: RGB a -> !a
+ Data.Colour.SRGB: channelRed :: RGB a -> !a
+ Data.Colour.SRGB: data Colour a
+ Data.Colour.SRGB: data RGB a
+ Data.Colour.SRGB: sRGBSpace :: (Ord a, Floating a) => RGBSpace a
+ Data.Colour.SRGB.Linear: RGB :: !a -> !a -> !a -> RGB a
+ Data.Colour.SRGB.Linear: channelBlue :: RGB a -> !a
+ Data.Colour.SRGB.Linear: channelGreen :: RGB a -> !a
+ Data.Colour.SRGB.Linear: channelRed :: RGB a -> !a
+ Data.Colour.SRGB.Linear: data Colour a
+ Data.Colour.SRGB.Linear: data RGB a
+ Data.Colour.SRGB.Linear: sRGBGamut :: RGBGamut

Files

Data/Colour.hs view
@@ -25,6 +25,25 @@ -- The most common way of creating colours is either by name -- (see "Data.Colour.Names") or by giving an sRGB triple  -- (see "Data.Colour.SRGB").+--+-- Methods of specifying Colours can be found in +--+-- - "Data.Colour.SRGB"+--+-- - "Data.Colour.SRGB.Linear"+--+-- - "Data.Colour.CIE"+--+-- Colours can be specified in a generic 'Data.Colour.RGBSpace.RGBSpace'+-- by using+--+-- - "Data.Colour.RGBSpace"+++--TODO+-- - "Data.Colour.HDTV"+--+-- - "Data.Colour.SDTV" module Data.Colour  ( -- *Colour type   Colour@@ -45,4 +64,53 @@  ) where +import Data.Char import Data.Colour.Internal+import qualified Data.Colour.SRGB.Linear+import Data.Colour.CIE.Chromaticity (app_prec, infix_prec)++instance (Fractional a) => Show (Colour a) where+  showsPrec d c = showParen (d > app_prec) showStr+   where+    showStr = showString linearConstructorQualifiedName+            . showString " " . (showsPrec (app_prec+1) r)+            . showString " " . (showsPrec (app_prec+1) g)+            . showString " " . (showsPrec (app_prec+1) b)+    Data.Colour.SRGB.Linear.RGB r g b = Data.Colour.SRGB.Linear.toRGB c++instance (Fractional a, Read a) => Read (Colour a) where+  readsPrec d r = readParen (d > app_prec)+                  (\r -> [(Data.Colour.SRGB.Linear.rgb r0 g0 b0,t)+                         |(name,s) <- mylex r+                         ,name `elem` [linearConstructorName+                                      ,linearConstructorQualifiedName]+                         ,(r0,s0) <- readsPrec (app_prec+1) s+                         ,(g0,s1) <- readsPrec (app_prec+1) s0+                         ,(b0,t)  <- readsPrec (app_prec+1) s1]) r+   where+    mylex = return +          . span (\c -> isAlphaNum c || c `elem` "._'")+          . dropWhile isSpace++linearConstructorQualifiedName = "Data.Colour.SRGB.Linear.rgb"+linearConstructorName = "rgb"++instance (Fractional a) => Show (AlphaColour a) where+  showsPrec d ac | a == 0 = showString "transparent"+                 | otherwise = showParen (d > infix_prec) showStr+   where+    showStr = showsPrec (infix_prec+1) c+            . showString " `withOpacity` "+            . showsPrec (infix_prec+1) a+    a = alphaChannel ac+    c = colourChannel ac++instance (Fractional a, Read a) => Read (AlphaColour a) where+  readsPrec d r = [(transparent,s)|("transparent",s) <- lex r]+               ++ readParen (d > infix_prec)+                  (\r -> [(c `withOpacity` o,s)+                         |(c,r0) <- readsPrec (infix_prec+1) r+                         ,("`",r1) <- lex r0+                         ,("withOpacity",r2) <- lex r1+                         ,("`",r3) <- lex r2+                         ,(o,s)  <- readsPrec (infix_prec+1) r3]) r
+ Data/Colour/CIE.hs view
@@ -0,0 +1,133 @@+{-+Copyright (c) 2008+Russell O'Connor++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.+-}+-- |Colour operations defined by the International Commission on +-- Illumination (CIE).+module Data.Colour.CIE+ (Colour+ ,cieXYZ, toCIEXYZ, luminance++ ,Chromaticity+ ,mkChromaticity, chromaCoords+ ,chromaX, chromaY, chromaZ+ ,chromaConvert+ ,chromaColour++ --,lightness, cieLab, cieLuv+ )+where++import Data.List+import Data.Colour+import Data.Colour.RGB+import Data.Colour.SRGB.Linear+import Data.Colour.CIE.Chromaticity+import Data.Colour.Matrix++-- |Construct a 'Colour' from XYZ coordinates for the 2&#176; standard+-- (colourimetric) observer.+cieXYZ :: (Fractional a) => a -> a -> a -> Colour a+cieXYZ x y z = rgb r g b+ where+  [r,g,b] = mult matrix [x,y,z]+  matrix = map (map fromRational) xyz2rgb709++-- |Return the XYZ colour coordinates for the 2&#176; standard+-- (colourimetric) observer.+toCIEXYZ :: (Fractional a) => Colour a -> (a,a,a)+toCIEXYZ c = (x,y,z)+ where+  RGB r g b = toRGB c+  [x,y,z] = mult matrix [r,g,b]+  matrix = map (map fromRational) rgb7092xyz++{- CIE luminance -}+-- |Returns the Y colour coordinate (luminance) for the 2&#176; standard+-- (colourimetric) observer.+luminance :: (Fractional a) => Colour a -> a+luminance c = y+ where+  (x,y,z) = toCIEXYZ c++instance AffineSpace Chromaticity where+ affineCombo l z =+   foldl1' chromaAdd [chromaScale w a | (w,a) <- (1-total,z):l]+  where+   total = sum $ map fst l+   (Chroma x0 y0) `chromaAdd` (Chroma x1 y1) = Chroma (x0+x1) (y0+y1)+   s `chromaScale` (Chroma x y) = Chroma (s*x) (s*y)++-- |Constructs a colour from the given 'Chromaticity' and 'luminance'.+chromaColour :: (Fractional a) =>+                Chromaticity a+             -> a              -- ^ 'luminance'+             -> Colour a+chromaColour ch y = cieXYZ (s*ch_x) y (s*ch_z)+ where+  (ch_x, ch_y, ch_z) = chromaCoords ch+  s = y/ch_y++-- |Returns the lightness of a colour, which is a perceptually uniform+-- measure.+lightness :: (Ord a, Floating a) => Colour a -> a+lightness c | (6/29)^3 < y = 116*y**(1/3) - 16+            | otherwise = (29/3)^3*y+ where+  y = luminance c++-- |Returns the CIELAB coordinates of a colour, which is a+-- perceptually uniform colour space.+-- If you don't know what white point to use, use+-- 'Data.Colour.CIE.Illuminant.d65'.+cieLab :: (Ord a, Floating a) => Chromaticity a -- ^White point+                              -> Colour a -> (a,a,a)+cieLab white_ch c = (lightness c, a, b)+ where+  white = chromaColour white_ch 1.0+  (x,y,z) = toCIEXYZ c+  (xn,yn,zn) = toCIEXYZ white+  a = 500*((x/xn)**(1/3) - (y/yn)**(1/3))+  b = 200*((y/yn)**(1/3) - (z/zn)**(1/3))++-- |Returns the CIELUV coordinates of a colour, which is a+-- perceptually uniform colour space.+-- If you don't know what white point to use, use+-- 'Data.Colour.CIE.Illuminant.d65'.+cieLuv :: (Ord a, Floating a) => Chromaticity a -- ^White point+                              -> Colour a -> (a,a,a)+cieLuv white_ch c = (l, 13*l*(u'-un'), 13*l*(v'-vn'))+ where+  white = chromaColour white_ch 1.0+  (u', v') = u'v' c+  (un', vn') = u'v' white+  l = lightness c+--------------------------------------------------------------------------+{- not for export -}+u'v' :: (Ord a, Floating a) => Colour a -> (a,a)+u'v' c = (4*x/(x+15*y+3*z), 9*y/(x+15*y+3*z))+ where+  (x,y,z) = toCIEXYZ c++rgb7092xyz = (rgb2xyz sRGBGamut)++xyz2rgb709 = inverse rgb7092xyz+
Data/Colour/CIE/Chromaticity.hs view
@@ -24,27 +24,46 @@  data Chromaticity a = Chroma !a !a deriving (Eq) +-- |Constructs 'Chromaticity' from the CIE little /x/, little /y/+-- coordinates for the 2&#176; standard (colourimetric) observer.+mkChromaticity :: (Fractional a) => a -> a -> Chromaticity a+mkChromaticity = Chroma+ -- |Returns the CIE little /x/, little /y/, little /z/ coordinates -- for the 2&#176; standard (colourimetric) observer.-chroma_coords :: (Fractional a) => Chromaticity a -> (a, a, a)-chroma_coords (Chroma x y) = (x, y, 1 - x - y)+chromaCoords :: (Fractional a) => Chromaticity a -> (a, a, a)+chromaCoords (Chroma x y) = (x, y, 1 - x - y) --- |Constructs 'Chromaticity' from the CIE little /x/, little /y/--- coordinates for the 2&#176; standard (colourimetric) observer.-cieChroma :: (Fractional a) => a -> a -> Chromaticity a-cieChroma = Chroma+-- |Returns the CIE little /x/ coordinate+-- for the 2&#176; standard (colourimetric) observer.+chromaX :: (Fractional a) => Chromaticity a -> a+chromaX (Chroma x _y) = x +-- |Returns the CIE little /y/ coordinate+-- for the 2&#176; standard (colourimetric) observer.+chromaY :: (Fractional a) => Chromaticity a -> a+chromaY (Chroma _x y) = y++-- |Returns the CIE little /z/ coordinate+-- for the 2&#176; standard (colourimetric) observer.+chromaZ :: (Fractional a) => Chromaticity a -> a+chromaZ (Chroma x y) = 1 - x - y++-- |Change the type used to represent the chromaticity coordinates.+chromaConvert :: (Fractional b, Real a) => Chromaticity a -> Chromaticity b+chromaConvert (Chroma x y) = Chroma (realToFrac x) (realToFrac y)+ instance (Fractional a) => Show (Chromaticity a) where   showsPrec d c = showParen (d > app_prec) showStr    where-    showStr = showString "cieChroma " . (showsPrec (app_prec+1) x)+    showStr = showString "mkChromaticity " . (showsPrec (app_prec+1) x)             . showString " "          . (showsPrec (app_prec+1) y)-    (x,y,z) = chroma_coords c+    (x,y,z) = chromaCoords c  instance (Fractional a, Read a) => Read (Chromaticity a) where   readsPrec d r = readParen (d > app_prec)-                  (\r -> [(cieChroma x y,t)-                         |("cieChroma",s) <- lex r+                  (\r -> [(mkChromaticity x y,t)+                         |("mkChromaticity",s) <- lex r                          ,(x,s0) <- readsPrec (app_prec+1) s                          ,(y,t) <- readsPrec (app_prec+1) s0]) r 
Data/Colour/CIE/Illuminant.hs view
@@ -28,80 +28,80 @@  -- |Incandescent \/ Tungsten a   :: (Fractional a) => Chromaticity a-a   = cieChroma 0.44757 0.40745 +a   = mkChromaticity 0.44757 0.40745   -- |{obsolete} Direct sunlight at noon b   :: (Fractional a) => Chromaticity a-b   = cieChroma 0.34842 0.35161+b   = mkChromaticity 0.34842 0.35161  -- |{obsolete} Average \/ North sky Daylight c   :: (Fractional a) => Chromaticity a-c   = cieChroma 0.31006 0.31616+c   = mkChromaticity 0.31006 0.31616  -- |Horizon Light. ICC profile PCS d50 :: (Fractional a) => Chromaticity a-d50 = cieChroma 0.34567 0.35850+d50 = mkChromaticity 0.34567 0.35850  -- |Mid-morning \/ Mid-afternoon Daylight d55 :: (Fractional a) => Chromaticity a-d55 = cieChroma 0.33242 0.34743+d55 = mkChromaticity 0.33242 0.34743  -- |Noon Daylight: Television, sRGB color space d65 :: (Fractional a) => Chromaticity a-d65 = cieChroma 0.31271 0.32902+d65 = mkChromaticity 0.31271 0.32902  -- |North sky Daylight d75 :: (Fractional a) => Chromaticity a-d75 = cieChroma 0.29902 0.31485+d75 = mkChromaticity 0.29902 0.31485  -- |Equal energy e   :: (Fractional a) => Chromaticity a-e   = cieChroma (1/3)   (1/3)+e   = mkChromaticity (1/3)   (1/3)  -- |Daylight Fluorescent f1  :: (Fractional a) => Chromaticity a-f1  = cieChroma 0.31310 0.33727+f1  = mkChromaticity 0.31310 0.33727  -- |Cool White Fluorescent f2  :: (Fractional a) => Chromaticity a-f2  = cieChroma 0.37208 0.37529+f2  = mkChromaticity 0.37208 0.37529  -- |White Fluorescent f3  :: (Fractional a) => Chromaticity a-f3  = cieChroma 0.40910 0.39430+f3  = mkChromaticity 0.40910 0.39430  -- |Warm White Fluorescent f4  :: (Fractional a) => Chromaticity a-f4  = cieChroma 0.44018 0.40329+f4  = mkChromaticity 0.44018 0.40329  -- |Daylight Fluorescent f5  :: (Fractional a) => Chromaticity a-f5  = cieChroma 0.31379 0.34531+f5  = mkChromaticity 0.31379 0.34531  -- |Lite White Fluorescent f6  :: (Fractional a) => Chromaticity a-f6  = cieChroma 0.37790 0.38835+f6  = mkChromaticity 0.37790 0.38835  -- |D65 simulator, Daylight simulator f7  :: (Fractional a) => Chromaticity a-f7  = cieChroma 0.31292 0.32933+f7  = mkChromaticity 0.31292 0.32933  -- |D50 simulator, Sylvania F40 Design 50 f8  :: (Fractional a) => Chromaticity a-f8  = cieChroma 0.34588 0.35875+f8  = mkChromaticity 0.34588 0.35875  -- |Cool White Deluxe Fluorescent f9  :: (Fractional a) => Chromaticity a-f9  = cieChroma 0.37417 0.37281+f9  = mkChromaticity 0.37417 0.37281  -- |Philips TL85, Ultralume 50 f10 :: (Fractional a) => Chromaticity a-f10 = cieChroma 0.34609 0.35986+f10 = mkChromaticity 0.34609 0.35986  -- |Philips TL84, Ultralume 40 f11 :: (Fractional a) => Chromaticity a-f11 = cieChroma 0.38052 0.37713+f11 = mkChromaticity 0.38052 0.37713  -- |Philips TL83, Ultralume 30 f12 :: (Fractional a) => Chromaticity a-f12 = cieChroma 0.43695 0.40441+f12 = mkChromaticity 0.43695 0.40441
Data/Colour/Chan.hs view
@@ -24,7 +24,7 @@ {- For internal use only:    Not to be exported from the package -} -import qualified Data.List+import qualified Data.List (sum)  newtype Chan p a = Chan a deriving (Eq) 
Data/Colour/Internal.hs view
@@ -23,10 +23,6 @@ module Data.Colour.Internal where  import Data.List-import qualified Data.Colour.RGB-import Data.Colour.RGB (RGBSpace(..))-import Data.Colour.CIE.Chromaticity-import Data.Colour.CIE.Illuminant import qualified Data.Colour.Chan as Chan import Data.Colour.Chan (Chan(Chan)) import Data.Monoid@@ -47,16 +43,6 @@ data Colour a = RGB !(Chan Red a) !(Chan Green a) !(Chan Blue a)                  deriving (Eq) --- |Constructs a 'Colour' from RGB values using the /linear/ RGB colour--- space specified in Rec.709.-rgb709 :: (Fractional a) => a -> a -> a -> Colour a-rgb709 r g b = RGB (Chan r) (Chan g) (Chan b)---- |Return RGB values using the /linear/ RGB colour space specified in--- Rec.709.-toRGB709 :: (Fractional a) => Colour a -> Data.Colour.RGB.RGB a-toRGB709 (RGB (Chan r) (Chan g) (Chan b)) = Data.Colour.RGB.RGB r g b- -- |Change the type used to represent the colour coordinates. colourConvert :: (Fractional b, Real a) => Colour a -> Colour b colourConvert (RGB r g b) =@@ -206,12 +192,15 @@ alphaChannel :: AlphaColour a -> a alphaChannel (RGBA _ (Chan a)) = a -rgb709Space :: Fractional a => RGBSpace a-rgb709Space = RGBSpace (Data.Colour.RGB.RGB-                        (cieChroma 0.64 0.33)-                        (cieChroma 0.30 0.60)-                        (cieChroma 0.15 0.06))-                       d65+-- |Returns the colour of an 'AlphaColour'.+-- @colourChannel transparent@ is undefined and may result in @nan@ or an+-- error.+-- Its use is discouraged.+-- If you are desperate, use+--+-- >darken (recip (alphaChannel c)) (c `over` black)+colourChannel :: (Fractional a) => AlphaColour a -> Colour a+colourChannel (RGBA c (Chan a)) = darken (recip a) c  -------------------------------------------------------------------------- -- not for export
Data/Colour/Names.hs view
@@ -32,7 +32,6 @@  import Prelude hiding (tan) import Data.Colour.SRGB-import Data.Colour  readColourName :: (Monad m, Ord a, Floating a) => String -> m (Colour a) readColourName "aliceblue" = return aliceblue
Data/Colour/RGB.hs view
@@ -43,11 +43,35 @@ curryRGB :: (RGB a -> b) -> a -> a -> a -> b curryRGB f r g b = f (RGB r g b) --- Should a always be Rational?-data RGBSpace a = RGBSpace {primaries :: !(RGB (Chromaticity a))-                           ,whitePoint   :: !(Chromaticity a)-                           } deriving (Eq, Read, Show)+-- |An 'RGBGamut' is a 3-D colour &#8220;cube&#8221; that contains all the+-- colours that can be displayed by a RGB device.+-- The &#8220;cube&#8221; is normalized so that white has+-- 'Data.Colour.CIE.luminance' 1.+data RGBGamut = RGBGamut {primaries :: !(RGB (Chromaticity Rational))+                         ,whitePoint :: !(Chromaticity Rational)+                         } deriving (Eq) +instance Show RGBGamut where+  showsPrec d gamut = showParen (d > app_prec) showStr+   where+    showStr = showString "mkRGBGamut"+            . showString " " . (showsPrec (app_prec+1) (primaries gamut))+            . showString " " . (showsPrec (app_prec+1) (whitePoint gamut))++instance Read RGBGamut where+  readsPrec d r = readParen (d > app_prec)+                  (\r -> [(mkRGBGamut p w,t)+                         |("mkRGBGamut",s) <- lex r+                         ,(p,s0) <- readsPrec (app_prec+1) s+                         ,(w,t)  <- readsPrec (app_prec+1) s0]) r++-- |An RGB gamut is specified by three primary colours (red, green, and +-- blue) and a white point (often 'Data.Colour.CIE.Illuminant.d65').+mkRGBGamut :: RGB (Chromaticity Rational) -- ^ The three primaries+           -> Chromaticity Rational       -- ^ The white point+           -> RGBGamut+mkRGBGamut = RGBGamut+ {- not for export -}  primaryMatrix :: (Fractional a) => (RGB (Chromaticity a)) -> [[a]]@@ -58,16 +82,15 @@  where   RGB (xr, yr, zr)       (xg, yg, zg)-      (xb, yb, zb) = fmap chroma_coords p+      (xb, yb, zb) = fmap chromaCoords p -rgb2xyz :: (Fractional a) => RGBSpace a -> [[a]]+rgb2xyz :: RGBGamut -> [[Rational]] rgb2xyz space =   transpose (zipWith (map . (*)) as (transpose matrix))  where-  (xn, yn, zn) = chroma_coords (whitePoint space)+  (xn, yn, zn) = chromaCoords (whitePoint space)   matrix = primaryMatrix (primaries space)   as = mult (inverse matrix) [xn/yn, 1, zn/yn] -xyz2rgb :: (Fractional a) => RGBSpace a -> [[a]]+xyz2rgb :: RGBGamut -> [[Rational]] xyz2rgb = inverse . rgb2xyz-
Data/Colour/RGBSpace.hs view
@@ -20,28 +20,127 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -}+-- |An 'RGBSpace' is characterized by 'Chromaticity' for red, green, and+-- blue, the 'Chromaticity' of the white point, and it's+-- 'TransferFunction'. module Data.Colour.RGBSpace- (RGB(..)+ (Colour+  -- *RGB Tuple+ ,RGB(..)  ,uncurryRGB, curryRGB++ -- *RGB Gamut+ ,RGBGamut+ ,mkRGBGamut, primaries, whitePoint+ ,inGamut+ -- *RGB Space+ ,TransferFunction(..)+ ,linearTransferFunction, powerTransferFunction+ ,inverseTransferFunction++ ,RGBSpace()+ ,mkRGBSpace ,gamut, transferFunction+ ,linearRGBSpace+ ,rgbUsingSpace+ ,toRGBUsingSpace  ) where -import Data.Colour+import Data.Monoid import Data.Colour.CIE.Chromaticity-import Data.Colour.Internal (rgb709, toRGB709, rgb709Space) import Data.Colour.Matrix import Data.Colour.RGB+import Data.Colour.SRGB.Linear -rgbSpace :: (Fractional a) => RGBSpace a -> a -> a -> a -> Colour a-rgbSpace space r g b = rgb709 r0 g0 b0+-- |Returns 'True' if the given colour lies inside the given gamut.+inGamut :: (Ord a, Fractional a) => RGBGamut -> Colour a -> Bool+inGamut gamut c = r && g && b  where-  matrix = matrixMult (xyz2rgb rgb709Space) (rgb2xyz space)+  test x = 0 <= x && x <= 1+  RGB r g b = fmap test (toRGBUsingGamut gamut c)++rtf :: (Fractional b, Real a) => [[a]] -> [[b]]+rtf = map (map realToFrac)++rgbUsingGamut :: (Fractional a) => RGBGamut -> a -> a -> a -> Colour a+rgbUsingGamut gamut r g b = rgb r0 g0 b0+ where+  matrix = rtf $ matrixMult (xyz2rgb sRGBGamut) (rgb2xyz gamut)   [r0,g0,b0] = mult matrix [r,g,b] -toRGBSpace :: (Fractional a) => RGBSpace a -> Colour a -> RGB a-toRGBSpace space c = RGB r g b+toRGBUsingGamut :: (Fractional a) => RGBGamut -> Colour a -> RGB a+toRGBUsingGamut gamut c = RGB r g b  where-  RGB r0 g0 b0 = toRGB709 c-  matrix = matrixMult (xyz2rgb space) (rgb2xyz rgb709Space)+  RGB r0 g0 b0 = toRGB c+  matrix = rtf $ matrixMult (xyz2rgb gamut) (rgb2xyz sRGBGamut)   [r,g,b] = mult matrix [r0,g0,b0] +-- |A 'transfer' function is a function that typically translates linear+-- colour space coordinates into non-linear coordinates.+-- The 'transferInverse' function reverses this by translating non-linear+-- colour space coordinates into linear coordinates.+-- It is required that+--+-- > transfer . transferInverse === id === transferInverse . inverse+--+-- (or that this law holds up to floating point rounding errors).+--+-- We also require that 'transfer' is approximately @(**transferGamma)@+-- (and hence 'transferInverse' is approximately+-- @(**(recip transferGamma))@).+-- The value 'transferGamma' is for informational purposes only, so there+-- is no bound on how good this approximation needs to be.+data TransferFunction a = TransferFunction+                          { transfer :: a -> a+                          , transferInverse :: a -> a+                          , transferGamma :: a }++-- |This is the identity 'TransferFunction'.+linearTransferFunction :: (Num a) => TransferFunction a+linearTransferFunction = TransferFunction id id 1++-- |This is the @(**gamma)@ 'TransferFunction'.+powerTransferFunction :: (Floating a) => a -> TransferFunction a+powerTransferFunction gamma =+  TransferFunction (**gamma) (**(recip gamma)) gamma++-- |This reverses a 'TransferFunction'.+inverseTransferFunction :: (Fractional a) => TransferFunction a -> TransferFunction a+inverseTransferFunction (TransferFunction for rev g) =+  TransferFunction rev for (recip g)++instance (Num a) => Monoid (TransferFunction a) where+ mempty = linearTransferFunction+ (TransferFunction f0 f1 f) `mappend` (TransferFunction g0 g1 g) =+   (TransferFunction (f0 . g0) (g1 . f1) (f*g))++-- |An 'RGBSpace' is a colour coordinate system for colours laying+-- 'inGamut' of 'gamut'.+-- Linear coordinates are passed through a 'transferFunction' to+-- produce non-linear 'RGB' values.+data RGBSpace a = RGBSpace { gamut :: RGBGamut,+                             transferFunction :: TransferFunction a }++-- |An RGBSpace is specified by an 'RGBGamut' and a 'TransferFunction'.+mkRGBSpace :: RGBGamut+           -> TransferFunction a+           -> RGBSpace a+mkRGBSpace = RGBSpace++-- |Produce a linear colour space from an 'RGBGamut'.+linearRGBSpace :: (Num a) => RGBGamut -> RGBSpace a+linearRGBSpace gamut = RGBSpace gamut mempty++-- |Create a 'Colour' from red, green, and blue coordinates given in a+-- general 'RGBSpace'.+rgbUsingSpace :: (Fractional a) => RGBSpace a -> a -> a -> a -> Colour a+rgbUsingSpace space = +  curryRGB (uncurryRGB (rgbUsingGamut (gamut space)) . fmap tinv)+ where+  tinv = transferInverse (transferFunction space)++-- |Return the coordinates of a given 'Colour' for a general 'RGBSpace'.+toRGBUsingSpace :: (Fractional a) => RGBSpace a -> Colour a -> RGB a+toRGBUsingSpace space c = fmap t (toRGBUsingGamut (gamut space) c)+ where+  t = transfer (transferFunction space)
Data/Colour/SRGB.hs view
@@ -22,23 +22,25 @@ -} -- |Specifies 'Colour's in accordance with the sRGB standard. module Data.Colour.SRGB- (sRGB24, sRGBBounded, sRGB+ (Colour, RGB(..)+ ,sRGB24, sRGBBounded, sRGB  ,toSRGB24, toSRGBBounded, toSRGB   ,sRGB24shows, sRGB24show  ,sRGB24reads, sRGB24read-  --,transferFunction, invTransferFunction -- should these be exported?++ ,sRGBSpace  ) where  import Data.Word import Numeric-import Data.Colour-import Data.Colour.Internal (rgb709, toRGB709, quantize)-import Data.Colour.RGBSpace+import Data.Colour.Internal (quantize)+import Data.Colour.SRGB.Linear+import Data.Colour.RGBSpace hiding (transferFunction)  {- Non-linear colour space -}-{- the sRGB transfer function approximates a gamma of about 2.2 -}+{- the sRGB transfer function approximates a gamma of about 1/2.2 -} transferFunction lin | lin == 1         = 1                      | lin <= 0.0031308 = 12.92*lin                      | otherwise        = (1 + a)*lin**(1/2.4) - a@@ -55,7 +57,7 @@ -- |Construct a colour from an sRGB specification. -- Input components are expected to be in the range [0..1]. sRGB :: (Ord b, Floating b) =>  b -> b -> b -> Colour b-sRGB = curryRGB (uncurryRGB rgb709 . fmap invTransferFunction)+sRGB = curryRGB (uncurryRGB rgb . fmap invTransferFunction)  -- |Construct a colour from an sRGB specification. -- Input components are expected to be in the range [0..'maxBound'].@@ -73,7 +75,7 @@  -- |Return the sRGB colour components in the range [0..1]. toSRGB :: (Ord b, Floating b) => Colour b -> RGB b-toSRGB c = fmap transferFunction (toRGB709 c)+toSRGB c = fmap transferFunction (toRGB c)  {- Results are clamped and quantized -} -- |Return the approximate sRGB colour components in the range@@ -127,3 +129,9 @@              | otherwise = fst (head rx)  where   rx = sRGB24reads x++-- |The sRGB colour space+sRGBSpace :: (Ord a, Floating a) => RGBSpace a+sRGBSpace = mkRGBSpace sRGBGamut transfer+ where+  transfer = TransferFunction transferFunction invTransferFunction (recip 2.2)
Data/Colour/SRGB/Linear.hs view
@@ -23,19 +23,32 @@ -- |Provides a /linear/ colour space with the same gamut as -- "Data.Colour.SRGB". module Data.Colour.SRGB.Linear - (rgb, toRGB+ (Colour, RGB(..)+ ,rgb, toRGB+ ,sRGBGamut  ) where -import Data.Colour.Internal+import qualified Data.Colour.Internal as Internal(Colour(RGB))+import Data.Colour.Internal (Colour)+import Data.Colour.Chan import Data.Colour.RGB+import Data.Colour.CIE.Chromaticity+import Data.Colour.CIE.Illuminant (d65)  -- |Constructs a 'Colour' from RGB values using the /linear/ RGB colour -- with the same gamut as sRGB. rgb :: Fractional a => a -> a -> a -> Colour a-rgb = rgb709+rgb r g b = Internal.RGB (Chan r) (Chan g) (Chan b)  -- |Return RGB values using the /linear/ RGB colour with the same gamut -- as sRGB. toRGB :: Fractional a => Colour a -> RGB a-toRGB = toRGB709+toRGB (Internal.RGB (Chan r) (Chan g) (Chan b)) = RGB r g b++-- |This is the gamut for the sRGB colour space.+sRGBGamut :: RGBGamut+sRGBGamut = RGBGamut (RGB (mkChromaticity 0.64 0.33)+                         (mkChromaticity 0.30 0.60)+                         (mkChromaticity 0.15 0.06))+                    d65
README view
@@ -1,12 +1,11 @@ I hope for this library to become the standard colour library for Haskell. Most software does not properly blend colours because they fail to-gamma-correct the colours before blending.  By using this library, Haskell-programs dealing with colour blending will avoid this problem.+gamma-correct the colours before blending.  Hopefully by using this library,+Haskell programs dealing with colour blending will avoid this problem. -This 1.0.0 release only contains the sRGB colour space.  Support for other-colour spaces is in development.  I'm releasing this now because I believe-sRGB support is all that is needed for many uses of this library.  I hope-that this sRGB interface will be stable.+I am making an early release of my colour library to get some feedback.+I am especially interested in getting feedback on the interfaces: should+functions be renamed, should functions be moved, etc.  Bug reports and any patches are also welcome.  Be warned, I haven't extensively tested this library yet.
Tests.hs view
@@ -31,13 +31,12 @@  import Data.Colour.Matrix import Data.Colour-import Data.Colour.Internal hiding (RGB)-import Data.Colour.Chan (Chan(..))-import Data.Colour.CIE.Chromaticity import Data.Colour.SRGB+import Data.Colour.SRGB.Linear import Data.Colour.CIE import Data.Colour.Names-import Data.Colour.HDTV as HDTV+--import Data.Colour.HDTV as HDTV+--import qualified Data.Colour.SDTV as SDTV import Data.Colour.RGB import Data.Colour.RGBSpace @@ -65,7 +64,7 @@     mkColour r' g' b' = colourConvert (sRGB24 r' g' b'::Colour Double)   coarbitrary c = coarbitrary (r,g,b)    where-    (RGB r g b) = toRGB709 c+    (RGB r g b) = toRGB c  instance (Real a, Fractional a, Arbitrary a) =>          Arbitrary (AlphaColour a) where@@ -82,71 +81,23 @@  instance (Fractional a, Arbitrary a) =>          Arbitrary (Chromaticity a) where-  arbitrary = liftM2 cieChroma arbitrary arbitrary+  arbitrary = liftM2 mkChromaticity arbitrary arbitrary   coarbitrary c = coarbitrary x . coarbitrary y    where-    (x,y,_) = chroma_coords c+    (x,y,_) = chromaCoords c  instance (Arbitrary a) => Arbitrary (RGB a) where   arbitrary = liftM3 RGB arbitrary arbitrary arbitrary   coarbitrary (RGB r g b) = coarbitrary (r,g,b) -instance (Fractional a, Arbitrary a) =>-         Arbitrary (RGBSpace a) where-  arbitrary = liftM2 RGBSpace arbitrary arbitrary-  coarbitrary (RGBSpace p w) = coarbitrary p . coarbitrary w--instance (Fractional a) => Show (Colour a) where-  showsPrec d c = showParen (d > app_prec) showStr-   where-    showStr = showString "rgb709 " . (showsPrec (app_prec+1) r)-            . showString " "       . (showsPrec (app_prec+1) g)-            . showString " "       . (showsPrec (app_prec+1) b)-    Data.Colour.RGB.RGB r g b = toRGB709 c--instance (Fractional a, Read a) => Read (Colour a) where-  readsPrec d r = readParen (d > app_prec)-                  (\r -> [(rgb709 r0 g0 b0,t)-                         |("rgb709",s) <- lex r-                         ,(r0,s0) <- readsPrec (app_prec+1) s-                         ,(g0,s1) <- readsPrec (app_prec+1) s0-                         ,(b0,t)  <- readsPrec (app_prec+1) s1]) r--instance (Fractional a) => Show (AlphaColour a) where-  showsPrec d ac = showParen (d > infix_prec) showStr-   where-    showStr | a == 0 = showString "transparent"-            | otherwise = showsPrec (infix_prec+1) c-                        . showString " `withOpacity` "-                        . showsPrec (infix_prec+1) a-    a = alphaChannel ac-    c = colourChannel ac--instance (Fractional a, Read a) => Read (AlphaColour a) where-  readsPrec d r = [(transparent,s)|("transparent",s) <- lex r]-               ++ readParen (d > infix_prec)-                  (\r -> [(c `withOpacity` o,s)-                         |(c,r0) <- readsPrec (infix_prec+1) r-                         ,("`",r1) <- lex r0-                         ,("withOpacity",r2) <- lex r1-                         ,("`",r3) <- lex r2-                         ,(o,s)  <- readsPrec (infix_prec+1) r3]) r---- |Returns the colour of an 'AlphaColour'.--- @colourChannel transparent@ is undefined and may result in @nan@ or an--- error.--- Its use is discouraged.--- If you are desparate, use------ >darken (recip (alphaChannel c)) (c `over` black)-colourChannel :: (Fractional a) => AlphaColour a -> Colour a-colourChannel (RGBA c (Chan a)) = darken (recip a) c-+instance Arbitrary RGBGamut where+  arbitrary = liftM2 RGBGamut arbitrary arbitrary+  coarbitrary (RGBGamut p w) = coarbitrary p . coarbitrary w -good (RGBSpace p w) = p1 && p2+good (RGBGamut p w) = p1 && p2  where   p1 = 0 /= determinant (primaryMatrix p)-  p2 = 0 /= let (x,y,z) = chroma_coords w in y+  p2 = 0 /= let (x,y,z) = chromaCoords w in y  prop_matrixMult (a1,b1,c1) (d1,e1,f1) (g1,h1,i1)                 (a2,b2,c2) (d2,e2,f2) (g2,h2,i2)@@ -157,12 +108,18 @@   v :: [Rational]   v = [x,y,z] -prop_toFromRGB709 :: RColour -> Bool-prop_toFromRGB709 c = uncurryRGB rgb709 (toRGB709 c) == c+newtype Depth = Depth Int deriving Show -prop_fromToRGB709 :: Rational -> Rational -> Rational -> Bool-prop_fromToRGB709 r g b = toRGB709 (rgb709 r g b) == RGB r g b+instance Arbitrary Depth where+  arbitrary = liftM Depth $ choose (0,11)+  coarbitrary (Depth x) = coarbitrary x +prop_toFromRGB :: RColour -> Bool+prop_toFromRGB c = uncurryRGB rgb (toRGB c) == c++prop_fromToRGB :: Rational -> Rational -> Rational -> Bool+prop_fromToRGB r g b = toRGB (rgb r g b) == RGB r g b+ prop_toFromXYZ :: RColour -> Bool prop_toFromXYZ c = (cieXYZ x y z) == c  where@@ -177,6 +134,7 @@  prop_fromToSRGB :: Word8 -> Word8 -> Word8 -> Bool prop_fromToSRGB r' g' b' = toSRGB24 (sRGB24 r' g' b') == RGB r' g' b'+ {- prop_fromToY'CbCr709 :: Word8 -> Word8 -> Word8 -> Bool prop_fromToY'CbCr709 y' cb cr =@@ -239,11 +197,11 @@ prop_atopAlpha :: RAlphaColour -> RAlphaColour -> Bool prop_atopAlpha c0 c1 = alphaChannel (c0 `atop` c1) == alphaChannel c1 -prop_showReadC :: RColour -> Bool-prop_showReadC c = read (show c) == c+prop_showReadC :: Depth -> RColour -> Bool+prop_showReadC (Depth d) c = readsPrec d (showsPrec d c "") == [(c,"")] -prop_showReadAC :: RAlphaColour -> Bool-prop_showReadAC c = read (show c) == c+prop_showReadAC :: Depth -> RAlphaColour -> Bool+prop_showReadAC (Depth d) c = readsPrec d (showsPrec d c "") == [(c,"")]  prop_sRGB24showlength :: DColour -> Bool prop_sRGB24showlength c = length (sRGB24show c) == 7@@ -252,22 +210,29 @@ prop_readshowSRGB24 c =   sRGB24show (sRGB24read (sRGB24show c)) == sRGB24show c -{--prop_luminance_white :: RGBSpace Rational -> Property+prop_luminance_white :: RGBGamut -> Property prop_luminance_white space =-  good space ==> luminance (rgbSpace space 1 1 1) == 1+  good space ==> luminance (rgbUsingSpace (linearRGBSpace space) 1 1 1) == 1 -prop_rgb709 :: Rational -> Rational -> Rational -> Bool-prop_rgb709 r g b =-  rgbSpace rgb709Space r g b == rgb709 r g b+prop_rgb :: Rational -> Rational -> Rational -> Bool+prop_rgb r g b =+  rgbUsingSpace (linearRGBSpace sRGBGamut) r g b == rgb r g b -prop_toRGB709 :: RColour -> Bool-prop_toRGB709 c =-  toRGBSpace rgb709Space c == toRGB709 c--}+prop_toRGB :: RColour -> Bool+prop_toRGB c =+  toRGBUsingSpace (linearRGBSpace sRGBGamut) c == toRGB c++prop_sRGB :: Double -> Double -> Double -> Bool+prop_sRGB r g b = rgbUsingSpace sRGBSpace r g b == sRGB r g b++prop_toSRGB :: DColour -> Bool+prop_toSRGB c =+  toRGBUsingSpace sRGBSpace c == toSRGB c++ tests = [("matrix-mult", test prop_matrixMult)-        ,("RGB709-to-from", test prop_toFromRGB709)-        ,("RGB709-from-to", test prop_fromToRGB709)+        ,("RGB-to-from", test prop_toFromRGB)+        ,("RGB-from-to", test prop_fromToRGB)         ,("XYZ-to-from", test prop_toFromXYZ)         ,("XYZ-from-to", test prop_fromToXYZ)         ,("sRGB-to-from", test prop_toFromSRGB)@@ -287,16 +252,18 @@         ,("darken-black", test prop_darkenBlack)         ,("darken-id", test prop_darkenId)         ,("atop-opaque", test prop_atopOpaque)-        ,("trasnparent-atop", test prop_transparentAtop)+        ,("transparent-atop", test prop_transparentAtop)         ,("atop-transparent", test prop_atopTransparent)         ,("atop-alpha", test prop_atopAlpha)         ,("colour-show-read", test prop_showReadC)         ,("alphaColour-show-read", test prop_showReadAC)         ,("sRGB24-show-length", test prop_sRGB24showlength)         ,("sRGB24-read-show", test prop_readshowSRGB24)---        ,("luminance-white", test prop_luminance_white)---        ,("rgb709", test prop_rgb709)---        ,("toRGB709", test prop_toRGB709)+        ,("luminance-white", test prop_luminance_white)+        ,("rgb", test prop_rgb)+        ,("toRGB", test prop_toRGB)+        ,("sRGB", test prop_sRGB)+        ,("toSRGB", test prop_toSRGB)         ]  main  = mapM_ (\(s,a) -> printf "%-25s: " s >> a) tests
colour.cabal view
@@ -1,5 +1,5 @@ Name:                colour-Version:             2.0.0+Version:             2.1.0 Cabal-Version:       >= 1.2 License:             OtherLicense License-file:        LICENSE@@ -10,7 +10,7 @@ Synopsis:            A model for human colour/color perception Description:         This package provides a data type for colours and transparency.                      Colours can be blended and composed.-                     sRGB colour space is supported ("Data.Colour.SRGB").+                     Various colour spaces are supported.                      A module of colour names ("Data.Colour.Names") is provided. Tested-with:         GHC == 6.8.2 extra-source-files:  Tests.hs README@@ -20,6 +20,8 @@   Exposed-Modules:   Data.Colour                      Data.Colour.SRGB                      Data.Colour.SRGB.Linear+                     Data.Colour.CIE+                     Data.Colour.CIE.Illuminant                      Data.Colour.RGBSpace                      Data.Colour.Names   Other-Modules:     Data.Colour.Internal@@ -27,4 +29,3 @@                      Data.Colour.RGB                      Data.Colour.Matrix                      Data.Colour.CIE.Chromaticity-                     Data.Colour.CIE.Illuminant