propane-0.1: Propane/Raster.hs
-- | Conversion to raster forms.
--
-- TODO: the reverse.
module Propane.Raster
( rasterize
, rastimate
) where
import qualified Data.Sequence as S
import qualified Data.Colour as C
import qualified Data.Colour.SRGB as C
import qualified Data.Array.Repa as R
import Data.Array.Repa ( Z(..), (:.)(..) )
import Propane.Types
import Propane.Transform ( spaced )
type W8888 = (Word8, Word8, Word8, Word8)
-- | Convert the @'Image'@ region [-1, 1] x [-1, 1] to a @'Raster'@ with
-- the specified number of pixels.
rasterize :: Size -> Image Colour -> Raster
rasterize (Size w h) im = Raster . chans $ R.fromFunction dim f where
f = quant . im . point
dw = fromIntegral w - 1
dh = fromIntegral h - 1
dim = Z :. w :. h
point :: R.DIM2 -> R2
point (Z :. y :. x) = (adj dw x, adj dh y) where
adj d n = (2 * fromIntegral n / d) - 1
quant :: Colour -> W8888
quant c = (r, g, b, a) where
C.RGB r g b = C.toSRGB24 (c `C.over` C.black)
a = round (C.alphaChannel c * 255.0)
chans :: R.Array R.DIM2 W8888 -> R.Array R.DIM3 Word8
chans arr = R.traverse arr (:. 4) chan where
chan a (Z :. y :. x :. c) = ix c (a (Z :. y :. x))
ix 0 (r,_,_,_) = r
ix 1 (_,g,_,_) = g
ix 2 (_,_,b,_) = b
ix 3 (_,_,_,a) = a
ix _ _ = error "Propane.Quantize: internal error (bad ix)"
-- | Convert the animation, for times in [0,1), to a @'Rastimation'@ with
-- the specified numbers of frames and pixels.
rastimate :: Count -> Size -> Animation Colour -> Rastimation
rastimate n sz ani = Rastimation (S.fromList frames) where
frames = map (rasterize sz . ani) (spaced n 0 1)