colour-2.3.3: A model for human colour/color perception

Safe Haskell | Safe
Language | Haskell98

Data.Colour

Contents

- Interfacing with Other Libraries' Colour Spaces
- Colour type
- Colour operations
- Orphan instances

Description

Datatypes for representing the human perception of colour. Includes common operations for blending and compositing colours. 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 `RGBSpace` by using

- Data.Colour.RGBSpace

Synopsis

- data Colour a
- colourConvert :: (Fractional b, Real a) => Colour a -> Colour b
- black :: Num a => Colour a
- data AlphaColour a
- opaque :: Num a => Colour a -> AlphaColour a
- withOpacity :: Num a => Colour a -> a -> AlphaColour a
- transparent :: Num a => AlphaColour a
- alphaColourConvert :: (Fractional b, Real a) => AlphaColour a -> AlphaColour b
- alphaChannel :: AlphaColour a -> a
- class AffineSpace f where
- blend :: (Num a, AffineSpace f) => a -> f a -> f a -> f a
- class ColourOps f where
- dissolve :: Num a => a -> AlphaColour a -> AlphaColour a
- atop :: Fractional a => AlphaColour a -> AlphaColour a -> AlphaColour a

# Interfacing with Other Libraries' Colour Spaces

Executive summary: Always use Data.Colour.SRGB when interfacing with other libraries. Use `toSRGB24` / `sRGB24` when interfacing with libraries wanting `Word8` per channel. Use `toSRGB` / `sRGB` when interfacing with libraries wanting `Double` or `Float` per channel.

