bitmap-0.0.2: Data/Bitmap/IO/File.hs
--------------------------------------------------------------------------------
-- Module : Data.Bitmap.IO.File
-- Version : 0.0.2
-- License : BSD3
-- Copyright : (c) 2009-2010 Balazs Komuves
-- Author : Balazs Komuves
-- Maintainer : bkomuves (plus) hackage (at) gmail (dot) com
-- Stability : experimental
-- Portability : requires FFI and CPP
-- Tested with : GHC 6.10.1
--------------------------------------------------------------------------------
-- | Saving and loading uncompressed bitmaps.
-- For loading from compressed formats, see the @stb-image@ library:
-- <http://hackage.haskell.org/package/stb-image>.
--
-- The goal of this module is to provide the simplest possible interface
-- for loading and saving bitmaps; so you can start experimenting
-- without much hassle.
--
-- Note: Endianness is the endianness of the host, so the resulting file is
-- not portable across platforms with different endiannesses.
--
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
module Data.Bitmap.IO.File
( readBitmap
, writeBitmap
--
, readRawData
, writeRawData
--
, hPutHeader
, hPutRawData
, hGetHeader
, hGetRawData
)
where
--------------------------------------------------------------------------------
import Control.Monad
import System.IO
--import Foreign -- GHC 7 complains?
import Foreign.C
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable
import Foreign.Marshal
import Data.Int
import Data.Bitmap.Base
import Data.Bitmap.Internal
import Data.Bitmap.IO
--------------------------------------------------------------------------------
readBitmap :: PixelComponent t => FilePath -> IO (IOBitmap t)
readBitmap fpath = do
h <- openFile fpath ReadMode
header <- hGetHeader h
bitmap <- hGetRawData h header
hClose h
return bitmap
readRawData :: PixelComponent t => FilePath -> (Size,NChn,PixelComponentType) -> IO (IOBitmap t)
readRawData fpath header = do
h <- openFile fpath ReadMode
bitmap <- hGetRawData h header
hClose h
return bitmap
--------------------------------------------------------------------------------
writeBitmap :: PixelComponent t => FilePath -> IOBitmap t -> IO ()
writeBitmap fpath bm = do
h <- openFile fpath WriteMode
hPutHeader h bm
hPutRawData h bm
hClose h
-- | Saves only the raw pixel data, no resolution etc.
writeRawData :: PixelComponent t => FilePath -> IOBitmap t -> IO ()
writeRawData fpath bm = do
h <- openFile fpath WriteMode
hPutRawData h bm
hClose h
--------------------------------------------------------------------------------
-- | Writes a 16 byte header in the following format:
--
-- > dword xsize
-- > dword ysize
-- > dword nchn
-- > dword pixelcomponent_type
--
-- Pixel component encoding is the following:
--
-- * 1 = Word8
--
-- * 2 = Word16
--
-- * 3 = Word32
--
-- * 4 = Float
--
-- Endianness is the endianness of the host, so the resulting file is
-- not portable across platform with different endiannesses.
hPutHeader :: PixelComponent t => Handle -> IOBitmap t -> IO ()
hPutHeader h bm = do
let (xsize,ysize) = bitmapSize bm
nchn = bitmapNChannels bm
typ = bitmapCType bm
with (fromIntegral xsize :: Int32) $ \p -> hPutBuf h p 4
with (fromIntegral ysize :: Int32) $ \p -> hPutBuf h p 4
with (fromIntegral nchn :: Int32) $ \p -> hPutBuf h p 4
with (fromIntegral typ :: Int32) $ \p -> hPutBuf h p 4
-- | Saves only the raw pixel data, no resolution etc.
hPutRawData :: PixelComponent t => Handle -> IOBitmap t -> IO ()
hPutRawData h bm =
withIOBitmap bm $ \(xres,yres) nchn padding ptr -> do
forM_ [0..yres-1] $ \k -> do
let q = ptr `plusPtr` (k*long)
hPutBuf h q short
where
long = bitmapPaddedRowSizeInBytes bm
short = bitmapUnpaddedRowSizeInBytes bm
--------------------------------------------------------------------------------
hGetRawData :: PixelComponent t => Handle -> (Size,NChn,PixelComponentType) -> IO (IOBitmap t)
hGetRawData h (siz,nchn,pct) = do
bm <- newIOBitmapUninitialized siz nchn (Just 1)
if bitmapComponentType bm /= pct
then error "bitmap/getRawData: bitmap component type does not match"
else do
withIOBitmap bm $ \(_,ysiz) _ _ ptr -> do
let n = ysiz * bitmapUnpaddedRowSizeInBytes bm
k <- hGetBuf h ptr n
when (k/=n) $ error "bitmap/getRawData: not enough data"
return bm
hGetHeader :: Handle -> IO (Size,NChn,PixelComponentType)
hGetHeader h = do
xsize <- loadInt32
ysize <- loadInt32
nchn <- loadInt32
ctyp <- loadInt32
return
( (fromIntegral xsize, fromIntegral ysize)
, fromIntegral nchn
, decodeCType (fromIntegral ctyp)
)
where
loadInt32 :: IO Int32
loadInt32 = alloca $ \p -> do
hGetBuf h p 4
peek p
--------------------------------------------------------------------------------