bitmap-0.0.2: Data/Bitmap/IO/Pixels.hs
--------------------------------------------------------------------------------
-- Module : Data.Bitmap.IO.Pixels
-- 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
--------------------------------------------------------------------------------
-- | Accessing individual pixels.
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
module Data.Bitmap.IO.Pixels
(
-- * Types
IOBitmap1 -- (..)
, IOBitmap2 -- (..)
, IOBitmap3 -- (..)
, IOBitmap4 -- (..)
--
, ioBitmap1
, ioBitmap2
, ioBitmap3
, ioBitmap4
--
, fromIOBitmap1
, fromIOBitmap2
, fromIOBitmap3
, fromIOBitmap4
-- * Reading and writing pixels
, withComponentPtr
--
, unsafeReadComponent
, unsafeWriteComponent
, unsafeReadComponents
, unsafeWriteComponents
--
, unsafeReadPixel
, unsafeReadPixel1
, unsafeReadPixel2
, unsafeReadPixel3
, unsafeReadPixel4
, unsafeWritePixel1
, unsafeWritePixel2
, unsafeWritePixel3
, unsafeWritePixel4
)
where
--------------------------------------------------------------------------------
import Control.Monad
import Control.Applicative
import Data.Word
--import Foreign -- GHC 7 complains?
import Foreign.C
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Storable
import Foreign.Marshal
--import Data.ByteString (ByteString)
--import qualified Data.ByteString as B
--import qualified Data.ByteString.Internal as B
import Data.Bitmap.Internal
import Data.Bitmap.Base
import Data.Bitmap.IO
--------------------------------------------------------------------------------
-- | Note that the resulting pointer is valid only within a line (because of the padding)
withComponentPtr
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> Int -- ^ channel index {0,1,...,nchannels-1}
-> (Ptr t -> IO a) -- ^ user action
-> IO a
withComponentPtr (IOBitmap bm) (x,y) ofs action =
withForeignPtr (bitmapPtr bm) $ \p -> do
let nchn = bitmapNChannels bm
rowsize = bitmapPaddedRowSizeInBytes bm
q = p `myPlusPtr` ( ( nchn*x + ofs ) * sizeOf (bitmapUndefined bm) + y * rowsize )
action q
-- | It is not very efficient to read\/write lots of pixels this way.
unsafeReadComponent
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> Int -- ^ channel index {0,1,...,nchannels-1}
-> IO t
unsafeReadComponent bm xy ofs = withComponentPtr bm xy ofs $ peek
unsafeWriteComponent
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> Int -- ^ channel index {0,1,...,nchannels-1}
-> t -- ^ the value to write
-> IO ()
unsafeWriteComponent bm xy ofs value = withComponentPtr bm xy ofs $ \q -> poke q value
-- | Please note that the component array to read shouldn't cross
-- the boundary between lines.
unsafeReadComponents
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> Int -- ^ channel index {0,1,...,nchannels-1}
-> Int -- ^ the number of components to read
-> IO [t]
unsafeReadComponents bm xy ofs k = withComponentPtr bm xy ofs $ \p -> peekArray k p
-- | Please note that the component array to write shouldn't cross
-- the boundary between lines.
unsafeWriteComponents
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> Int -- ^ channel index {0,1,...,nchannels-1}
-> [t] -- ^ the components to write
-> IO ()
unsafeWriteComponents bm xy ofs values = withComponentPtr bm xy ofs $ \q -> pokeArray q values
unsafeReadPixel
:: PixelComponent t
=> IOBitmap t -- ^ the bitmap
-> Offset -- ^ position (x,y)
-> IO [t]
unsafeReadPixel bm xy = unsafeReadComponents bm xy 0 (bitmapNChannels bm)
--------------------------------------------------------------------------------
instance BitmapClass IOBitmap1 where
underlyingBitmap = unIOBitmap . fromIOBitmap1
instance BitmapClass IOBitmap2 where
underlyingBitmap = unIOBitmap . fromIOBitmap2
instance BitmapClass IOBitmap3 where
underlyingBitmap = unIOBitmap . fromIOBitmap3
instance BitmapClass IOBitmap4 where
underlyingBitmap = unIOBitmap . fromIOBitmap4
--------------------------------------------------------------------------------
-- | Newtypes for mutable bitmaps with a fixed number of channels (components per pixel)
newtype IOBitmap1 t = IOBitmap1 { fromIOBitmap1 :: IOBitmap t }
newtype IOBitmap2 t = IOBitmap2 { fromIOBitmap2 :: IOBitmap t }
newtype IOBitmap3 t = IOBitmap3 { fromIOBitmap3 :: IOBitmap t }
newtype IOBitmap4 t = IOBitmap4 { fromIOBitmap4 :: IOBitmap t }
ioBitmap1 :: IOBitmap t -> IOBitmap1 t
ioBitmap2 :: IOBitmap t -> IOBitmap2 t
ioBitmap3 :: IOBitmap t -> IOBitmap3 t
ioBitmap4 :: IOBitmap t -> IOBitmap4 t
ioBitmap1 bm = if bitmapNChannels bm == 1 then IOBitmap1 bm else error "bitmap/ioBitmap1: number of channels is not 1"
ioBitmap2 bm = if bitmapNChannels bm == 2 then IOBitmap2 bm else error "bitmap/ioBitmap2: number of channels is not 2"
ioBitmap3 bm = if bitmapNChannels bm == 3 then IOBitmap3 bm else error "bitmap/ioBitmap3: number of channels is not 3"
ioBitmap4 bm = if bitmapNChannels bm == 4 then IOBitmap4 bm else error "bitmap/ioBitmap4: number of channels is not 4"
--------------------------------------------------------------------------------
unsafeReadPixel1 :: PixelComponent t => IOBitmap1 t -> Offset -> IO t
unsafeReadPixel2 :: PixelComponent t => IOBitmap2 t -> Offset -> IO (t,t)
unsafeReadPixel3 :: PixelComponent t => IOBitmap3 t -> Offset -> IO (t,t,t)
unsafeReadPixel4 :: PixelComponent t => IOBitmap4 t -> Offset -> IO (t,t,t,t)
unsafeWritePixel1 :: PixelComponent t => IOBitmap1 t -> Offset -> t -> IO ()
unsafeWritePixel2 :: PixelComponent t => IOBitmap2 t -> Offset -> (t,t) -> IO ()
unsafeWritePixel3 :: PixelComponent t => IOBitmap3 t -> Offset -> (t,t,t) -> IO ()
unsafeWritePixel4 :: PixelComponent t => IOBitmap4 t -> Offset -> (t,t,t,t) -> IO ()
unsafeReadPixel1 bm xy = withComponentPtr (fromIOBitmap1 bm) xy 0 $ \p -> liftM (\[x] -> x ) $ peekArray 1 p
unsafeReadPixel2 bm xy = withComponentPtr (fromIOBitmap2 bm) xy 0 $ \p -> liftM (\[x,y] -> (x,y) ) $ peekArray 2 p
unsafeReadPixel3 bm xy = withComponentPtr (fromIOBitmap3 bm) xy 0 $ \p -> liftM (\[x,y,z] -> (x,y,z) ) $ peekArray 3 p
unsafeReadPixel4 bm xy = withComponentPtr (fromIOBitmap4 bm) xy 0 $ \p -> liftM (\[x,y,z,w] -> (x,y,z,w)) $ peekArray 4 p
unsafeWritePixel1 bm xy x = withComponentPtr (fromIOBitmap1 bm) xy 0 $ \q -> pokeArray q [x]
unsafeWritePixel2 bm xy (x,y) = withComponentPtr (fromIOBitmap2 bm) xy 0 $ \q -> pokeArray q [x,y]
unsafeWritePixel3 bm xy (x,y,z) = withComponentPtr (fromIOBitmap3 bm) xy 0 $ \q -> pokeArray q [x,y,z]
unsafeWritePixel4 bm xy (x,y,z,w) = withComponentPtr (fromIOBitmap4 bm) xy 0 $ \q -> pokeArray q [x,y,z,w]
--------------------------------------------------------------------------------
-- restricted type
{-# SPECIALIZE myPlusPtr :: Ptr Word8 -> Int -> Ptr Word8 #-}
{-# SPECIALIZE myPlusPtr :: Ptr Float -> Int -> Ptr Float #-}
myPlusPtr :: Ptr a -> Int -> Ptr a
myPlusPtr = plusPtr
--------------------------------------------------------------------------------