module Codec.BMP.BitmapInfoV4
( BitmapInfoV4 (..)
, CIEXYZ (..)
, sizeOfBitmapInfoV4
, checkBitmapInfoV4
, imageSizeFromBitmapInfoV4)
where
import Codec.BMP.Error
import Codec.BMP.CIEXYZ
import Codec.BMP.BitmapInfoV3
import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
data BitmapInfoV4
= BitmapInfoV4
{
dib4InfoV3 :: BitmapInfoV3
, dib4RedMask :: Word32
, dib4GreenMask :: Word32
, dib4BlueMask :: Word32
, dib4AlphaMask :: Word32
, dib4ColorSpaceType :: Word32
, dib4Endpoints :: (CIEXYZ, CIEXYZ, CIEXYZ)
, dib4GammaRed :: Word32
, dib4GammaGreen :: Word32
, dib4GammaBlue :: Word32
}
deriving (Show)
sizeOfBitmapInfoV4 :: Int
sizeOfBitmapInfoV4 = 108
instance Binary BitmapInfoV4 where
get
= do infoV3 <- get
rmask <- getWord32le
gmask <- getWord32le
bmask <- getWord32le
amask <- getWord32le
cstype <- getWord32le
ends <- get
rgamma <- getWord32le
ggamma <- getWord32le
bgamma <- getWord32le
return $ BitmapInfoV4
{ dib4InfoV3 = infoV3
, dib4RedMask = rmask
, dib4GreenMask = gmask
, dib4BlueMask = bmask
, dib4AlphaMask = amask
, dib4ColorSpaceType = cstype
, dib4Endpoints = ends
, dib4GammaRed = rgamma
, dib4GammaGreen = ggamma
, dib4GammaBlue = bgamma }
put header
= do put $ dib4InfoV3 header
putWord32le $ dib4RedMask header
putWord32le $ dib4GreenMask header
putWord32le $ dib4BlueMask header
putWord32le $ dib4AlphaMask header
putWord32le $ dib4ColorSpaceType header
put $ dib4Endpoints header
putWord32le $ dib4GammaRed header
putWord32le $ dib4GammaGreen header
putWord32le $ dib4GammaBlue header
checkBitmapInfoV4 :: BitmapInfoV4 -> Word32 -> Maybe Error
checkBitmapInfoV4 headerV4 physicalBufferSize
| dib3Planes headerV3 /= 1
= Just $ ErrorUnhandledPlanesCount $ dib3Planes headerV3
| dib3BitCount headerV3 /= 24
, dib3BitCount headerV3 /= 32
= Just $ ErrorUnhandledColorDepth $ dib3BitCount headerV3
| headerImageSize <- dib3ImageSize headerV3
, headerImageSize /= 0
, physicalBufferSize < headerImageSize
= Just $ ErrorImagePhysicalSizeMismatch
headerImageSize physicalBufferSize
| Just calculatedImageSize <- imageSizeFromBitmapInfoV4 headerV4
, fromIntegral physicalBufferSize < calculatedImageSize
= Just $ ErrorImageDataTruncated
calculatedImageSize
(fromIntegral physicalBufferSize)
| dib3BitCount headerV3 == 32
, dib3Compression headerV3 == CompressionRGB
= Nothing
| dib3BitCount headerV3 == 32
, dib3Compression headerV3 == CompressionBitFields
, dib4AlphaMask headerV4 == 0xff000000
, dib4RedMask headerV4 == 0x00ff0000
, dib4GreenMask headerV4 == 0x0000ff00
, dib4BlueMask headerV4 == 0x000000ff
= Nothing
| dib3BitCount headerV3 == 24
, dib3Compression headerV3 == CompressionRGB
= Nothing
| otherwise
= Just $ ErrorUnhandledCompressionMode (dib3Compression headerV3)
where headerV3 = dib4InfoV3 headerV4
imageSizeFromBitmapInfoV4 :: BitmapInfoV4 -> Maybe Int
imageSizeFromBitmapInfoV4 headerV4
| dib3BitCount headerV3 == 32
, dib3Planes headerV3 == 1
, dib3Compression headerV3 == CompressionRGB
= Just $ fromIntegral (dib3Width headerV3 * dib3Height headerV3 * 4)
| dib3BitCount headerV3 == 32
, dib3Planes headerV3 == 1
, dib3Compression headerV3 == CompressionBitFields
, dib4AlphaMask headerV4 == 0xff000000
, dib4RedMask headerV4 == 0x00ff0000
, dib4GreenMask headerV4 == 0x0000ff00
, dib4BlueMask headerV4 == 0x000000ff
= Just $ fromIntegral (dib3Width headerV3 * dib3Height headerV3 * 4)
| dib3BitCount headerV3 == 24
, dib3Planes headerV3 == 1
, dib3Compression headerV3 == CompressionRGB
= let imageBytesPerLine = dib3Width headerV3 * 3
tailBytesPerLine = imageBytesPerLine `mod` 4
padBytesPerLine = if tailBytesPerLine > 0
then 4 tailBytesPerLine
else 0
in Just $ fromIntegral
$ dib3Height headerV3 * imageBytesPerLine + padBytesPerLine
| otherwise
= Nothing
where headerV3 = dib4InfoV3 headerV4