pdfinfo 0.1.3.3 → 1.4.0
raw patch · 2 files changed
+60/−55 lines, 2 filesdep +process-extrasdep +textdep −processdep ~mtl
Dependencies added: process-extras, text
Dependencies removed: process
Dependency ranges changed: mtl
Files
- pdfinfo.cabal +8/−6
- src/Text/PDF/Info.hs +52/−49
pdfinfo.cabal view
@@ -1,21 +1,23 @@ name: pdfinfo-version: 0.1.3.3+version: 1.4.0 synopsis: Wrapper around the pdfinfo command. description: Just a wrapper around the pdfinfo command. See man pdfinfo. license: BSD3 license-file: LICENSE author: Chris Done maintainer: chrisdone@gmail.com-copyright: 2010 Chris Done+copyright: 2013 Chris Done category: Text build-type: Simple-cabal-version: >=1.2+cabal-version: >=1.8 library- ghc-options: -O2 -Wall+ ghc-options: -O2 -Wall exposed-modules: Text.PDF.Info hs-source-dirs: src/ build-depends: base >= 4 && < 5, old-locale >= 1.0.0.0 && < 1.1, time >= 1.1 && < 1.5,- process >= 1.0 && < 1.2,- mtl >= 1.1 && < 2.2+ process-extras,+ text,+ -- mtl-2.1 contains a severe bug+ mtl >= 1.1 && < 2.1 || >= 2.1.1 && < 2.2
src/Text/PDF/Info.hs view
@@ -1,6 +1,9 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, ViewPatterns #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS -Wall #-}+ module Text.PDF.Info (-- * Reading PDF info pdfInfo@@ -16,44 +19,48 @@ ,readRight) where -import Prelude-import Control.Monad.Error-import System.Process-import Control.Applicative-import Control.Arrow-import Data.Char-import Data.Time-import System.Locale-import Control.Exception as E+import Control.Applicative+import Control.Arrow+import Control.Exception as E+import Control.Monad.Error +import Data.Text (Text)+import qualified Data.Text as T+import Data.Time+import Prelude+import System.Exit+import System.Locale+import System.Process.Text+ -- | A type representing the output from the pdfinfo command. data PDFInfo = PDFInfo {- pdfInfoTitle :: Maybe String -- ^ Title- , pdfInfoSubject :: Maybe String -- ^ Subject- , pdfInfoAuthor :: Maybe String -- ^ Author: E.g. Chris Done- , pdfInfoCreator :: Maybe String -- ^ Creator: E.g. Microsoft Office Word 2007- , pdfInfoProducer :: Maybe String -- ^ Producer: E.g. Microsoft Office Word 2007- , pdfInfoCreationDate :: Maybe UTCTime -- ^ Creation Date- , pdfInfoModDate :: Maybe UTCTime -- ^ Modification Date- , pdfInfoTagged :: Maybe Bool -- ^ Tagged?- , pdfInfoPages :: Maybe Integer -- ^ Pages: E.g. 238- , pdfInfoEncrypted :: Maybe Bool -- ^ Encrypted?- , pdfInfoPageSize :: Maybe PDFSize -- ^ Page: E.g. 595.32 x 841.92 pts (A4)- , pdfInfoFileSize :: Maybe Integer -- ^ File: E.g. 4061737 bytes- , pdfInfoOptimized :: Maybe Bool -- ^ Optimized?- , pdfInfoPDFVersion :: Maybe Double -- ^ PDF: E.g. 1.5+ pdfInfoTitle :: !(Maybe Text) -- ^ Title+ , pdfInfoSubject :: !(Maybe Text) -- ^ Subject+ , pdfInfoAuthor :: !(Maybe Text) -- ^ Author: E.g. Chris Done+ , pdfInfoCreator :: !(Maybe Text) -- ^ Creator: E.g. Microsoft Office Word 2007+ , pdfInfoProducer :: !(Maybe Text) -- ^ Producer: E.g. Microsoft Office Word 2007+ , pdfInfoCreationDate :: !(Maybe UTCTime) -- ^ Creation Date+ , pdfInfoModDate :: !(Maybe UTCTime) -- ^ Modification Date+ , pdfInfoTagged :: !(Maybe Bool) -- ^ Tagged?+ , pdfInfoPages :: !(Maybe Integer) -- ^ Pages: E.g. 238+ , pdfInfoEncrypted :: !(Maybe Bool) -- ^ Encrypted?+ , pdfInfoPageSize :: !(Maybe PDFSize) -- ^ Page: E.g. 595.32 x 841.92 pts (A4)+ , pdfInfoFileSize :: !(Maybe Integer) -- ^ File: E.g. 4061737 bytes+ , pdfInfoOptimized :: !(Maybe Bool) -- ^ Optimized?+ , pdfInfoPDFVersion :: !(Maybe Double) -- ^ PDF: E.g. 1.5 } deriving Show -- | Possible things that can go wrong while reading the info.-data PDFInfoError =- ParseError String -- ^ Couldn't parse a property value.- | ProcessError IOException -- ^ Error to do with the pdfinfo process.- | NoMessage -- ^ No message given.- | SomeError String -- ^ Some nonspecific error.+data PDFInfoError+ = ParseError !String -- ^ Couldn't parse a property value.+ | ProcessFailure !Text -- ^ Process exited with this stderr.+ | ProcessError !IOException -- ^ Error to do with the pdfinfo process.+ | NoMessage -- ^ No message given.+ | SomeError String -- ^ Some nonspecific error. deriving Show -- | Size of the PDF in pts.-data PDFSize = PDFSize { pdfSizeW :: Float, pdfSizeH :: Float }+data PDFSize = PDFSize { pdfSizeW :: !Float, pdfSizeH :: !Float } deriving (Eq,Show) instance Error PDFInfoError where noMsg = NoMessage; strMsg = SomeError@@ -65,11 +72,14 @@ -- running the process. pdfInfo :: MonadIO m => FilePath -> m (Either PDFInfoError PDFInfo) pdfInfo path = liftIO $ loadInfo `E.catch` ioErrorHandler where- loadInfo = parse <$> readProcess "pdfinfo" [path] ""+ loadInfo = do (code,out,err) <- readProcessWithExitCode "pdfinfo" ["-enc","UTF-8",path] ""+ case code of+ ExitSuccess -> return (parse out)+ ExitFailure{} -> return (Left (ProcessFailure err)) ioErrorHandler = return . Left . ProcessError -- | Parse PDFInfo's output.-parse :: String -> Either PDFInfoError PDFInfo+parse :: Text -> Either PDFInfoError PDFInfo parse out = runParse $ PDFInfo <$> string "Title" <*> string "Subject"@@ -85,48 +95,41 @@ <*> integer "File size" <*> bool "Optimized" <*> floating "PDF version"- where string = get id date = get (>>= parseDate) size = get (>>= parseSize) bool = get $ fmap $ \yes -> yes == "yes" floating = readIt integer = readIt- readIt :: Read a => String -> ParsePDFInfo (Maybe a)+ readIt :: Read a => Text -> ParsePDFInfo (Maybe a) readIt = get (>>= readRight)-- properties = map split . lines $ out+ properties = map split . T.lines $ out get f name = case lookup name properties of- Just ok -> catchError (Just <$> (f $ return $ trim ok))+ Just ok -> catchError (Just <$> (f $ return $ T.strip ok)) (\_ -> return Nothing) Nothing -> return Nothing - split = second (drop 2) . span (/=':')- trim = bi reverse (dropWhile isSpace) . dropWhile isSpace+ split = second (T.drop 2) . T.span (/=':') -- | Parse a page size. This is loosely defined.-parseSize :: String -> ParsePDFInfo PDFSize+parseSize :: Text -> ParsePDFInfo PDFSize parseSize s =- case words s of+ case T.words s of ((readRight -> Right x):"x":(readRight -> Right y):_) -> return $ PDFSize x y _ -> throwError $ ParseError $ "Unable to read size: " ++ show s -- | Parse a date according to pdfinfo's format.-parseDate :: String -> ParsePDFInfo UTCTime+parseDate :: Text -> ParsePDFInfo UTCTime parseDate s =- case parseTime defaultTimeLocale "%a %b %e %H:%M:%S %Y" s of+ case parseTime defaultTimeLocale "%a %b %e %H:%M:%S %Y" (T.unpack s) of Just ok -> return ok Nothing -> throwError $ ParseError $ "Unable to parse date: " ++ show s -- | Read a value, maybe, allow misc trailing data.-readRight :: (MonadError PDFInfoError m,Read a) => String -> m a+readRight :: (MonadError PDFInfoError m,Read a) => Text -> m a readRight s =- case reads s of+ case reads (T.unpack s) of [(v,_)] -> return v _ -> throwError $ ParseError $ "Couldn't read value: " ++ show s---- | Untwist a value, apply a function, twist it back.-bi :: (c1 -> c) -> (c -> c1) -> c1 -> c-bi g f = g . f . g