-- | -- Module: Graphics.Chalkboard.PPM -- Copyright: (c) 2009 Andy Gill -- License: BSD3 -- -- Maintainer: Andy Gill -- Stability: unstable -- Portability: ghc -- -- Reading and writing portable pix maps. For now, we only support color images (@P3@ and @P6@ formats). -- module Graphics.Chalkboard.PPM where import System.IO import Data.Array import Data.Char import Graphics.Chalkboard.Types import Graphics.Chalkboard.Color import Graphics.Chalkboard.Board import Graphics.Chalkboard.Array -- | 'readPPM' reads a PPM file, and outputs a @Board@, and the @x@ and @y@ dimensions of the image. readPPM :: String -> IO (Board (Maybe RGB),(Int,Int)) readPPM filename = do h <- openFile filename ReadMode ty <- hGetLine h bin <- case ty of "P3" -> return False "P6" -> return True _ -> error $ "bad PPM format: " ++ ty szs <- hGetLine h let [width,height] = (map read (words szs) :: [Int]) -- print width -- print height mx <- hGetLine h let [maxs] = (map read (words mx) :: [R]) -- print mx str <- hGetContents h let num1 = if bin then map (\ x -> fromIntegral (ord x) / maxs) str else map (\ x -> read x / maxs) (words str) let joinN _ [] = [] joinN n xs = take n xs : joinN n (drop n xs) let num3 = joinN 3 num1 let num_rows = joinN width num3 let arr = array ((0,0),(width-1,height-1)) [ ((w,h'),RGB r g b) | (row,h') <- zip num_rows [height-1,height-2..] , ([r,g,b],w) <- zip row [0..] ] return $ (arrayToBoard arr,(width,height)) -- | 'writePPM' writes a PPM file, based on a color @Board@, where bottom left corner of the image is as @(0,0)@. writePPM :: String -> (Int,Int) -> Board RGB -> IO () writePPM filename (x_dim,y_dim) img = writeFile filename $ "P6\n" ++ show (x_dim) ++ " " ++ show (y_dim) ++ "\n255\n" ++ concat [ let (RGB r g b) = arr ! (x,y) f x' = if v < 0 then chr 0 else if v > 255 then chr 255 else chr v where v = floor (x' * 255) in [f r,f g,f b] | y <- reverse [0..y_dim-1] , x <- [0..x_dim-1] ] where arr = boardToArray (x_dim-1,y_dim-1) 3 img