packages feed

asciidiagram-1.0: 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.Text.IO as STIO
import System.FilePath( replaceExtension
                      , takeExtension )

import Graphics.Rasterific.Svg( renderSvgDocument
                              , loadCreateFontCache )

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
import Graphics.Svg

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

data Format = FormatSvg | FormatPng

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)")
      )

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
    _ -> FormatPng

runConversion :: Options -> IO ()
runConversion opt = do
  verbose . putStrLn $ "Loading file " ++ _inputFile opt
  inputData <- STIO.readFile $ _inputFile opt
  let svgDoc = svgOfDiagram $ parseAsciiDiagram inputData
  case (_format opt, formatOfOuputFilename $ _outputFile opt) of
    (Nothing, FormatSvg) -> saveDoc svgDoc
    (Just FormatSvg, _) -> saveDoc svgDoc
    (Nothing, FormatPng) -> savePng svgDoc
    (Just FormatPng, _) -> savePng svgDoc
  where
    verbose = when $ _verbose opt
    saveDoc doc = do
      verbose . putStrLn $ "Writing SVG file " ++ _outputFile opt
      saveXmlFile (savingPath "svg") doc

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

    savePng doc = do
      verbose . putStrLn $ "Loading/Building font cache (can be long)"
      cache <- loadCreateFontCache "asciidiagram-fonty-fontcache"
      verbose . putStrLn $ "Writing PNG file " ++ _outputFile opt
      (img, _) <- renderSvgDocument cache Nothing 96 doc
      writePng (savingPath "png") img

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