{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Image.Farbfeld
( Image(..)
, Pixel(..)
, parseImage
, emitImage
) where
import Control.Monad (when, forM_)
import Data.Array (Array, array, bounds, (!))
import Data.ByteString.Lazy (ByteString)
import Data.Word (Word16, Word32)
import qualified Data.Serialize as S
newtype Image = Image
{ imgPixels :: Array (Word32, Word32) Pixel
} deriving (Eq, Show)
data Pixel = Pixel
{ pxRed :: !Word16
, pxGreen :: !Word16
, pxBlue :: !Word16
, pxAlpha :: !Word16
} deriving (Eq, Show)
parseImage :: ByteString -> Either String Image
parseImage = S.runGetLazy $ do
magic <- S.getByteString 8
when (magic /= "farbfeld") $
fail "Unable to find farbfeld magic number"
w <- S.getWord32be
h <- S.getWord32be
imgPixels <- array ((0, 0), (w-1, h-1)) <$> sequence
[ sequence ((x, y), getPixel)
| y <- [0..h-1]
, x <- [0..w-1]
]
return Image { .. }
emitImage :: Image -> ByteString
emitImage (Image pixels) = S.runPutLazy $ do
S.putByteString "farbfeld"
let (w, h) = snd (bounds pixels)
S.putWord32be (w + 1)
S.putWord32be (h + 1)
forM_ [0..h] $ \y ->
forM_ [0..w] $ \x -> do
let Pixel { .. } = pixels ! (x, y)
S.putWord16be pxRed
S.putWord16be pxGreen
S.putWord16be pxBlue
S.putWord16be pxAlpha
getPixel :: S.Get Pixel
getPixel = Pixel
<$> S.getWord16be
<*> S.getWord16be
<*> S.getWord16be
<*> S.getWord16be