module Pdf.Toolbox.Core.Stream.Filter.FlateDecode
(
flateDecode
)
where
import Data.Word
import qualified Data.ByteString as BS
import Codec.Zlib
import Control.Error
import Control.Exception
import qualified System.IO.Streams as Streams
import Pdf.Toolbox.Core.IO
import Pdf.Toolbox.Core.Object.Types
import Pdf.Toolbox.Core.Object.Util
import Pdf.Toolbox.Core.Stream.Filter.Type
flateDecode :: StreamFilter
flateDecode = StreamFilter {
filterName = "FlateDecode",
filterDecode = \params is -> decode params is >>= catchZlibExceptions
}
catchZlibExceptions :: IS -> IO IS
catchZlibExceptions is =
Streams.makeInputStream $
Streams.read is
`catch` (\(e :: ZlibException) -> throwIO $ DecodeException $ toException e)
decode :: Maybe Dict -> IS -> IO IS
decode Nothing is = Streams.decompress is
decode (Just dict) is = do
predictor <- runEitherT $ lookupDict "Predictor" dict
case predictor of
Left _ -> Streams.decompress is
Right p -> do
p' <- runEitherT $ fromObject p >>= intValue
case p' of
Left e -> fail $ "Malformed predictor: " ++ show e
Right val -> Streams.decompress is >>= unpredict dict val
unpredict :: Dict -> Int -> IS -> IO IS
unpredict _ 1 is = return is
unpredict dict 12 is = do
c <- runEitherT $ lookupDict "Columns" dict >>= fromObject >>= intValue
case c of
Left e -> fail $ "flateDecode: malformed Columns value: " ++ show e
Right cols -> unpredict12 (cols + 1) is
unpredict _ p _ = fail $ "Unsupported predictor: " ++ show p
unpredict12 :: Int -> IS -> IO IS
unpredict12 cols is = Streams.toList is >>= Streams.fromList . return . BS.pack . step (replicate cols 0) [] . concatMap BS.unpack
where
step :: [Word8] -> [Word8] -> [Word8] -> [Word8]
step _ _ [] = []
step (c:cs) [] (_:xs) = step cs [c] xs
step (c:cs) (p:ps) (x:xs) = (x + p) : step cs (c:(x + p):ps) xs
step [] ps xs = step (reverse ps) [] xs