bitmap-0.0.2: Data/Bitmap/Pure.hs
--------------------------------------------------------------------------------
-- Module : Data.Bitmap.Pure
-- 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
--------------------------------------------------------------------------------
-- | The pure, inmutable API.
{-# LANGUAGE CPP #-}
module Data.Bitmap.Pure
(
module Data.Bitmap.Base
-- * Creating bitmaps
, emptyBitmap
, cloneBitmap
, emptyCloneBitmap
, createSingleChannelBitmap
, bitmapFromForeignPtrUnsafe
-- * Using bitmaps
, withBitmap
-- * Mapping over bitmaps
, componentMap
, componentMap'
-- * Cropping and extending
, copySubImage
, copySubImage'
-- * Flipping and mirroring
, flipBitmap
, mirrorBitmap
-- * Casting
, castBitmap
-- , castChannel
-- * Manipulating channels
, combineChannels
, extractChannels
, extractSingleChannel
-- * Bilinear resampling
, bilinearResample
, bilinearResampleChannel
-- * Blending
, blendBitmaps
, blendChannels
-- * Gamma correction
, powerlawGammaCorrection
, powerlawGammaCorrectionChannel
{-
-- * Conversion to ByteString
, bitmapToByteString
-}
)
where
--------------------------------------------------------------------------------
import Data.Word
-- import Foreign.ForeignPtr
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import Data.Bitmap.Base
import Data.Bitmap.Internal
import qualified Data.Bitmap.IO as IO
import System.IO.Unsafe
--------------------------------------------------------------------------------
-- | A bitmap filled with zero values.
-- Note: we /cannot/ guarantee the alignment
-- of the memory block (but typically it is aligned at least to machine word boundary),
-- but what we /can/ guarantee is that the rows are properly padded.
emptyBitmap
:: PixelComponent t
=> Size -- ^ (width,height)
-> NChn -- ^ number of channels (components\/pixel)
-> Maybe Alignment -- ^ the row alignment of the new image
-> Bitmap t
emptyBitmap siz nchn malign = unIOBitmap $ unsafePerformIO $ IO.newIOBitmap siz nchn malign
-- | Creates a single channel bitmap from a function.
-- This is probably a bit slow.
createSingleChannelBitmap
:: PixelComponent t
=> Size -- ^ (width,height)
-> Maybe Alignment -- ^ the row alignment of the new image
-> (Int -> Int -> t) -- ^ the function used to create the bitmap
-> Bitmap t
createSingleChannelBitmap siz maling fun = unIOBitmap $ unsafePerformIO $
IO.createSingleChannelBitmap siz maling fun
-- | Creates an empty bitmap with the same properties as the source.
emptyCloneBitmap
:: PixelComponent t
=> Bitmap t -- ^ source (only dimensions and such is used)
-> Maybe Alignment -- ^ target alignment
-> Bitmap t -- ^ new empty bitmap
emptyCloneBitmap bm1 malign = unIOBitmap $ unsafePerformIO $
IO.emptyCloneBitmap (IOBitmap bm1) malign
-- | Clones a bitmap. The only effect of this in the pure
-- setting should be that the alignment/padding can change.
-- You shouldn't normally use this function.
cloneBitmap
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Maybe Alignment -- ^ target alignment
-> Bitmap t
cloneBitmap bm1 malign = unIOBitmap $ unsafePerformIO $
IO.cloneBitmap (IOBitmap bm1) malign
--------------------------------------------------------------------------------
-- | Warning: this is probably slow.
componentMap :: PixelComponent s => (s -> s) -> Bitmap s -> Bitmap s
componentMap f bm = unIOBitmap $ unsafePerformIO $
IO.componentMap f (IOBitmap bm)
-- | Warning: this is probably slow.
componentMap' :: (PixelComponent s, PixelComponent t) => (s -> t) -> Bitmap s -> Maybe Alignment -> Bitmap t
componentMap' f bm malign = unIOBitmap $ unsafePerformIO $
IO.componentMap' f (IOBitmap bm) malign
--------------------------------------------------------------------------------
-- | Copies a subrectangle of the source image into a new image.
copySubImage
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Offset -- ^ source rectangle offset
-> Size -- ^ source rectangle size
-> Bitmap t
copySubImage bm ofs siz = unIOBitmap $ unsafePerformIO $
IO.copySubImage (IOBitmap bm) ofs siz
-- | Copy into a new \"black\" bitmap; common generalization of crop and extend.
copySubImage'
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Offset -- ^ source rectangle offset
-> Size -- ^ source rectangle size
-> Size -- ^ target image size
-> Offset -- ^ target rectangle offset
-> Bitmap t
copySubImage' bm1 ofs1 rsiz tsiz ofs2 = unIOBitmap $ unsafePerformIO $
IO.copySubImage' (IOBitmap bm1) ofs1 rsiz tsiz ofs2
--------------------------------------------------------------------------------
-- | Flips the bitmap vertically.
flipBitmap
:: PixelComponent t
=> Bitmap t
-> Maybe Alignment
-> Bitmap t
flipBitmap bm malign = unIOBitmap $ unsafePerformIO $ IO.flipBitmap (IOBitmap bm) malign
-- | Flips the bitmap horizontally.
mirrorBitmap
:: PixelComponent t
=> Bitmap t
-> Maybe Alignment
-> Bitmap t
mirrorBitmap bm malign = unIOBitmap $ unsafePerformIO $ IO.mirrorBitmap (IOBitmap bm) malign
--------------------------------------------------------------------------------
-- | Converts between different component types.
castBitmap
:: (PixelComponent s, PixelComponent t)
=> Bitmap s -- ^ source image
-> Maybe Alignment -- ^ target image row alignment
-> Bitmap t
castBitmap bm1 malign = unIOBitmap $ unsafePerformIO $
IO.castBitmap (IOBitmap bm1) malign
--------------------------------------------------------------------------------
extractSingleChannel
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Maybe Alignment -- ^ target image row alignment
-> Int -- ^ source channel index
-> Bitmap t
extractSingleChannel bm1 malign j = unIOBitmap $ unsafePerformIO $
IO.extractSingleChannel (IOBitmap bm1) malign j
extractChannels :: PixelComponent t => Bitmap t -> Maybe Alignment -> [Bitmap t]
extractChannels bm malign = map unIOBitmap $ unsafePerformIO $
IO.extractChannels (IOBitmap bm) malign
combineChannels :: PixelComponent t => [Bitmap t] -> Maybe Alignment -> Bitmap t
combineChannels bms malign = unIOBitmap $ unsafePerformIO $
IO.combineChannels (map IOBitmap bms) malign
--------------------------------------------------------------------------------
bilinearResample
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Size -- ^ target image size
-> Maybe Alignment -- ^ target image row alignment
-> Bitmap t
bilinearResample bm siz malign = unIOBitmap $ unsafePerformIO $
IO.bilinearResample (IOBitmap bm) siz malign
bilinearResampleChannel
:: PixelComponent t
=> Bitmap t -- ^ source image
-> Int -- ^ source channel indexe
-> Size -- ^ target image size
-> Maybe Alignment -- ^ target image row alignment
-> Bitmap t
bilinearResampleChannel bm j siz malign = unIOBitmap $ unsafePerformIO $
IO.bilinearResampleChannel (IOBitmap bm) j siz malign
--------------------------------------------------------------------------------
-- | Blends two bitmaps with the given weights; that is, the result is
-- the specified linear combination. If the values are outside the allowed
-- range (this can happen with the Word8, Word16, Word32 types and weights
-- whose sum is bigger than 1, or with a negative weight), then they are
-- clipped. The clipping /does not/ happen with the Float component type.
blendBitmaps
:: PixelComponent t
=> Float -- ^ weight 1
-> Float -- ^ weight 2
-> Bitmap t -- ^ source image 1
-> Bitmap t -- ^ source image 2
-> Maybe Alignment -- ^ target alignment
-> Bitmap t
blendBitmaps w1 w2 bm1 bm2 malign = unIOBitmap $ unsafePerformIO $
IO.blendBitmaps w1 w2 (IOBitmap bm1) (IOBitmap bm2) malign
blendChannels
:: PixelComponent t
=> Float -- ^ weight 1
-> Float -- ^ weight 2
-> Bitmap t -- ^ source image 1
-> Int -- ^ channel index 1
-> Bitmap t -- ^ source image 2
-> Int -- ^ channel index 2
-> Maybe Alignment -- ^ target alignment
-> Bitmap t
blendChannels w1 w2 bm1 ofs1 bm2 ofs2 malign = unIOBitmap $ unsafePerformIO $
IO.blendChannels w1 w2 (IOBitmap bm1) ofs1 (IOBitmap bm2) ofs2 malign
--------------------------------------------------------------------------------
-- | This is equivalent to @componentMap (\c -> c^gamma)@, except that
-- @(^)@ is defined only for integral exponents; but should be faster anyway.
powerlawGammaCorrection
:: PixelComponent t
=> Float -- ^ gamma
-> Bitmap t -- ^ source image
-> Maybe Alignment -- ^ target image row alignment
-> Bitmap t
powerlawGammaCorrection gamma bm malign = unIOBitmap $ unsafePerformIO $
IO.powerlawGammaCorrection gamma (IOBitmap bm) malign
powerlawGammaCorrectionChannel
:: PixelComponent t
=> Float -- ^ gamma
-> Bitmap t -- ^ source image
-> Int -- ^ source channel indexe
-> Maybe Alignment -- ^ target image row alignment
-> Bitmap t
powerlawGammaCorrectionChannel gamma bm j malign = unIOBitmap $ unsafePerformIO $
IO.powerlawGammaCorrectionChannel gamma (IOBitmap bm) j malign
--------------------------------------------------------------------------------
{-
-- | Note that the data is /shared/; and also that the resulting ByteString
-- is encoded using the host machine's endianness.
bitmapToByteString :: PixelComponent t => Bitmap t -> ByteString
bitmapToByteString bm = bs where
bs = B.fromForeignPtr (castForeignPtr $ bitmapPtr bm) 0 n
n = bitmapSizeInBytes bm
-}
{-
-- | As its name says, this pretty much unsafe!
reallyUnsafeBitmapFromByteString :: ByteString -> Size -> NChn -> Padding -> Bitmap t
reallyUnsafeBitmapFromByteString bs siz nchn pad =
if n > len || ofs /= 0
then error "reallyUnsafeBitmapFromByteString: better than segfault :)"
else bm
where
bm = Bitmap
{ bitmapSize = siz
, bitmapNChannels = nchn
, bitmapPtr = fptr
, bitmapRowPadding = pad
, bitmapRowAlignment = 1
} :: Bitmap t
n = bitmapSizeInBytes bm
(fptr,ofs,len) = B.toForeignPtr bm
-}
--------------------------------------------------------------------------------