packages feed

hpdft-0.1.1.1: src/PDF/PDFIO.hs

{-# LANGUAGE OverloadedStrings #-}

{-|
Module      : PDF.PDFIO
Description : IO utilities for hpdft
Copyright   : (c) Keiichiro Shikano, 2016
License     : MIT
Maintainer  : k16.shikano@gmail.com

Functions for use within IO. 
-}

module PDF.PDFIO ( getObjectByRef
                 , getPDFBSFromFile
                 , getPDFObjFromFile
                 , getRootRef
                 , getRootObj
                 , getStream
                 , getTrailer
                 , getInfo
                 ) where

import PDF.Definition
import PDF.DocumentStructure
  (rawStream, rawStreamByRef, findObjs, findObjsByRef,
   findDictByRef, findObjFromDict, rootRef,
   findTrailer, expandObjStm)
import PDF.Object (parsePDFObj)

import Debug.Trace

import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy.Char8 as BSL

-- | Get PDF objects as a whole bytestring. Use `getPDFObjFromFile` instead if there's no reason to see a raw bytestring. 

getPDFBSFromFile :: FilePath -> IO [PDFBS]
getPDFBSFromFile f = do
  c <- BS.readFile f
  let bs = findObjs c
  return bs

-- | Get PDF objects each parsed as 'PDFObj' without being sorted. 

getPDFObjFromFile :: FilePath -> IO [PDFObj]
getPDFObjFromFile f = do
  c <- BS.readFile f
  let obj = expandObjStm $ map parsePDFObj $ findObjs c
  return obj

-- | Get a PDF object from a whole 'PDFObj' by specifying `ref :: Int`

getObjectByRef :: Int -> [PDFObj] -> IO [Obj]
getObjectByRef ref pdfobjs = do
  case findObjsByRef ref pdfobjs of
    Just os -> return os
    Nothing -> error $ "No Object with Ref " ++ show ref

-- | Get a PDF stream from a whole 'PDFObj' by specifying `ref :: Int`

getStream :: Bool -> [Obj] -> IO BSL.ByteString
getStream hex obj = return $ showBSL hex $ rawStream obj

showBSL hex s =
  let strm' = (B.toLazyByteString . B.lazyByteStringHex) s
  in if hex
     then if BSL.length strm' > 256 then BSL.concat [BSL.take 256 strm', "...(omit)"] else strm'
     else s

-- | The reference number of /Root in `filename`.

getRootRef :: FilePath -> IO Int
getRootRef filename = do
  c <- BS.readFile filename
  let n = rootRef c
  case n of
    Just i -> return i
    Nothing -> error "Could not find rood object"
    
-- | The /Root object in `filename`.

getRootObj :: FilePath -> IO [Obj]
getRootObj filename = do
  rootref <- getRootRef filename
  objs <- getPDFObjFromFile filename
  case findObjsByRef rootref objs of
    Just os -> return os
    Nothing -> error "Could not get root object"

-- | The trailer of `filename`.

getTrailer :: FilePath -> IO Dict
getTrailer filename = do
  c <- BS.readFile filename
  return $ findTrailer c

-- | /Info of `filename`.

getInfo :: FilePath -> IO Dict
getInfo filename = do
  d <- getTrailer filename
  objs <- getPDFObjFromFile filename
  let inforef = case findObjFromDict d "/Info" of
                  Just (ObjRef ref) -> ref
                  Just _ -> error "There seems to be no Info"
                  Nothing -> error "There seems to be no Info"
  case findDictByRef inforef objs of
    Just os -> return os
    Nothing -> error "Could not get info object"