{-# LANGUAGE OverloadedStrings #-} -- | Page tree node module Pdf.Toolbox.Document.PageNode ( PageNode, PageTree(..), pageNodeNKids, pageNodeParent, pageNodeKids, loadPageNode, pageNodePageByNum ) where import Pdf.Toolbox.Core import Pdf.Toolbox.Document.Monad import Pdf.Toolbox.Document.Internal.Types import Pdf.Toolbox.Document.Internal.Util -- | Total number of child leaf nodes, including deep children pageNodeNKids :: MonadPdf m => PageNode -> PdfE m Int pageNodeNKids (PageNode _ dict) = lookupDict "Count" dict >>= fromObject >>= intValue -- | Parent page node pageNodeParent :: MonadPdf m => PageNode -> PdfE m (Maybe PageNode) pageNodeParent (PageNode _ dict) = case lookupDict' "Parent" dict of Nothing -> return Nothing Just o -> do ref <- fromObject o node <- lookupObject ref >>= fromObject ensureType "Pages" node return $ Just $ PageNode ref node -- | Referencies to all kids pageNodeKids :: MonadPdf m => PageNode -> PdfE m [Ref] pageNodeKids (PageNode _ dict) = do Array kids <- lookupDict "Kids" dict >>= fromObject mapM fromObject kids -- | Load page tree node by reference loadPageNode :: MonadPdf m => Ref -> PdfE m PageTree loadPageNode ref = do node <- lookupObject ref >>= fromObject nodeType <- dictionaryType node case nodeType of "Pages" -> return $ PageTreeNode $ PageNode ref node "Page" -> return $ PageTreeLeaf $ Page ref node _ -> throwE $ UnexpectedError $ "Unexpected page tree node type: " ++ show nodeType -- | Find page by it's number -- -- Note: it is not efficient for PDF files with a lot of pages, -- because it performs traversal through the page tree each time. -- Use 'pageNodeNKids', 'pageNodeKids' and 'loadPageNode' for -- efficient traversal. pageNodePageByNum :: MonadPdf m => PageNode -> Int -> PdfE m Page pageNodePageByNum node num = annotateError ("page #" ++ show num ++ " for node: " ++ show node) $ do pageNodeKids node >>= loop num where loop _ [] = throwE $ UnexpectedError "Page not found" loop i (x:xs) = do kid <- loadPageNode x case kid of PageTreeNode n -> do nkids <- pageNodeNKids n if i < nkids then pageNodePageByNum n i else loop (i - nkids) xs PageTreeLeaf page -> if i == 0 then return page else loop (i - 1) xs