diff --git a/AC-Colour.cabal b/AC-Colour.cabal
--- a/AC-Colour.cabal
+++ b/AC-Colour.cabal
@@ -1,6 +1,6 @@
 Cabal-Version: >= 1.6
 Name:          AC-Colour
-Version:       1.1.2
+Version:       1.1.3
 Stability:     Experimental
 Synopsis:      Efficient RGB colour types.
 
@@ -13,8 +13,10 @@
 
   Changes:
 
-  * Now works with GHC 6.12.x.
+  * Added (linear) colour map support.
 
+  * Added pack/unpack functions.
+
 Category:      Data, Math, Numerical, Graphics
 License:       BSD3
 License-file:  License.txt
@@ -24,6 +26,6 @@
 Tested-With:   GHC == 6.10.3
 
 Library
-  Exposed-modules: Data.Colour.Double, Data.Colour.Word8, Data.Colour.FastFloor, Data.Colour
+  Exposed-modules: Data.Colour.Double, Data.Colour.Map, Data.Colour.Word8, Data.Colour.FastFloor, Data.Colour
   Build-Depends:   base >= 4 && < 5, ghc-prim >= 0.1.0.0 && < 0.3
   HS-Source-Dirs:  .
diff --git a/Data/Colour.hs b/Data/Colour.hs
--- a/Data/Colour.hs
+++ b/Data/Colour.hs
@@ -13,11 +13,11 @@
 module Data.Colour
     (
       Colour (..),
-      grey, cscale, clip,
+      grey, cscale, clip, pack, unpack,
       cBlack, cWhite, cRed, cYellow, cGreen, cCyan, cBlue, cMagenta,
 
       Colour8 (..),
-      grey8, c8scale,
+      grey8, c8scale, pack8, unpack8,
       c8Black, c8White, c8Red, c8Yellow, c8Green, c8Cyan, c8Blue, c8Magenta,
 
       cpromote, cdemote
diff --git a/Data/Colour/Double.hs b/Data/Colour/Double.hs
--- a/Data/Colour/Double.hs
+++ b/Data/Colour/Double.hs
@@ -74,6 +74,12 @@
 clip :: Colour -> Colour
 clip = cmap (min 1 . max 0)
 
+unpack :: Colour -> (Double, Double, Double)
+unpack (Colour r g b) = (r, g, b)
+
+pack :: (Double, Double, Double) -> Colour
+pack (r, g, b) = Colour r g b
+
 -- | Constant: Black.
 cBlack   :: Colour
 cBlack   = Colour 0 0 0
diff --git a/Data/Colour/Map.hs b/Data/Colour/Map.hs
new file mode 100644
--- /dev/null
+++ b/Data/Colour/Map.hs
@@ -0,0 +1,87 @@
+{- |
+  This module provides 1-dimensional colour maps with
+  smooth (linear) colour blending between control points.
+-}
+
+module Data.Colour.Map
+    (
+      range_cycle,
+      ColourMap, colour_map,
+      FullColourMap (..), full_colour_map
+    )
+  where
+
+import Data.Colour.Double
+
+{- |
+  Takes a range and a value, and returns a value inside
+  the given range. If the value is already in the range,
+  it is unchanged. Otherwise it \"wraps around\". For
+  example, if the range is @(0, 1)@ then, in effect,
+  the fractional part of the value is returned.
+
+  Note that extremely narrow ranges may exhibit numerical
+  instability.
+-}
+range_cycle :: (Double,Double) -> Double -> Double
+range_cycle (x0,x1) x
+  | x0 == x1  = error "Data.Colour.Map.range_cycle: zero-width range"
+  | x0 >  x1  = range_cycle (x1,x0) x
+  | otherwise =
+    let
+      dx = x1 - x0
+      y  = x  - x0
+      n  = floor (y / dx)
+      z  = y - (fromIntegral n * dx)
+    in z + x0
+
+{- |
+  This is the basic colour map type. It consists of a list of
+  control points, each one being a parameter value and the
+  colour at that parameter value. The colour at other
+  parameter values is linearly interpolated between the
+  control points.
+
+  Parameter values outside the range (i.e., below the first
+  point or above the last point) take the colour of the
+  end control point. This means that in the degenerate
+  case of a single control point, the colour is applied
+  everywhere (and the parameter value is ignored).
+
+  A map with /zero/ control points is not permitted.
+-}
+type ColourMap = [(Double, Colour)]
+
+{- |
+  Compute the value of a colour map at a particular
+  parameter value.
+-}
+colour_map :: ColourMap -> Double -> Colour
+colour_map [] _ = error "Data.Colour.Map.colour_map []"
+colour_map ps x = cm_internal ps x
+
+cm_internal ((x0,c0):[])         x = c0
+cm_internal ((x0,c0):(x1,c1):ps) x
+  | x < x0 = c0
+  | x > x1 = cm_internal ((x1,c1):ps) x
+  | otherwise =
+    let
+      dx = x1 - x0
+      k  = (x - x0) / dx
+    in (1-k) `cscale` c0 + k `cscale` c1
+
+{- |
+  This is a colour map with has optional repeating behaviour
+  using 'range_cycle' above.
+-}
+data FullColourMap =
+  SimpleMap                    ColourMap | -- ^ Colour map which does not repeat.
+  RepeatingMap (Double,Double) ColourMap   -- ^ Colour map which repeats.
+
+{- |
+  Compute the value of a full colour map at a particular
+  parameter value, similar to 'colour_map'.
+-}
+full_colour_map :: FullColourMap -> Double -> Colour
+full_colour_map (SimpleMap      m) = colour_map m
+full_colour_map (RepeatingMap r m) = colour_map m . range_cycle r
diff --git a/Data/Colour/Word8.hs b/Data/Colour/Word8.hs
--- a/Data/Colour/Word8.hs
+++ b/Data/Colour/Word8.hs
@@ -72,6 +72,12 @@
   signum = c8map signum
   fromInteger = grey8 . fromInteger
 
+unpack8 :: Colour8 -> (Word8, Word8, Word8)
+unpack8 (Colour8 r g b) = (r,g,b)
+
+pack8 :: (Word8, Word8, Word8) -> Colour8
+pack8 (r,g,b) = Colour8 r g b
+
 -- | Constant: Black.
 c8Black   :: Colour8
 c8Black   = Colour8 0x00 0x00 0x00