Interfacing with the colour for other libraries, such as cairo (http://www.haskell.org/gtk2hs/archives/category/cairo/) and OpenGL (http://hackage.haskell.org/cgi-bin/hackage-scripts/package/OpenGL), can be a challenge because these libraries often do not use colour spaces in a consistent way. The problem is that these libraries work in a device dependent colour space and give no indication what the colour space is. For most devices this colours space is implicitly the non-linear sRGB space. However, to make matters worse, these libraries also do their compositing and blending in the device colour space. Blending and compositing ought to be done in a linear colour space, but since the device space is typically non-linear sRGB, these libraries typically produce colour blends that are too dark.

(Note that Data.Colour is a device independent colour space, and produces correct blends. e.g. compare `toSRGB (blend 0.5 lime red)` with `RGB 0.5 0.5 0`)

Because these other colour libraries can only blend in device colour spaces, they are fundamentally broken and there is no "right" way to interface with them. For most libraries, the best one can do is assume they are working with an sRGB colour space and doing incorrect blends. In these cases use Data.Colour.SRGB to convert to and from the colour coordinates. This is the best advice for interfacing with cairo.

When using OpenGL, the choice is less clear. Again, OpenGL usually does blending in the device colour space. However, because blending is an important part of proper shading, one may want to consider that OpenGL is working in a linear colour space, and the resulting rasters are improperly displayed. This is born out by the fact that OpenGL extensions that support sRGB do so by converting sRGB input/output to linear colour coordinates for processing by OpenGL.

The best way to use OpenGL, is to use proper sRGB surfaces for textures and rendering. These surfaces will automatically convert to and from OpenGL's linear colour space. In this case, use Data.Colour.SRGB.Linear to interface OpenGL's linear colour space.

If not using proper surfaces with OpenGL, then you have a choice between having OpenGL do improper blending or improper display If you are using OpenGL for 3D shading, I recommend using Data.Colour.SRGB.Linear (thus choosing improper OpenGL display). If you are not using OpenGL for 3D shading, I recommend using Data.Colour.SRGB (thus choosing improper OpenGL blending).

# Colour type

data Colour a #

This type represents the human preception of colour. The `a` parameter is a numeric type used internally for the representation.

The `Monoid` instance allows one to add colours, but beware that adding colours can take you out of gamut. Consider using `blend` whenever possible.

Instances

ColourOps Colour # |
Methods over :: Num a => AlphaColour a -> Colour a -> Colour a # darken :: Num a => a -> Colour a -> Colour a #
AffineSpace Colour # |
Methods affineCombo :: Num a => [(a, Colour a)] -> Colour a -> Colour a #
Eq a => Eq (Colour a) # |
Methods (==) :: Colour a -> Colour a -> Bool # (/=) :: Colour a -> Colour a -> Bool #
Num a => Monoid (Colour a) # |
Methods mempty :: Colour a # mappend :: Colour a -> Colour a -> Colour a # mconcat :: [Colour a] -> Colour a #

colourConvert :: (Fractional b, Real a) => Colour a -> Colour b #

Change the type used to represent the colour coordinates.

black :: Num a => Colour a #

data AlphaColour a #

This type represents a `Colour` that may be semi-transparent.

The `Monoid` instance allows you to composite colours.

    x `mappend` y == x `over` y

To get the (pre-multiplied) colour channel of an `AlphaColour` `c`, simply composite `c` over black.

    c `over` black

Instances

ColourOps AlphaColour # |
Methods over :: Num a => AlphaColour a -> AlphaColour a -> AlphaColour a # darken :: Num a => a -> AlphaColour a -> AlphaColour a #
AffineSpace AlphaColour # |
Methods affineCombo :: Num a => [(a, AlphaColour a)] -> AlphaColour a -> AlphaColour a #
Eq a => Eq (AlphaColour a) # |
Methods (==) :: AlphaColour a -> AlphaColour a -> Bool # (/=) :: AlphaColour a -> AlphaColour a -> Bool #
Num a => Monoid (AlphaColour a) # | `AlphaColour` forms a monoid with `over` and `transparent`.
Methods mempty :: AlphaColour a # mappend :: AlphaColour a -> AlphaColour a -> AlphaColour a # mconcat :: [AlphaColour a] -> AlphaColour a #

opaque :: Num a => Colour a -> AlphaColour a #

Creates an opaque `AlphaColour` from a `Colour`.

withOpacity :: Num a => Colour a -> a -> AlphaColour a #

Creates an `AlphaColour` from a `Colour` with a given opacity.

    c `withOpacity` o == dissolve o (opaque c)

transparent :: Num a => AlphaColour a #

This `AlphaColour` is entirely transparent and has no associated colour channel.

alphaColourConvert :: (Fractional b, Real a) => AlphaColour a -> AlphaColour b #

Change the type used to represent the colour coordinates.

alphaChannel :: AlphaColour a -> a #

Returns the opacity of an `AlphaColour`.

# Colour operations

These operations allow combine and modify existing colours

class AffineSpace f where #

Minimal complete definition

affineCombo

Methods

affineCombo :: Num a => [(a, f a)] -> f a -> f a #

Compute a affine Combination (weighted-average) of points. The last parameter will get the remaining weight. e.g.

    affineCombo [(0.2,a), (0.3,b)] c == 0.2*a + 0.3*b + 0.5*c

Weights can be negative, or greater than 1.0; however, be aware that non-convex combinations may lead to out of gamut colours.

Instances

AffineSpace AlphaColour # |
Methods affineCombo :: Num a => [(a, AlphaColour a)] -> AlphaColour a -> AlphaColour a #
AffineSpace Colour # |
Methods affineCombo :: Num a => [(a, Colour a)] -> Colour a -> Colour a #

blend :: (Num a, AffineSpace f) => a -> f a -> f a -> f a #

Compute the weighted average of two points. e.g.

    blend 0.4 a b = 0.4*a + 0.6*b

The weight can be negative, or greater than 1.0; however, be aware that non-convex combinations may lead to out of gamut colours.

class ColourOps f where #

Minimal complete definition

over, darken

Methods

over :: Num a => AlphaColour a -> f a -> f a #

`c1 `over` c2` returns the `Colour` created by compositing the `AlphaColour` `c1` over `c2`, which may be either a `Colour` or `AlphaColour`.

darken :: Num a => a -> f a -> f a #

`darken s c` blends a colour with black without changing it's opacity.

For `Colour`, `darken s c = blend s c mempty`

Instances

ColourOps AlphaColour # |
Methods over :: Num a => AlphaColour a -> AlphaColour a -> AlphaColour a # darken :: Num a => a -> AlphaColour a -> AlphaColour a #
ColourOps Colour # |
Methods over :: Num a => AlphaColour a -> Colour a -> Colour a # darken :: Num a => a -> Colour a -> Colour a #

dissolve :: Num a => a -> AlphaColour a -> AlphaColour a #

Returns an `AlphaColour` more transparent by a factor of `o`.

atop :: Fractional a => AlphaColour a -> AlphaColour a -> AlphaColour a #

`c1 `atop` c2` returns the `AlphaColour` produced by covering the portion of `c2` visible by `c1`. The resulting alpha channel is always the same as the alpha channel of `c2`.

    c1 `atop` (opaque c2) == c1 `over` (opaque c2)
    AlphaChannel (c1 `atop` c2) == AlphaChannel c2

# Orphan instances

(Fractional a, Read a) => Read (AlphaColour a) # |
Methods readsPrec :: Int -> ReadS (AlphaColour a) # readList :: ReadS [AlphaColour a] # readPrec :: ReadPrec (AlphaColour a) # readListPrec :: ReadPrec [AlphaColour a] #
(Fractional a, Read a) => Read (Colour a) # |
Methods readsPrec :: Int -> ReadS (Colour a) # readList :: ReadS [Colour a] # readPrec :: ReadPrec (Colour a) # readListPrec :: ReadPrec [Colour a] #
(Fractional a, Show a, Eq a) => Show (AlphaColour a) # |
Methods showsPrec :: Int -> AlphaColour a -> ShowS # show :: AlphaColour a -> String # showList :: [AlphaColour a] -> ShowS #
(Fractional a, Show a) => Show (Colour a) # |
Methods showsPrec :: Int -> Colour a -> ShowS # show :: Colour a -> String # showList :: [Colour a] -> ShowS #