-----------------------------------------------------------------------------
-- |
-- 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           Graphics.Rendering.Cairo   (Format (..))
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 FormatARGB32 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"