packages feed

asciidiagram-1.2: exec-src/asciidiagram.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE CPP #-}

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative( (<$>), (<*>), pure )
#endif

import Control.Applicative( (<|>) )
import Control.Monad( when )
import Data.Monoid( (<>) )

import qualified Data.ByteString.Lazy as LB
import qualified Data.Text.IO as STIO
import System.Directory( getTemporaryDirectory )
import System.FilePath( (</>)
                      , replaceExtension
                      , takeExtension )

import Graphics.Rasterific.Svg( loadCreateFontCache )
import Graphics.Text.TrueType( FontCache )
import Codec.Picture( writePng )
import Options.Applicative( Parser
                          , ParserInfo
                          , argument
                          , execParser
                          , flag
                          , fullDesc
                          , header
                          , help
                          , helper
                          , info
                          , long
                          , metavar
                          , progDesc
                          , str
                          , switch
                          )
import Text.AsciiDiagram

data Options = Options
  { _inputFile  :: !FilePath
  , _outputFile :: !FilePath
  , _verbose    :: !Bool
  , _format     :: !(Maybe Format)
  }

data Format = FormatSvg | FormatPng | FormatPdf

argParser :: Parser Options
argParser = Options
  <$> ( argument str
            (metavar "INPUTFILE"
            <> help "Text file of the Ascii diagram to parse."))
  <*> ( argument str
            (metavar "OUTPUTFILE"
            <> help ("Output file name, same as input with"
                    <> " different extension if unspecified."))
        <|> pure "" )
  <*> ( switch (long "verbose" <> help "Display more information") )
  <*> ( flag Nothing (Just FormatSvg)
            (  long "svg"
            <> help "Force the use of the SVG format (deduced from extension otherwise)")
     <|> flag Nothing (Just FormatPng)
            ( long "png"
            <> help "Force the use of the PNG format (deduced from extension otherwise) (by default)")
     <|> flag Nothing (Just FormatPdf)
            ( long "pdf"
            <> help  "Force the use of the PDF format (deduced from extension otherwise)")
      )

progOptions :: ParserInfo Options
progOptions = info (helper <*> argParser)
      ( fullDesc
     <> progDesc "Convert INPUTFILE into a svg or png OUTPUTFILE"
     <> header "asciidiagram - A pretty printer for ASCII art diagram to SVG." )

formatOfOuputFilename :: FilePath -> Format
formatOfOuputFilename f = case takeExtension f of
    ".png" -> FormatPng
    ".svg" -> FormatSvg
    ".pdf" -> FormatPdf
    _ -> FormatPng

getFontCache :: Bool -> IO FontCache
getFontCache verbose = do
  when verbose $ putStrLn "Loading/Building font cache (can be long)"
  tempDir <- getTemporaryDirectory 
  loadCreateFontCache $ tempDir </> "asciidiagram-fonty-fontcache"

runConversion :: Options -> IO ()
runConversion opt = do
  verbose . putStrLn $ "Loading file " ++ _inputFile opt
  inputData <- STIO.readFile $ _inputFile opt
  let diag = parseAsciiDiagram inputData
      format = _format opt <|> (pure . formatOfOuputFilename $ _outputFile opt)
  case format of
    Nothing -> saveDoc diag
    Just FormatSvg -> saveDoc diag
    Just FormatPng -> savePng diag
    Just FormatPdf -> savePdf diag
  where
    verbose = when $ _verbose opt
    saveDoc diag = do
      verbose . putStrLn $ "Writing SVG file " ++ _outputFile opt
      saveAsciiDiagramAsSvg (savingPath "svg") diag

    savingPath ext = case _outputFile opt of
      "" -> replaceExtension (_inputFile opt) ext
      p -> p

    savePdf diag = do
      cache <- getFontCache  $ _verbose opt
      verbose . putStrLn $ "Writing PDF file " ++ _outputFile opt
      pdf <- pdfOfDiagram cache diag
      LB.writeFile (savingPath "pdf") pdf

    savePng diag = do
      cache <- getFontCache  $ _verbose opt
      verbose . putStrLn $ "Writing PNG file " ++ _outputFile opt
      img <- imageOfDiagram cache diag
      writePng (savingPath "png") img

main :: IO ()
main = execParser progOptions >>= runConversion