Basic LaTeX example.

This commit is contained in:
David 2019-02-15 15:20:33 +01:00
commit 6244f76da3
4 changed files with 124 additions and 2 deletions

View file

@ -157,3 +157,17 @@ scaling = adjustSpeed 2 $ syncAll
## Valentine's Day ## Valentine's Day
![Valentine's Day](gifs/valentine.gif) ![Valentine's Day](gifs/valentine.gif)
## Basic LaTeX
```
latex_basic :: Ani ()
latex_basic = proc () -> do
duration 1 -< ()
emit -< do
rect_ [width_ "100%", height_ "100%", fill_ "black"]
g_ [transform_ $ translate 5 50] $
g_ [transform_ $ scale 4 4, fill_ "white"] $
latex "$\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}$"
```
![Basic LaTeX](gifs/latex_basic.gif)

View file

@ -20,6 +20,7 @@ library
Reanimate.Render Reanimate.Render
Reanimate.Examples Reanimate.Examples
Reanimate.Combinators Reanimate.Combinators
Reanimate.LaTeX
build-depends: base >=4.12 && <4.13, build-depends: base >=4.12 && <4.13,
lucid-svg, time, text, unix, lucid, filepath, process, directory lucid-svg, time, text, unix, lucid, filepath, process, directory

View file

@ -10,8 +10,7 @@ import Numeric
import Reanimate.Arrow import Reanimate.Arrow
import Reanimate.Combinators import Reanimate.Combinators
import Reanimate.LaTeX
import Debug.Trace
sinewave :: Ani () sinewave :: Ani ()
sinewave = proc () -> do sinewave = proc () -> do
@ -326,3 +325,13 @@ frequencies = proc () -> do
(idx*width, 0) (idx*width, 0)
wave1 n = approxFnData 1000 $ \idx -> wave1 n = approxFnData 1000 $ \idx ->
(idx*width, sum [ sin ((idx+n)*pi*2*freq) * 20 | freq <- freqs ]) (idx*width, sum [ sin ((idx+n)*pi*2*freq) * 20 | freq <- freqs ])
latex_basic :: Ani ()
latex_basic = proc () -> do
duration 1 -< ()
emit -< do
rect_ [width_ "100%", height_ "100%", fill_ "black"]
g_ [transform_ $ translate 5 50] $
g_ [transform_ $ scale 4 4, fill_ "white"] $
latex "$\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}$"

98
src/Reanimate/LaTeX.hs Normal file
View file

@ -0,0 +1,98 @@
{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
module Reanimate.LaTeX where
import System.Process
import System.Exit
import System.IO
import System.IO.Unsafe
import System.FilePath
import System.Directory
import Control.Exception
import Lucid (toHtmlRaw, toHtml)
import Lucid.Svg (Svg, text_, font_size_, fill_)
--toHtmlRaw svgFile
--latex -interaction=batchmode -halt-on-error
--dvisvgm {file} -n -v 0 -o out
latex :: String -> Svg ()
latex = unsafePerformIO . latexToSVG
latexToSVG :: String -> IO (Svg ())
latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
latex <- requireExecutable "latex"
dvisvgm <- requireExecutable "dvisvgm"
withTempDir $ \tmp_dir -> withTempFile "tex" $ \tex_file -> withTempFile "svg" $ \svg_file -> do
let dvi_file = tmp_dir </> replaceExtension (takeFileName tex_file) "dvi"
writeFile tex_file tex_prologue
appendFile tex_file tex
appendFile tex_file tex_epilogue
runCmd latex ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
runCmd dvisvgm [dvi_file, "-n","-v", "0", "-o",svg_file]
svg_data <- readFile svg_file
evaluate (length svg_data)
return $ toHtmlRaw $ unlines $ drop 1 $ lines svg_data
failedSvg :: String -> Svg ()
failedSvg tex =
text_ [ font_size_ "20"
, fill_ "white"] (toHtml $ "bad latex: "++tex)
runCmd exec args = do
(ret, stdout, stderr) <- readProcessWithExitCode exec args ""
evaluate (length stdout + length stderr)
case ret of
ExitSuccess -> return ()
ExitFailure err -> do
putStrLn $
"Failed to run: " ++ showCommandForUser exec args ++ "\n" ++
"Error code: " ++ show err ++ "\n" ++
"stderr: " ++ show stderr
throwIO (ExitFailure err)
withTempDir action = do
dir <- getTemporaryDirectory
(path, handle) <- openTempFile dir "reanimate-XXXXXX"
hClose handle
removeFile path
createDirectory (dir </> path)
action (dir </> path) `finally` removeDirectoryRecursive (dir </> path)
withTempFile ext action = do
dir <- getTemporaryDirectory
(path, handle) <- openTempFile dir ("reanimate-XXXXXX" <.> ext)
hClose handle
action path `finally` removeFile path
requireExecutable :: String -> IO FilePath
requireExecutable exec = do
mbPath <- findExecutable exec
case mbPath of
Nothing -> error $ "Couldn't find executable: " ++ exec
Just path -> return path
tex_prologue =
"\\documentclass[preview]{standalone}\n\
\\\usepackage[english]{babel}\n\
\\\usepackage{amsmath}\n\
\\\usepackage{amssymb}\n\
\\\usepackage{dsfont}\n\
\\\usepackage{setspace}\n\
\\\usepackage{tipa}\n\
\\\usepackage{relsize}\n\
\\\usepackage{textcomp}\n\
\\\usepackage{mathrsfs}\n\
\\\usepackage{calligra}\n\
\\\usepackage{wasysym}\n\
\\\usepackage{ragged2e}\n\
\\\usepackage{physics}\n\
\\\usepackage{xcolor}\n\
\\\usepackage{textcomp}\n\
\\\usepackage{microtype}\n\
\\\DisableLigatures{encoding = *, family = * }\n\
\%\\usepackage[UTF8]{ctex}\n\
\\\linespread{1}\n\
\\\begin{document}\n"
tex_epilogue = "\n\\end{document}"