propane-0.1: Propane/IO.hs
-- | Input and output.
--
-- TODO: input.
module Propane.IO
( saveRaster
, saveRastimation
) where
import qualified Data.Array.Repa as R
import qualified Data.Array.Repa.IO.DevIL as D
import qualified Data.Foldable as F
import Control.Monad
import Control.Concurrent.Spawn
import Control.Exception
import System.FilePath
import System.Directory
import Text.Printf
import Propane.Types
import Propane.IO.Lock ( lock )
errStr :: String -> String
errStr = ("Propane.IO: " ++)
-- | Save the @'Raster'@ to a given file.
--
-- The file format is specified by the filename, and can
-- be any of the formats supported by the DevIL library.
--
-- Note that DevIL silently refuses to overwrite an existing
-- file.
saveRaster :: FilePath -> Raster -> IO ()
saveRaster name (Raster img) = do
evaluate (R.deepSeqArray img ())
lock $ D.runIL (D.writeImage name img)
-- | Save the @'Rastimation'@ to a sequence of frames in
-- the given directory.
--
-- The frames will be PNG files with names like
--
-- >00000000.png
-- >00000001.png
--
-- etc, in frame order.
--
-- Files are written concurrently, and there is no guarantee
-- about which files exist, until the IO action completes.
--
-- Note that DevIL silently refuses to overwrite an existing
-- file.
saveRastimation :: FilePath -> Rastimation -> IO ()
saveRastimation dir (Rastimation frames) = do
createDirectoryIfMissing True dir
-- Check existence, to give better error messages
e <- doesDirectoryExist dir
when (not e)
(throwIO . ErrorCall $ errStr ("directory does not exist: " ++ dir))
let go :: Int -> Raster -> IO (IO ())
go i img = spawn $ saveRaster (dir </> printf "%08d.png" i) img
zipWithM go [0..] (F.toList frames) >>= sequence_