{-# OPTIONS_HADDOCK hide #-}
module Codec.BMP.Unpack
(unpackBMPToRGBA32)
where
import Codec.BMP.Base
import Codec.BMP.BitmapInfo
import Codec.BMP.BitmapInfoV3
import Foreign.Ptr
import Foreign.Marshal.Alloc
import Foreign.Storable
import System.IO.Unsafe
import Data.Word
import Data.ByteString as BS
import Data.ByteString.Unsafe as BS
import Prelude as P
unpackBMPToRGBA32 :: BMP -> ByteString
unpackBMPToRGBA32 :: BMP -> ByteString
unpackBMPToRGBA32 BMP
bmp
= let info :: BitmapInfoV3
info = BitmapInfo -> BitmapInfoV3
getBitmapInfoV3 (BitmapInfo -> BitmapInfoV3) -> BitmapInfo -> BitmapInfoV3
forall a b. (a -> b) -> a -> b
$ BMP -> BitmapInfo
bmpBitmapInfo BMP
bmp
width :: Int
width = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int) -> Word32 -> Int
forall a b. (a -> b) -> a -> b
$ BitmapInfoV3 -> Word32
dib3Width BitmapInfoV3
info
height :: Int
height = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int) -> Word32 -> Int
forall a b. (a -> b) -> a -> b
$ BitmapInfoV3 -> Word32
dib3Height BitmapInfoV3
info
flipX :: Bool
flipX = BitmapInfoV3 -> Bool
dib3HeightFlipped BitmapInfoV3
info
bitCount :: Word16
bitCount = BitmapInfoV3 -> Word16
dib3BitCount BitmapInfoV3
info
in case Word16
bitCount of
Word16
24 -> Int -> Int -> Bool -> ByteString -> ByteString
packRGB24ToRGBA32 Int
width Int
height Bool
flipX (BMP -> ByteString
bmpRawImageData BMP
bmp)
Word16
32 -> Int -> Int -> Bool -> ByteString -> ByteString
packRGB32ToRGBA32 Int
width Int
height Bool
flipX (BMP -> ByteString
bmpRawImageData BMP
bmp)
Word16
_ -> [Char] -> ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"Codec.BMP: Unhandled bitcount."
packRGB24ToRGBA32
:: Int
-> Int
-> Bool
-> ByteString
-> ByteString
packRGB24ToRGBA32 :: Int -> Int -> Bool -> ByteString -> ByteString
packRGB24ToRGBA32 Int
width Int
height Bool
flipX ByteString
str
= let
srcBytesPerLine :: Int
srcBytesPerLine = ByteString -> Int
BS.length ByteString
str Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
height
sizeDest :: Int
sizeDest = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
height Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4
in if ByteString -> Int
BS.length ByteString
str Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
height Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
srcBytesPerLine
then [Char] -> ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"Codec.BMP: Image data is truncated."
else IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO
(IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
sizeDest ((Ptr CChar -> IO ByteString) -> IO ByteString)
-> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
bufDest ->
ByteString -> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
BS.unsafeUseAsCString ByteString
str ((Ptr CChar -> IO ByteString) -> IO ByteString)
-> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
bufSrc ->
do Int -> Int -> Bool -> Int -> Ptr Any -> Ptr Any -> IO ()
forall {b} {b}.
Int -> Int -> Bool -> Int -> Ptr b -> Ptr b -> IO ()
packRGB24ToRGBA32'
Int
width Int
height Bool
flipX
Int
srcBytesPerLine
(Ptr CChar -> Ptr Any
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
bufSrc) (Ptr CChar -> Ptr Any
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
bufDest)
CStringLen -> IO ByteString
packCStringLen (Ptr CChar
bufDest, Int
sizeDest)
packRGB24ToRGBA32' :: Int -> Int -> Bool -> Int -> Ptr b -> Ptr b -> IO ()
packRGB24ToRGBA32' Int
width Int
height Bool
flipX Int
srcBytesPerLine Ptr b
ptrSrc Ptr b
ptrDst
= Int -> IO ()
go Int
0
where
go :: Int -> IO ()
go Int
posY
| Int
posY Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
height
= () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
flipX
= let !oSrc :: Int
oSrc = Int
srcBytesPerLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
height Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
posY)
!oDst :: Int
oDst = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
in Int -> Int -> Int -> Int -> IO ()
go_line Int
0 Int
posY Int
oSrc Int
oDst
| Bool
otherwise
= let !oSrc :: Int
oSrc = Int
srcBytesPerLine Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
!oDst :: Int
oDst = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
in Int -> Int -> Int -> Int -> IO ()
go_line Int
0 Int
posY Int
oSrc Int
oDst
go_line :: Int -> Int -> Int -> Int -> IO ()
go_line Int
posX Int
posY Int
oSrc Int
oDst
| Int
posX Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
width
= Int -> IO ()
go (Int
posY Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
| Bool
otherwise
= do Word8
blue :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
0)
Word8
green :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Word8
red :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
0) Word8
red
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Word8
green
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Word8
blue
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) (Word8
255 :: Word8)
Int -> Int -> Int -> Int -> IO ()
go_line (Int
posX Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
posY (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)
packRGB32ToRGBA32
:: Int
-> Int
-> Bool
-> ByteString
-> ByteString
packRGB32ToRGBA32 :: Int -> Int -> Bool -> ByteString -> ByteString
packRGB32ToRGBA32 Int
width Int
height Bool
flipX ByteString
str
= let sizeDest :: Int
sizeDest = Int
height Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4
in if ByteString -> Int
BS.length ByteString
str Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
sizeDest
then [Char] -> ByteString
forall a. HasCallStack => [Char] -> a
error [Char]
"Codec.BMP: Image data is truncated."
else IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO
(IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
sizeDest ((Ptr CChar -> IO ByteString) -> IO ByteString)
-> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
bufDest ->
ByteString -> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
BS.unsafeUseAsCString ByteString
str ((Ptr CChar -> IO ByteString) -> IO ByteString)
-> (Ptr CChar -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
bufSrc ->
do Int -> Int -> Bool -> Ptr Any -> Ptr Any -> IO ()
forall {b} {b}. Int -> Int -> Bool -> Ptr b -> Ptr b -> IO ()
packRGB32ToRGBA32' Int
width Int
height
Bool
flipX
(Ptr CChar -> Ptr Any
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
bufSrc) (Ptr CChar -> Ptr Any
forall a b. Ptr a -> Ptr b
castPtr Ptr CChar
bufDest)
CStringLen -> IO ByteString
packCStringLen (Ptr CChar
bufDest, Int
sizeDest)
packRGB32ToRGBA32' :: Int -> Int -> Bool -> Ptr b -> Ptr b -> IO ()
packRGB32ToRGBA32' Int
width Int
height Bool
flipX Ptr b
ptrSrc Ptr b
ptrDst
= Int -> IO ()
go Int
0
where
go :: Int -> IO ()
go Int
posY
| Int
posY Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
height
= () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
| Bool
flipX
= let !oSrc :: Int
oSrc = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
height Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
posY)
!oDst :: Int
oDst = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
in Int -> Int -> Int -> Int -> IO ()
go_line Int
0 Int
posY Int
oSrc Int
oDst
| Bool
otherwise
= let !oSrc :: Int
oSrc = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
!oDst :: Int
oDst = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
posY
in Int -> Int -> Int -> Int -> IO ()
go_line Int
0 Int
posY Int
oSrc Int
oDst
go_line :: Int -> Int -> Int -> Int -> IO ()
go_line Int
posX Int
posY Int
oSrc Int
oDst
| Int
posX Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
width
= Int -> IO ()
go (Int
posY Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
| Bool
otherwise
= do Word8
blue :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
0)
Word8
green :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Word8
red :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)
Word8
alpha :: Word8 <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptrSrc (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3)
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
0) Word8
red
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Word8
green
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Word8
blue
Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptrDst (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) Word8
alpha
Int -> Int -> Int -> Int -> IO ()
go_line (Int
posX Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
posY (Int
oSrc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) (Int
oDst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4)