-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.Backend.Cairo.List
-- Copyright   :  (c) 2012 Diagrams-cairo team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Render a diagram directly to a list of lists of Colour values
-- (/i.e./ pixels).
--
-----------------------------------------------------------------------------

module Diagrams.Backend.Cairo.List where

import           Control.Applicative        ((<$>))
import           Control.Exception          (bracket)

import           Data.Colour
import           Data.Colour.SRGB           (sRGB)
import           Data.Word                  (Word8)

import           Diagrams.Backend.Cairo     (Cairo)
import           Diagrams.Backend.Cairo.Ptr (renderPtr)
import           Diagrams.Prelude           (Diagram, R2)

import           Foreign.Marshal.Alloc      (free)
import           Foreign.Marshal.Array      (peekArray)

-- | Render to a regular list of Colour values.

renderToList :: (Ord a, Floating a) =>
                  Int -> Int -> Diagram Cairo R2 -> IO [[AlphaColour a]]
renderToList w h d =
  f 0 <$> bracket (renderPtr w h d) free (peekArray $ w*h*4)
 where
  f :: (Ord a, Floating a) => Int -> [Word8] -> [[AlphaColour a]]
  f _ [] = []
  f n xs | n >= w = [] : f 0 xs
  f n (g:b:r:a:xs) =
    let l x = fromIntegral x / fromIntegral a
        c   = sRGB (l r) (l g) (l b) `withOpacity` (fromIntegral a / 255)

    in case f (n+1) xs of
      []    -> [[c]]
      cs:ys -> (c:cs) : ys

  f _ _ = error "renderToList: Internal format error"