WIP: start moving some navigation-related routines from Pages into Object directly and generalize them to multi-component to allow easier browsing

This commit is contained in:
Tissevert 2020-02-10 17:43:04 +01:00
parent 195446e653
commit e77bbbcda9

View file

@ -1,6 +1,8 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
module PDF.Object ( module PDF.Object (
Content(..) Content(..)
, Dictionary , Dictionary
@ -17,6 +19,7 @@ module PDF.Object (
, Structure(..) , Structure(..)
, XRefEntry(..) , XRefEntry(..)
, XRefSection , XRefSection
, (//)
, array , array
, blank , blank
, dictionary , dictionary
@ -34,6 +37,8 @@ module PDF.Object (
) where ) where
import Control.Applicative ((<|>), many) import Control.Applicative ((<|>), many)
import Control.Monad.Reader (MonadReader(..))
import Control.Monad.Fail (MonadFail(..))
import Data.Attoparsec.ByteString.Char8 (choice, count, option, sepBy) import Data.Attoparsec.ByteString.Char8 (choice, count, option, sepBy)
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import qualified Data.ByteString as BS (concat) import qualified Data.ByteString as BS (concat)
@ -51,6 +56,7 @@ import PDF.Output (
, saveOffset , saveOffset
) )
import PDF.Parser (MonadParser(..), Parser, (<?>), octDigit, oneOf) import PDF.Parser (MonadParser(..), Parser, (<?>), octDigit, oneOf)
import Prelude hiding (fail)
import Text.Printf (printf) import Text.Printf (printf)
line :: MonadParser m => String -> m () line :: MonadParser m => String -> m ()
@ -404,3 +410,36 @@ instance Output Content where
] ]
where where
Structure {xRef, trailer} = docStructure Structure {xRef, trailer} = docStructure
type PDFContent m = (MonadReader Content m, MonadFail m)
--
-- Navigation
--
key :: MonadFail m => String -> Dictionary -> m DirectObject
key keyName dictionary =
maybe (fail errorMessage) return (Map.lookup (Name keyName) dictionary)
where
errorMessage =
printf "Key %s not found in dictionary %s" keyName (show dictionary)
dict :: PDFContent m => Object -> m Dictionary
dict (Direct (Dictionary aDict)) = return aDict
dict obj = fail $ "Not a dictionary : " ++ show obj
getObject :: PDFContent m => ObjectId -> m Object
getObject objectId = do
content <- ask
return (objects content ! objectId)
getResource :: PDFContent m => DirectObject -> m Dictionary
getResource (Dictionary aDict) = return aDict
getResource (Reference (IndirectObjCoordinates {objectId})) =
getObject objectId >>= dict
getResource directObject =
fail $ "Not a resource (dictionary or reference) : " ++ show directObject
(//) :: PDFContent m => Dictionary -> [String] -> m DirectObject
(//) aDict [] = return $ Dictionary aDict
(//) aDict [field] = key field aDict
(//) aDict (field:fields) = key field aDict >>= getResource >>= (// fields)