{-# LANGUAGE DeriveDataTypeable, NoMonomorphismRestriction #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Backend.Pdf.CmdLine -- Copyright : (c) 2013 alpheccar.org (see LICENSE) -- License : BSD-style (see LICENSE) -- -- Convenient creation of command-line-driven executables for -- rendering diagrams using the Pdf backend. -- -- * 'defaultMain' creates an executable which can render a single -- diagram at various options. -- ----------------------------------------------------------------------------- module Diagrams.Backend.Pdf.CmdLine ( defaultMain , multipleMain , Pdf ) where import Diagrams.Prelude hiding (width, height, interval) import Diagrams.Backend.Pdf import System.Console.CmdArgs.Implicit hiding (args) import Prelude import Data.List.Split import System.Environment (getProgName) import qualified Graphics.PDF as P data DiagramOpts = DiagramOpts { width :: Maybe Int , height :: Maybe Int , output :: FilePath , compressed :: Maybe Bool , author :: Maybe String } deriving (Show, Data, Typeable) diagramOpts :: String -> DiagramOpts diagramOpts prog = DiagramOpts { width = def &= typ "INT" &= help "Desired width of the output image (default 400)" , height = def &= typ "INT" &= help "Desired height of the output image (default 400)" , output = def &= typFile &= help "Output file" , compressed = def &= typ "BOOL" &= help "Compressed PDF file" , author = def &= typ "STRING" &= help "Author of the document" } &= summary "Command-line diagram generation." &= program prog -- | This is the simplest way to render diagrams, and is intended to -- be used like so: -- -- > ... other definitions ... -- > myDiagram = ... -- > -- > main = defaultMain myDiagram -- -- Compiling a source file like the above example will result in an -- executable which takes command-line options for setting the size, -- output file, and so on, and renders @myDiagram@ with the -- specified options. -- -- Pass @--help@ to the generated executable to see all available -- options. Currently it looks something like -- -- @ -- Command-line diagram generation. -- -- Foo [OPTIONS] -- -- Common flags: -- -w --width=INT Desired width of the output image (default 400) -- -h --height=INT Desired height of the output image (default 400) -- -o --output=FILE Output file -- -c --compressed Compressed PDF file -- -? --help Display help message -- -V --version Print version information -- @ -- -- For example, a couple common scenarios include -- -- @ -- $ ghc --make MyDiagram -- -- # output image.eps with a width of 400pt (and auto-determined height) -- $ ./MyDiagram --compressed -o image.pdf -w 400 -- @ defaultMain :: Diagram Pdf R2 -> IO () defaultMain d = do prog <- getProgName opts <- cmdArgs (diagramOpts prog) let sizeSpec = case (width opts, height opts) of (Nothing, Nothing) -> Absolute (Just wi, Nothing) -> Width (fromIntegral wi) (Nothing, Just he) -> Height (fromIntegral he) (Just wi, Just he) -> Dims (fromIntegral wi) (fromIntegral he) (w,h) = sizeFromSpec sizeSpec theAuthor = maybe "diagrams-pdf" id (author opts) compression = maybe False id (compressed opts) docRect = P.PDFRect 0 0 (floor w) (floor h) pdfOpts = PdfOptions sizeSpec ifCanRender opts $ do P.runPdf (output opts) (P.standardDocInfo { P.author=P.toPDFString theAuthor, P.compressed = compression}) docRect $ do page1 <- P.addPage Nothing P.drawWithPage page1 $ renderDia Pdf pdfOpts d -- | Generate a multipage PDF document from several diagrams. -- Each diagram is scaled to the page size multipleMain :: [Diagram Pdf R2] -> IO () multipleMain d = do prog <- getProgName opts <- cmdArgs (diagramOpts prog) let sizeSpec = case (width opts, height opts) of (Nothing, Nothing) -> Absolute (Just wi, Nothing) -> Width (fromIntegral wi) (Nothing, Just he) -> Height (fromIntegral he) (Just wi, Just he) -> Dims (fromIntegral wi) (fromIntegral he) (w,h) = sizeFromSpec sizeSpec theAuthor = maybe "diagrams-pdf" id (author opts) compression = maybe False id (compressed opts) docRect = P.PDFRect 0 0 (floor w) (floor h) pdfOpts = PdfOptions sizeSpec createPage aDiag = do page1 <- P.addPage Nothing P.drawWithPage page1 $ renderDia Pdf pdfOpts aDiag ifCanRender opts $ do P.runPdf (output opts) (P.standardDocInfo { P.author=P.toPDFString theAuthor, P.compressed = compression}) docRect $ do mapM_ createPage d ifCanRender :: DiagramOpts -> IO () -> IO () ifCanRender opts action = case splitOn "." (output opts) of [""] -> putStrLn "No output file given." ps | last ps `elem` ["pdf"] -> action | otherwise -> putStrLn $ "Unknown file type: " ++ last ps