{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module Codec.Picture.Tiff.Internal.Types
( BinaryParam( .. )
, Endianness( .. )
, TiffHeader( .. )
, TiffPlanarConfiguration( .. )
, TiffCompression( .. )
, IfdType( .. )
, TiffColorspace( .. )
, TiffSampleFormat( .. )
, ImageFileDirectory( .. )
, ExtraSample( .. )
, Predictor( .. )
, planarConfgOfConstant
, constantToPlaneConfiguration
, unpackSampleFormat
, packSampleFormat
, word16OfTag
, unpackPhotometricInterpretation
, packPhotometricInterpretation
, codeOfExtraSample
, unPackCompression
, packCompression
, predictorOfConstant
) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative( (<$>), (<*>), pure )
#endif
import Control.Monad( forM_, when, replicateM, )
import Data.Bits( (.&.), unsafeShiftR )
import Data.Binary( Binary( .. ) )
import Data.Binary.Get( Get
, getWord16le, getWord16be
, getWord32le, getWord32be
, bytesRead
, skip
, getByteString
)
import Data.Binary.Put( Put
, putWord16le, putWord16be
, putWord32le, putWord32be
, putByteString
)
import Data.Function( on )
import Data.List( sortBy, mapAccumL )
import qualified Data.Vector as V
import qualified Data.ByteString as B
import Data.Int( Int32 )
import Data.Word( Word8, Word16, Word32 )
import Codec.Picture.Metadata.Exif
data Endianness
= EndianLittle
| EndianBig
deriving (Endianness -> Endianness -> Bool
(Endianness -> Endianness -> Bool)
-> (Endianness -> Endianness -> Bool) -> Eq Endianness
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Endianness -> Endianness -> Bool
$c/= :: Endianness -> Endianness -> Bool
== :: Endianness -> Endianness -> Bool
$c== :: Endianness -> Endianness -> Bool
Eq, Int -> Endianness -> ShowS
[Endianness] -> ShowS
Endianness -> String
(Int -> Endianness -> ShowS)
-> (Endianness -> String)
-> ([Endianness] -> ShowS)
-> Show Endianness
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Endianness] -> ShowS
$cshowList :: [Endianness] -> ShowS
show :: Endianness -> String
$cshow :: Endianness -> String
showsPrec :: Int -> Endianness -> ShowS
$cshowsPrec :: Int -> Endianness -> ShowS
Show)
instance Binary Endianness where
put :: Endianness -> Put
put Endianness
EndianLittle = Word16 -> Put
putWord16le Word16
0x4949
put Endianness
EndianBig = Word16 -> Put
putWord16le Word16
0x4D4D
get :: Get Endianness
get = do
Word16
tag <- Get Word16
getWord16le
case Word16
tag of
Word16
0x4949 -> Endianness -> Get Endianness
forall (m :: * -> *) a. Monad m => a -> m a
return Endianness
EndianLittle
Word16
0x4D4D -> Endianness -> Get Endianness
forall (m :: * -> *) a. Monad m => a -> m a
return Endianness
EndianBig
Word16
_ -> String -> Get Endianness
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid endian tag value"
class BinaryParam a b where
getP :: a -> Get b
putP :: a -> b -> Put
data =
{ TiffHeader -> Endianness
hdrEndianness :: !Endianness
, TiffHeader -> Word32
hdrOffset :: {-# UNPACK #-} !Word32
}
deriving (TiffHeader -> TiffHeader -> Bool
(TiffHeader -> TiffHeader -> Bool)
-> (TiffHeader -> TiffHeader -> Bool) -> Eq TiffHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TiffHeader -> TiffHeader -> Bool
$c/= :: TiffHeader -> TiffHeader -> Bool
== :: TiffHeader -> TiffHeader -> Bool
$c== :: TiffHeader -> TiffHeader -> Bool
Eq, Int -> TiffHeader -> ShowS
[TiffHeader] -> ShowS
TiffHeader -> String
(Int -> TiffHeader -> ShowS)
-> (TiffHeader -> String)
-> ([TiffHeader] -> ShowS)
-> Show TiffHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TiffHeader] -> ShowS
$cshowList :: [TiffHeader] -> ShowS
show :: TiffHeader -> String
$cshow :: TiffHeader -> String
showsPrec :: Int -> TiffHeader -> ShowS
$cshowsPrec :: Int -> TiffHeader -> ShowS
Show)
instance BinaryParam Endianness Word16 where
putP :: Endianness -> Word16 -> Put
putP Endianness
EndianLittle = Word16 -> Put
putWord16le
putP Endianness
EndianBig = Word16 -> Put
putWord16be
getP :: Endianness -> Get Word16
getP Endianness
EndianLittle = Get Word16
getWord16le
getP Endianness
EndianBig = Get Word16
getWord16be
instance BinaryParam Endianness Int32 where
putP :: Endianness -> Int32 -> Put
putP Endianness
en Int32
v = Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
en (Word32 -> Put) -> Word32 -> Put
forall a b. (a -> b) -> a -> b
$ (Int32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
v :: Word32)
getP :: Endianness -> Get Int32
getP Endianness
en = Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Get Word32 -> Get Int32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Endianness -> Get Word32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
en :: Get Word32)
instance BinaryParam Endianness Word32 where
putP :: Endianness -> Word32 -> Put
putP Endianness
EndianLittle = Word32 -> Put
putWord32le
putP Endianness
EndianBig = Word32 -> Put
putWord32be
getP :: Endianness -> Get Word32
getP Endianness
EndianLittle = Get Word32
getWord32le
getP Endianness
EndianBig = Get Word32
getWord32be
instance Binary TiffHeader where
put :: TiffHeader -> Put
put TiffHeader
hdr = do
let endian :: Endianness
endian = TiffHeader -> Endianness
hdrEndianness TiffHeader
hdr
Endianness -> Put
forall t. Binary t => t -> Put
put Endianness
endian
Endianness -> Word16 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endian (Word16
42 :: Word16)
Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endian (Word32 -> Put) -> Word32 -> Put
forall a b. (a -> b) -> a -> b
$ TiffHeader -> Word32
hdrOffset TiffHeader
hdr
get :: Get TiffHeader
get = do
Endianness
endian <- Get Endianness
forall t. Binary t => Get t
get
Word16
magic <- Endianness -> Get Word16
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endian
let magicValue :: Word16
magicValue = Word16
42 :: Word16
Bool -> Get () -> Get ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word16
magic Word16 -> Word16 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word16
magicValue)
(String -> Get ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid TIFF magic number")
Endianness -> Word32 -> TiffHeader
TiffHeader Endianness
endian (Word32 -> TiffHeader) -> Get Word32 -> Get TiffHeader
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get Word32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endian
data TiffPlanarConfiguration
= PlanarConfigContig
| PlanarConfigSeparate
planarConfgOfConstant :: Word32 -> Get TiffPlanarConfiguration
planarConfgOfConstant :: Word32 -> Get TiffPlanarConfiguration
planarConfgOfConstant Word32
0 = TiffPlanarConfiguration -> Get TiffPlanarConfiguration
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffPlanarConfiguration
PlanarConfigContig
planarConfgOfConstant Word32
1 = TiffPlanarConfiguration -> Get TiffPlanarConfiguration
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffPlanarConfiguration
PlanarConfigContig
planarConfgOfConstant Word32
2 = TiffPlanarConfiguration -> Get TiffPlanarConfiguration
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffPlanarConfiguration
PlanarConfigSeparate
planarConfgOfConstant Word32
v = String -> Get TiffPlanarConfiguration
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get TiffPlanarConfiguration)
-> String -> Get TiffPlanarConfiguration
forall a b. (a -> b) -> a -> b
$ String
"Unknown planar constant (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
constantToPlaneConfiguration :: TiffPlanarConfiguration -> Word16
constantToPlaneConfiguration :: TiffPlanarConfiguration -> Word16
constantToPlaneConfiguration TiffPlanarConfiguration
PlanarConfigContig = Word16
1
constantToPlaneConfiguration TiffPlanarConfiguration
PlanarConfigSeparate = Word16
2
data TiffCompression
= CompressionNone
| CompressionModifiedRLE
| CompressionLZW
| CompressionJPEG
| CompressionPackBit
data IfdType
= TypeByte
| TypeAscii
| TypeShort
| TypeLong
| TypeRational
| TypeSByte
| TypeUndefined
| TypeSignedShort
| TypeSignedLong
| TypeSignedRational
| TypeFloat
| TypeDouble
deriving Int -> IfdType -> ShowS
[IfdType] -> ShowS
IfdType -> String
(Int -> IfdType -> ShowS)
-> (IfdType -> String) -> ([IfdType] -> ShowS) -> Show IfdType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IfdType] -> ShowS
$cshowList :: [IfdType] -> ShowS
show :: IfdType -> String
$cshow :: IfdType -> String
showsPrec :: Int -> IfdType -> ShowS
$cshowsPrec :: Int -> IfdType -> ShowS
Show
instance BinaryParam Endianness IfdType where
getP :: Endianness -> Get IfdType
getP Endianness
endianness = Endianness -> Get Word16
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness Get Word16 -> (Word16 -> Get IfdType) -> Get IfdType
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Word16 -> Get IfdType
conv where
conv :: Word16 -> Get IfdType
conv :: Word16 -> Get IfdType
conv Word16
v = case Word16
v of
Word16
1 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeByte
Word16
2 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeAscii
Word16
3 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeShort
Word16
4 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeLong
Word16
5 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeRational
Word16
6 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeSByte
Word16
7 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeUndefined
Word16
8 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeSignedShort
Word16
9 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeSignedLong
Word16
10 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeSignedRational
Word16
11 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeFloat
Word16
12 -> IfdType -> Get IfdType
forall (m :: * -> *) a. Monad m => a -> m a
return IfdType
TypeDouble
Word16
_ -> String -> Get IfdType
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid TIF directory type"
putP :: Endianness -> IfdType -> Put
putP Endianness
endianness = Endianness -> Word16 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness (Word16 -> Put) -> (IfdType -> Word16) -> IfdType -> Put
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IfdType -> Word16
conv where
conv :: IfdType -> Word16
conv :: IfdType -> Word16
conv IfdType
v = case IfdType
v of
IfdType
TypeByte -> Word16
1
IfdType
TypeAscii -> Word16
2
IfdType
TypeShort -> Word16
3
IfdType
TypeLong -> Word16
4
IfdType
TypeRational -> Word16
5
IfdType
TypeSByte -> Word16
6
IfdType
TypeUndefined -> Word16
7
IfdType
TypeSignedShort -> Word16
8
IfdType
TypeSignedLong -> Word16
9
IfdType
TypeSignedRational -> Word16
10
IfdType
TypeFloat -> Word16
11
IfdType
TypeDouble -> Word16
12
instance BinaryParam Endianness ExifTag where
getP :: Endianness -> Get ExifTag
getP Endianness
endianness = Word16 -> ExifTag
tagOfWord16 (Word16 -> ExifTag) -> Get Word16 -> Get ExifTag
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get Word16
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness
putP :: Endianness -> ExifTag -> Put
putP Endianness
endianness = Endianness -> Word16 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness (Word16 -> Put) -> (ExifTag -> Word16) -> ExifTag -> Put
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExifTag -> Word16
word16OfTag
data Predictor
= PredictorNone
| PredictorHorizontalDifferencing
deriving Predictor -> Predictor -> Bool
(Predictor -> Predictor -> Bool)
-> (Predictor -> Predictor -> Bool) -> Eq Predictor
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Predictor -> Predictor -> Bool
$c/= :: Predictor -> Predictor -> Bool
== :: Predictor -> Predictor -> Bool
$c== :: Predictor -> Predictor -> Bool
Eq
predictorOfConstant :: Word32 -> Get Predictor
predictorOfConstant :: Word32 -> Get Predictor
predictorOfConstant Word32
1 = Predictor -> Get Predictor
forall (f :: * -> *) a. Applicative f => a -> f a
pure Predictor
PredictorNone
predictorOfConstant Word32
2 = Predictor -> Get Predictor
forall (f :: * -> *) a. Applicative f => a -> f a
pure Predictor
PredictorHorizontalDifferencing
predictorOfConstant Word32
v = String -> Get Predictor
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get Predictor) -> String -> Get Predictor
forall a b. (a -> b) -> a -> b
$ String
"Unknown predictor (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
paddWrite :: B.ByteString -> Put
paddWrite :: ByteString -> Put
paddWrite ByteString
str = ByteString -> Put
putByteString ByteString
str Put -> Put -> Put
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Put
padding where
zero :: Word8
zero = Word8
0 :: Word8
padding :: Put
padding = Bool -> Put -> Put
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Bool
forall a. Integral a => a -> Bool
odd (ByteString -> Int
B.length ByteString
str)) (Put -> Put) -> Put -> Put
forall a b. (a -> b) -> a -> b
$ Word8 -> Put
forall t. Binary t => t -> Put
put Word8
zero
instance BinaryParam (Endianness, Int, ImageFileDirectory) ExifData where
putP :: (Endianness, Int, ImageFileDirectory) -> ExifData -> Put
putP (Endianness
endianness, Int
_, ImageFileDirectory
_) = ExifData -> Put
dump
where
dump :: ExifData -> Put
dump ExifData
ExifNone = () -> Put
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
dump (ExifLong Word32
_) = () -> Put
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
dump (ExifShort Word16
_) = () -> Put
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
dump (ExifIFD [(ExifTag, ExifData)]
_) = () -> Put
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
dump (ExifString ByteString
bstr) = ByteString -> Put
paddWrite ByteString
bstr
dump (ExifUndefined ByteString
bstr) = ByteString -> Put
paddWrite ByteString
bstr
dump (ExifShorts Vector Word16
shorts) = (Word16 -> Put) -> Vector Word16 -> Put
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Endianness -> Word16 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness) Vector Word16
shorts
dump (ExifLongs Vector Word32
longs) = (Word32 -> Put) -> Vector Word32 -> Put
forall (m :: * -> *) a b. Monad m => (a -> m b) -> Vector a -> m ()
V.mapM_ (Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness) Vector Word32
longs
dump (ExifRational Word32
a Word32
b) = Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness Word32
a Put -> Put -> Put
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness Word32
b
dump (ExifSignedRational Int32
a Int32
b) = Endianness -> Int32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness Int32
a Put -> Put -> Put
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Endianness -> Int32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness Int32
b
getP :: (Endianness, Int, ImageFileDirectory) -> Get ExifData
getP (Endianness
endianness, Int
maxi, ImageFileDirectory
ifd) = ImageFileDirectory -> Get ExifData
fetcher ImageFileDirectory
ifd
where
align :: ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory { ifdOffset :: ImageFileDirectory -> Word32
ifdOffset = Word32
offset } Get ExifData
act = do
Int64
readed <- Get Int64
bytesRead
let delta :: Int64
delta = Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
offset Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int64
readed
if Word32
offset Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
maxi Bool -> Bool -> Bool
|| Int64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
readed Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
offset then
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExifData
ExifNone
else do
Int -> Get ()
skip (Int -> Get ()) -> Int -> Get ()
forall a b. (a -> b) -> a -> b
$ Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
delta
Get ExifData
act
getE :: (BinaryParam Endianness a) => Get a
getE :: Get a
getE = Endianness -> Get a
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness
getVec :: a -> m a -> m (Vector a)
getVec a
count = Int -> m a -> m (Vector a)
forall (m :: * -> *) a. Monad m => Int -> m a -> m (Vector a)
V.replicateM (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
count)
immediateBytes :: a -> [a]
immediateBytes a
ofs =
let bytes :: [a]
bytes = [a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ (a
ofs a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0xFF000000) a -> Int -> a
forall a. Bits a => a -> Int -> a
`unsafeShiftR` (Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8)
,a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ (a
ofs a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x00FF0000) a -> Int -> a
forall a. Bits a => a -> Int -> a
`unsafeShiftR` (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8)
,a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ (a
ofs a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x0000FF00) a -> Int -> a
forall a. Bits a => a -> Int -> a
`unsafeShiftR` (Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8)
,a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a) -> a -> a
forall a b. (a -> b) -> a -> b
$ a
ofs a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x000000FF
]
in case Endianness
endianness of
Endianness
EndianLittle -> [a] -> [a]
forall a. [a] -> [a]
reverse [a]
bytes
Endianness
EndianBig -> [a]
bytes
fetcher :: ImageFileDirectory -> Get ExifData
fetcher ImageFileDirectory { ifdIdentifier :: ImageFileDirectory -> ExifTag
ifdIdentifier = ExifTag
TagExifOffset
, ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeLong
, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 } = do
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ do
let byOffset :: [ImageFileDirectory] -> [ImageFileDirectory]
byOffset = (ImageFileDirectory -> ImageFileDirectory -> Ordering)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Word32 -> Word32 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Word32 -> Word32 -> Ordering)
-> (ImageFileDirectory -> Word32)
-> ImageFileDirectory
-> ImageFileDirectory
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` ImageFileDirectory -> Word32
ifdOffset)
cleansIfds :: [ImageFileDirectory] -> [ImageFileDirectory]
cleansIfds = (ImageFileDirectory -> ImageFileDirectory)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Endianness -> ImageFileDirectory -> ImageFileDirectory
cleanImageFileDirectory Endianness
endianness)
[ImageFileDirectory]
subIfds <- [ImageFileDirectory] -> [ImageFileDirectory]
cleansIfds ([ImageFileDirectory] -> [ImageFileDirectory])
-> ([ImageFileDirectory] -> [ImageFileDirectory])
-> [ImageFileDirectory]
-> [ImageFileDirectory]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ImageFileDirectory] -> [ImageFileDirectory]
byOffset ([ImageFileDirectory] -> [ImageFileDirectory])
-> Get [ImageFileDirectory] -> Get [ImageFileDirectory]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get [ImageFileDirectory]
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness
[ImageFileDirectory]
cleaned <- Endianness
-> Int -> [ImageFileDirectory] -> Get [ImageFileDirectory]
fetchExtended Endianness
endianness Int
maxi ([ImageFileDirectory] -> Get [ImageFileDirectory])
-> [ImageFileDirectory] -> Get [ImageFileDirectory]
forall a b. (a -> b) -> a -> b
$ (ImageFileDirectory -> ImageFileDirectory -> Ordering)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Word32 -> Word32 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Word32 -> Word32 -> Ordering)
-> (ImageFileDirectory -> Word32)
-> ImageFileDirectory
-> ImageFileDirectory
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` ImageFileDirectory -> Word32
ifdOffset) [ImageFileDirectory]
subIfds
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData) -> ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ [(ExifTag, ExifData)] -> ExifData
ExifIFD [(ImageFileDirectory -> ExifTag
ifdIdentifier ImageFileDirectory
fd, ImageFileDirectory -> ExifData
ifdExtended ImageFileDirectory
fd) | ImageFileDirectory
fd <- [ImageFileDirectory]
cleaned]
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeUndefined, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
count } | Word32
count Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
4 =
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ ByteString -> ExifData
ExifUndefined (ByteString -> ExifData) -> Get ByteString -> Get ExifData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Get ByteString
getByteString (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
count)
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeUndefined, ifdOffset :: ImageFileDirectory -> Word32
ifdOffset = Word32
ofs } =
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData)
-> ([Word8] -> ExifData) -> [Word8] -> Get ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ExifData
ExifUndefined (ByteString -> ExifData)
-> ([Word8] -> ByteString) -> [Word8] -> ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
B.pack ([Word8] -> Get ExifData) -> [Word8] -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int) -> Word32 -> Int
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdCount ImageFileDirectory
ifd)
(Word32 -> [Word8]
forall a a. (Integral a, Bits a, Num a) => a -> [a]
immediateBytes Word32
ofs)
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeAscii, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
count } | Word32
count Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
4 =
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ ByteString -> ExifData
ExifString (ByteString -> ExifData) -> Get ByteString -> Get ExifData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Get ByteString
getByteString (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
count)
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeAscii, ifdOffset :: ImageFileDirectory -> Word32
ifdOffset = Word32
ofs } =
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData)
-> ([Word8] -> ExifData) -> [Word8] -> Get ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ExifData
ExifString (ByteString -> ExifData)
-> ([Word8] -> ByteString) -> [Word8] -> ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
B.pack ([Word8] -> Get ExifData) -> [Word8] -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int) -> Word32 -> Int
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdCount ImageFileDirectory
ifd)
(Word32 -> [Word8]
forall a a. (Integral a, Bits a, Num a) => a -> [a]
immediateBytes Word32
ofs)
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeShort, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
2, ifdOffset :: ImageFileDirectory -> Word32
ifdOffset = Word32
ofs } =
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData)
-> (Vector Word16 -> ExifData) -> Vector Word16 -> Get ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector Word16 -> ExifData
ExifShorts (Vector Word16 -> Get ExifData) -> Vector Word16 -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Int -> [Word16] -> Vector Word16
forall a. Int -> [a] -> Vector a
V.fromListN Int
2 [Word16]
valList
where high :: Word16
high = Word32 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word16) -> Word32 -> Word16
forall a b. (a -> b) -> a -> b
$ Word32
ofs Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16
low :: Word16
low = Word32 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Word16) -> Word32 -> Word16
forall a b. (a -> b) -> a -> b
$ Word32
ofs Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0xFFFF
valList :: [Word16]
valList = case Endianness
endianness of
Endianness
EndianLittle -> [Word16
low, Word16
high]
Endianness
EndianBig -> [Word16
high, Word16
low]
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeRational, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 } = do
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Word32 -> Word32 -> ExifData
ExifRational (Word32 -> Word32 -> ExifData)
-> Get Word32 -> Get (Word32 -> ExifData)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get Word32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
EndianLittle Get (Word32 -> ExifData) -> Get Word32 -> Get ExifData
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Endianness -> Get Word32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
EndianLittle
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeSignedRational, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 } = do
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Int32 -> Int32 -> ExifData
ExifSignedRational (Int32 -> Int32 -> ExifData)
-> Get Int32 -> Get (Int32 -> ExifData)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get Int32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
EndianLittle Get (Int32 -> ExifData) -> Get Int32 -> Get ExifData
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Endianness -> Get Int32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
EndianLittle
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeShort, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 } =
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData)
-> (Word32 -> ExifData) -> Word32 -> Get ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> ExifData
ExifShort (Word16 -> ExifData) -> (Word32 -> Word16) -> Word32 -> ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Get ExifData) -> Word32 -> Get ExifData
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdOffset ImageFileDirectory
ifd
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeShort, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
count } | Word32
count Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
2 =
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Vector Word16 -> ExifData
ExifShorts (Vector Word16 -> ExifData) -> Get (Vector Word16) -> Get ExifData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word32 -> Get Word16 -> Get (Vector Word16)
forall (m :: * -> *) a a.
(Monad m, Integral a) =>
a -> m a -> m (Vector a)
getVec Word32
count Get Word16
forall a. BinaryParam Endianness a => Get a
getE
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeLong, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 } =
ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExifData -> Get ExifData)
-> (Word32 -> ExifData) -> Word32 -> Get ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> ExifData
ExifLong (Word32 -> ExifData) -> (Word32 -> Word32) -> Word32 -> ExifData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Get ExifData) -> Word32 -> Get ExifData
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdOffset ImageFileDirectory
ifd
fetcher ImageFileDirectory { ifdType :: ImageFileDirectory -> IfdType
ifdType = IfdType
TypeLong, ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
count } | Word32
count Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
> Word32
1 =
ImageFileDirectory -> Get ExifData -> Get ExifData
align ImageFileDirectory
ifd (Get ExifData -> Get ExifData) -> Get ExifData -> Get ExifData
forall a b. (a -> b) -> a -> b
$ Vector Word32 -> ExifData
ExifLongs (Vector Word32 -> ExifData) -> Get (Vector Word32) -> Get ExifData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word32 -> Get Word32 -> Get (Vector Word32)
forall (m :: * -> *) a a.
(Monad m, Integral a) =>
a -> m a -> m (Vector a)
getVec Word32
count Get Word32
forall a. BinaryParam Endianness a => Get a
getE
fetcher ImageFileDirectory
_ = ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExifData
ExifNone
cleanImageFileDirectory :: Endianness -> ImageFileDirectory -> ImageFileDirectory
cleanImageFileDirectory :: Endianness -> ImageFileDirectory -> ImageFileDirectory
cleanImageFileDirectory Endianness
EndianBig ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdCount :: ImageFileDirectory -> Word32
ifdCount = Word32
1 }) = IfdType -> ImageFileDirectory
aux (IfdType -> ImageFileDirectory) -> IfdType -> ImageFileDirectory
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> IfdType
ifdType ImageFileDirectory
ifd
where
aux :: IfdType -> ImageFileDirectory
aux IfdType
TypeShort = ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = ImageFileDirectory -> Word32
ifdOffset ImageFileDirectory
ifd Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16 }
aux IfdType
_ = ImageFileDirectory
ifd
cleanImageFileDirectory Endianness
_ ImageFileDirectory
ifd = ImageFileDirectory
ifd
fetchExtended :: Endianness -> Int -> [ImageFileDirectory] -> Get [ImageFileDirectory]
fetchExtended :: Endianness
-> Int -> [ImageFileDirectory] -> Get [ImageFileDirectory]
fetchExtended Endianness
endian Int
maxi = (ImageFileDirectory -> Get ImageFileDirectory)
-> [ImageFileDirectory] -> Get [ImageFileDirectory]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((ImageFileDirectory -> Get ImageFileDirectory)
-> [ImageFileDirectory] -> Get [ImageFileDirectory])
-> (ImageFileDirectory -> Get ImageFileDirectory)
-> [ImageFileDirectory]
-> Get [ImageFileDirectory]
forall a b. (a -> b) -> a -> b
$ \ImageFileDirectory
ifd -> do
ExifData
v <- (Endianness, Int, ImageFileDirectory) -> Get ExifData
forall a b. BinaryParam a b => a -> Get b
getP (Endianness
endian, Int
maxi, ImageFileDirectory
ifd)
ImageFileDirectory -> Get ImageFileDirectory
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ImageFileDirectory -> Get ImageFileDirectory)
-> ImageFileDirectory -> Get ImageFileDirectory
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory
ifd { ifdExtended :: ExifData
ifdExtended = ExifData
v }
orderIfdByTag :: [ImageFileDirectory] -> [ImageFileDirectory]
orderIfdByTag :: [ImageFileDirectory] -> [ImageFileDirectory]
orderIfdByTag = (ImageFileDirectory -> ImageFileDirectory -> Ordering)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ImageFileDirectory -> ImageFileDirectory -> Ordering
comparer where
comparer :: ImageFileDirectory -> ImageFileDirectory -> Ordering
comparer ImageFileDirectory
a ImageFileDirectory
b = Word16 -> Word16 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Word16
t1 Word16
t2 where
t1 :: Word16
t1 = ExifTag -> Word16
word16OfTag (ExifTag -> Word16) -> ExifTag -> Word16
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> ExifTag
ifdIdentifier ImageFileDirectory
a
t2 :: Word16
t2 = ExifTag -> Word16
word16OfTag (ExifTag -> Word16) -> ExifTag -> Word16
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> ExifTag
ifdIdentifier ImageFileDirectory
b
setupIfdOffsets :: Word32 -> [ImageFileDirectory] -> (Word32, [ImageFileDirectory])
setupIfdOffsets :: Word32 -> [ImageFileDirectory] -> (Word32, [ImageFileDirectory])
setupIfdOffsets Word32
initialOffset [ImageFileDirectory]
lst = (Word32 -> ImageFileDirectory -> (Word32, ImageFileDirectory))
-> Word32 -> [ImageFileDirectory] -> (Word32, [ImageFileDirectory])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL Word32 -> ImageFileDirectory -> (Word32, ImageFileDirectory)
updater Word32
startExtended [ImageFileDirectory]
lst
where ifdElementCount :: Word32
ifdElementCount = Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word32) -> Int -> Word32
forall a b. (a -> b) -> a -> b
$ [ImageFileDirectory] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ImageFileDirectory]
lst
ifdSize :: Word32
ifdSize = Word32
12
ifdCountSize :: Word32
ifdCountSize = Word32
2
nextOffsetSize :: Word32
nextOffsetSize = Word32
4
startExtended :: Word32
startExtended = Word32
initialOffset
Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
ifdElementCount Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
* Word32
ifdSize
Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
ifdCountSize Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
nextOffsetSize
paddedSize :: ByteString -> b
paddedSize ByteString
blob = Int -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> b) -> Int -> b
forall a b. (a -> b) -> a -> b
$ Int
blobLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
padding where
blobLength :: Int
blobLength = ByteString -> Int
B.length ByteString
blob
padding :: Int
padding = if Int -> Bool
forall a. Integral a => a -> Bool
odd Int
blobLength then Int
1 else Int
0
updater :: Word32 -> ImageFileDirectory -> (Word32, ImageFileDirectory)
updater Word32
ix ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdIdentifier :: ImageFileDirectory -> ExifTag
ifdIdentifier = ExifTag
TagExifOffset }) =
(Word32
ix, ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = Word32
ix } )
updater Word32
ix ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdExtended :: ImageFileDirectory -> ExifData
ifdExtended = ExifUndefined ByteString
b }) =
(Word32
ix Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ ByteString -> Word32
forall b. Num b => ByteString -> b
paddedSize ByteString
b, ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = Word32
ix } )
updater Word32
ix ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdExtended :: ImageFileDirectory -> ExifData
ifdExtended = ExifString ByteString
b }) =
(Word32
ix Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ ByteString -> Word32
forall b. Num b => ByteString -> b
paddedSize ByteString
b, ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = Word32
ix } )
updater Word32
ix ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdExtended :: ImageFileDirectory -> ExifData
ifdExtended = ExifLongs Vector Word32
v })
| Vector Word32 -> Int
forall a. Vector a -> Int
V.length Vector Word32
v Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 = ( Word32
ix Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word32 -> Int
forall a. Vector a -> Int
V.length Vector Word32
v Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
4)
, ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = Word32
ix } )
updater Word32
ix ifd :: ImageFileDirectory
ifd@(ImageFileDirectory { ifdExtended :: ImageFileDirectory -> ExifData
ifdExtended = ExifShorts Vector Word16
v })
| Vector Word16 -> Int
forall a. Vector a -> Int
V.length Vector Word16
v Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
2 = ( Word32
ix Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Vector Word16 -> Int
forall a. Vector a -> Int
V.length Vector Word16
v Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
, ImageFileDirectory
ifd { ifdOffset :: Word32
ifdOffset = Word32
ix })
updater Word32
ix ImageFileDirectory
ifd = (Word32
ix, ImageFileDirectory
ifd)
instance BinaryParam B.ByteString (TiffHeader, [[ImageFileDirectory]]) where
putP :: ByteString -> (TiffHeader, [[ImageFileDirectory]]) -> Put
putP ByteString
rawData (TiffHeader
hdr, [[ImageFileDirectory]]
ifds) = do
TiffHeader -> Put
forall t. Binary t => t -> Put
put TiffHeader
hdr
ByteString -> Put
putByteString ByteString
rawData
let endianness :: Endianness
endianness = TiffHeader -> Endianness
hdrEndianness TiffHeader
hdr
(Word32
_, [[ImageFileDirectory]]
offseted) = (Word32 -> [ImageFileDirectory] -> (Word32, [ImageFileDirectory]))
-> Word32
-> [[ImageFileDirectory]]
-> (Word32, [[ImageFileDirectory]])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
mapAccumL
(\Word32
ix [ImageFileDirectory]
ifd -> Word32 -> [ImageFileDirectory] -> (Word32, [ImageFileDirectory])
setupIfdOffsets Word32
ix ([ImageFileDirectory] -> (Word32, [ImageFileDirectory]))
-> [ImageFileDirectory] -> (Word32, [ImageFileDirectory])
forall a b. (a -> b) -> a -> b
$ [ImageFileDirectory] -> [ImageFileDirectory]
orderIfdByTag [ImageFileDirectory]
ifd)
(TiffHeader -> Word32
hdrOffset TiffHeader
hdr)
[[ImageFileDirectory]]
ifds
[[ImageFileDirectory]] -> ([ImageFileDirectory] -> Put) -> Put
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [[ImageFileDirectory]]
offseted (([ImageFileDirectory] -> Put) -> Put)
-> ([ImageFileDirectory] -> Put) -> Put
forall a b. (a -> b) -> a -> b
$ \[ImageFileDirectory]
list -> do
Endianness -> [ImageFileDirectory] -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness [ImageFileDirectory]
list
(ImageFileDirectory -> Put) -> [ImageFileDirectory] -> Put
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\ImageFileDirectory
field -> (Endianness, Int, ImageFileDirectory) -> ExifData -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP (Endianness
endianness, (Int
0::Int), ImageFileDirectory
field) (ExifData -> Put) -> ExifData -> Put
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> ExifData
ifdExtended ImageFileDirectory
field) [ImageFileDirectory]
list
getP :: ByteString -> Get (TiffHeader, [[ImageFileDirectory]])
getP ByteString
raw = do
TiffHeader
hdr <- Get TiffHeader
forall t. Binary t => Get t
get
Int64
readed <- Get Int64
bytesRead
Int -> Get ()
skip (Int -> Get ()) -> (Int64 -> Int) -> Int64 -> Get ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Get ()) -> Int64 -> Get ()
forall a b. (a -> b) -> a -> b
$ Word32 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (TiffHeader -> Word32
hdrOffset TiffHeader
hdr) Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int64
readed
let endian :: Endianness
endian = TiffHeader -> Endianness
hdrEndianness TiffHeader
hdr
byOffset :: [ImageFileDirectory] -> [ImageFileDirectory]
byOffset = (ImageFileDirectory -> ImageFileDirectory -> Ordering)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Word32 -> Word32 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Word32 -> Word32 -> Ordering)
-> (ImageFileDirectory -> Word32)
-> ImageFileDirectory
-> ImageFileDirectory
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` ImageFileDirectory -> Word32
ifdOffset)
cleanIfds :: [ImageFileDirectory] -> [ImageFileDirectory]
cleanIfds = (ImageFileDirectory -> ImageFileDirectory)
-> [ImageFileDirectory] -> [ImageFileDirectory]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Endianness -> ImageFileDirectory -> ImageFileDirectory
cleanImageFileDirectory Endianness
endian)
[ImageFileDirectory]
ifd <- [ImageFileDirectory] -> [ImageFileDirectory]
cleanIfds ([ImageFileDirectory] -> [ImageFileDirectory])
-> ([ImageFileDirectory] -> [ImageFileDirectory])
-> [ImageFileDirectory]
-> [ImageFileDirectory]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ImageFileDirectory] -> [ImageFileDirectory]
byOffset ([ImageFileDirectory] -> [ImageFileDirectory])
-> Get [ImageFileDirectory] -> Get [ImageFileDirectory]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Endianness -> Get [ImageFileDirectory]
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endian
[ImageFileDirectory]
cleaned <- Endianness
-> Int -> [ImageFileDirectory] -> Get [ImageFileDirectory]
fetchExtended Endianness
endian (ByteString -> Int
B.length ByteString
raw) [ImageFileDirectory]
ifd
(TiffHeader, [[ImageFileDirectory]])
-> Get (TiffHeader, [[ImageFileDirectory]])
forall (m :: * -> *) a. Monad m => a -> m a
return (TiffHeader
hdr, [[ImageFileDirectory]
cleaned])
data TiffSampleFormat
= TiffSampleUint
| TiffSampleInt
| TiffSampleFloat
| TiffSampleUnknown
deriving TiffSampleFormat -> TiffSampleFormat -> Bool
(TiffSampleFormat -> TiffSampleFormat -> Bool)
-> (TiffSampleFormat -> TiffSampleFormat -> Bool)
-> Eq TiffSampleFormat
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TiffSampleFormat -> TiffSampleFormat -> Bool
$c/= :: TiffSampleFormat -> TiffSampleFormat -> Bool
== :: TiffSampleFormat -> TiffSampleFormat -> Bool
$c== :: TiffSampleFormat -> TiffSampleFormat -> Bool
Eq
unpackSampleFormat :: Word32 -> Get TiffSampleFormat
unpackSampleFormat :: Word32 -> Get TiffSampleFormat
unpackSampleFormat Word32
v = case Word32
v of
Word32
1 -> TiffSampleFormat -> Get TiffSampleFormat
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffSampleFormat
TiffSampleUint
Word32
2 -> TiffSampleFormat -> Get TiffSampleFormat
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffSampleFormat
TiffSampleInt
Word32
3 -> TiffSampleFormat -> Get TiffSampleFormat
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffSampleFormat
TiffSampleFloat
Word32
4 -> TiffSampleFormat -> Get TiffSampleFormat
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffSampleFormat
TiffSampleUnknown
Word32
vv -> String -> Get TiffSampleFormat
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get TiffSampleFormat) -> String -> Get TiffSampleFormat
forall a b. (a -> b) -> a -> b
$ String
"Undefined data format (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
vv String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
packSampleFormat :: TiffSampleFormat -> Word32
packSampleFormat :: TiffSampleFormat -> Word32
packSampleFormat TiffSampleFormat
TiffSampleUint = Word32
1
packSampleFormat TiffSampleFormat
TiffSampleInt = Word32
2
packSampleFormat TiffSampleFormat
TiffSampleFloat = Word32
3
packSampleFormat TiffSampleFormat
TiffSampleUnknown = Word32
4
data ImageFileDirectory = ImageFileDirectory
{ ImageFileDirectory -> ExifTag
ifdIdentifier :: !ExifTag
, ImageFileDirectory -> IfdType
ifdType :: !IfdType
, ImageFileDirectory -> Word32
ifdCount :: !Word32
, ImageFileDirectory -> Word32
ifdOffset :: !Word32
, ImageFileDirectory -> ExifData
ifdExtended :: !ExifData
}
deriving Int -> ImageFileDirectory -> ShowS
[ImageFileDirectory] -> ShowS
ImageFileDirectory -> String
(Int -> ImageFileDirectory -> ShowS)
-> (ImageFileDirectory -> String)
-> ([ImageFileDirectory] -> ShowS)
-> Show ImageFileDirectory
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ImageFileDirectory] -> ShowS
$cshowList :: [ImageFileDirectory] -> ShowS
show :: ImageFileDirectory -> String
$cshow :: ImageFileDirectory -> String
showsPrec :: Int -> ImageFileDirectory -> ShowS
$cshowsPrec :: Int -> ImageFileDirectory -> ShowS
Show
instance BinaryParam Endianness ImageFileDirectory where
getP :: Endianness -> Get ImageFileDirectory
getP Endianness
endianness =
ExifTag
-> IfdType -> Word32 -> Word32 -> ExifData -> ImageFileDirectory
ImageFileDirectory (ExifTag
-> IfdType -> Word32 -> Word32 -> ExifData -> ImageFileDirectory)
-> Get ExifTag
-> Get
(IfdType -> Word32 -> Word32 -> ExifData -> ImageFileDirectory)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get ExifTag
forall a. BinaryParam Endianness a => Get a
getE Get (IfdType -> Word32 -> Word32 -> ExifData -> ImageFileDirectory)
-> Get IfdType
-> Get (Word32 -> Word32 -> ExifData -> ImageFileDirectory)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get IfdType
forall a. BinaryParam Endianness a => Get a
getE Get (Word32 -> Word32 -> ExifData -> ImageFileDirectory)
-> Get Word32 -> Get (Word32 -> ExifData -> ImageFileDirectory)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get Word32
forall a. BinaryParam Endianness a => Get a
getE Get (Word32 -> ExifData -> ImageFileDirectory)
-> Get Word32 -> Get (ExifData -> ImageFileDirectory)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get Word32
forall a. BinaryParam Endianness a => Get a
getE
Get (ExifData -> ImageFileDirectory)
-> Get ExifData -> Get ImageFileDirectory
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ExifData -> Get ExifData
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExifData
ExifNone
where getE :: (BinaryParam Endianness a) => Get a
getE :: Get a
getE = Endianness -> Get a
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness
putP :: Endianness -> ImageFileDirectory -> Put
putP Endianness
endianness ImageFileDirectory
ifd = do
let putE :: (BinaryParam Endianness a) => a -> Put
putE :: a -> Put
putE = Endianness -> a -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness
ExifTag -> Put
forall a. BinaryParam Endianness a => a -> Put
putE (ExifTag -> Put) -> ExifTag -> Put
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> ExifTag
ifdIdentifier ImageFileDirectory
ifd
IfdType -> Put
forall a. BinaryParam Endianness a => a -> Put
putE (IfdType -> Put) -> IfdType -> Put
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> IfdType
ifdType ImageFileDirectory
ifd
Word32 -> Put
forall a. BinaryParam Endianness a => a -> Put
putE (Word32 -> Put) -> Word32 -> Put
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdCount ImageFileDirectory
ifd
Word32 -> Put
forall a. BinaryParam Endianness a => a -> Put
putE (Word32 -> Put) -> Word32 -> Put
forall a b. (a -> b) -> a -> b
$ ImageFileDirectory -> Word32
ifdOffset ImageFileDirectory
ifd
instance BinaryParam Endianness [ImageFileDirectory] where
getP :: Endianness -> Get [ImageFileDirectory]
getP Endianness
endianness = do
Word16
count <- Endianness -> Get Word16
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness :: Get Word16
[ImageFileDirectory]
rez <- Int -> Get ImageFileDirectory -> Get [ImageFileDirectory]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
count) (Get ImageFileDirectory -> Get [ImageFileDirectory])
-> Get ImageFileDirectory -> Get [ImageFileDirectory]
forall a b. (a -> b) -> a -> b
$ Endianness -> Get ImageFileDirectory
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness
Word32
_ <- Endianness -> Get Word32
forall a b. BinaryParam a b => a -> Get b
getP Endianness
endianness :: Get Word32
[ImageFileDirectory] -> Get [ImageFileDirectory]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [ImageFileDirectory]
rez
putP :: Endianness -> [ImageFileDirectory] -> Put
putP Endianness
endianness [ImageFileDirectory]
lst = do
let count :: Word16
count = Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word16) -> Int -> Word16
forall a b. (a -> b) -> a -> b
$ [ImageFileDirectory] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ImageFileDirectory]
lst :: Word16
Endianness -> Word16 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness Word16
count
(ImageFileDirectory -> Put) -> [ImageFileDirectory] -> Put
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Endianness -> ImageFileDirectory -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness) [ImageFileDirectory]
lst
Endianness -> Word32 -> Put
forall a b. BinaryParam a b => a -> b -> Put
putP Endianness
endianness (Word32
0 :: Word32)
data TiffColorspace
= TiffMonochromeWhite0
| TiffMonochrome
| TiffRGB
| TiffPaleted
| TiffTransparencyMask
| TiffCMYK
| TiffYCbCr
| TiffCIELab
packPhotometricInterpretation :: TiffColorspace -> Word16
packPhotometricInterpretation :: TiffColorspace -> Word16
packPhotometricInterpretation TiffColorspace
v = case TiffColorspace
v of
TiffColorspace
TiffMonochromeWhite0 -> Word16
0
TiffColorspace
TiffMonochrome -> Word16
1
TiffColorspace
TiffRGB -> Word16
2
TiffColorspace
TiffPaleted -> Word16
3
TiffColorspace
TiffTransparencyMask -> Word16
4
TiffColorspace
TiffCMYK -> Word16
5
TiffColorspace
TiffYCbCr -> Word16
6
TiffColorspace
TiffCIELab -> Word16
8
unpackPhotometricInterpretation :: Word32 -> Get TiffColorspace
unpackPhotometricInterpretation :: Word32 -> Get TiffColorspace
unpackPhotometricInterpretation Word32
v = case Word32
v of
Word32
0 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffMonochromeWhite0
Word32
1 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffMonochrome
Word32
2 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffRGB
Word32
3 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffPaleted
Word32
4 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffTransparencyMask
Word32
5 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffCMYK
Word32
6 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffYCbCr
Word32
8 -> TiffColorspace -> Get TiffColorspace
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffColorspace
TiffCIELab
Word32
vv -> String -> Get TiffColorspace
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get TiffColorspace) -> String -> Get TiffColorspace
forall a b. (a -> b) -> a -> b
$ String
"Unrecognized color space " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
vv
data
=
|
|
codeOfExtraSample :: ExtraSample -> Word16
ExtraSample
v = case ExtraSample
v of
ExtraSample
ExtraSampleUnspecified -> Word16
0
ExtraSample
ExtraSampleAssociatedAlpha -> Word16
1
ExtraSample
ExtraSampleUnassociatedAlpha -> Word16
2
unPackCompression :: Word32 -> Get TiffCompression
unPackCompression :: Word32 -> Get TiffCompression
unPackCompression Word32
v = case Word32
v of
Word32
0 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionNone
Word32
1 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionNone
Word32
2 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionModifiedRLE
Word32
5 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionLZW
Word32
6 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionJPEG
Word32
32773 -> TiffCompression -> Get TiffCompression
forall (f :: * -> *) a. Applicative f => a -> f a
pure TiffCompression
CompressionPackBit
Word32
vv -> String -> Get TiffCompression
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get TiffCompression) -> String -> Get TiffCompression
forall a b. (a -> b) -> a -> b
$ String
"Unknown compression scheme " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
vv
packCompression :: TiffCompression -> Word16
packCompression :: TiffCompression -> Word16
packCompression TiffCompression
v = case TiffCompression
v of
TiffCompression
CompressionNone -> Word16
1
TiffCompression
CompressionModifiedRLE -> Word16
2
TiffCompression
CompressionLZW -> Word16
5
TiffCompression
CompressionJPEG -> Word16
6
TiffCompression
CompressionPackBit -> Word16
32773