go-hep.org/x/hep@v0.38.1/hplot/htex/latex.go (about) 1 // Copyright ©2020 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package htex // import "go-hep.org/x/hep/hplot/htex" 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "os" 12 "os/exec" 13 "path" 14 ) 15 16 // Handler is the interface that handles the generation of PDFs 17 // from TeX, usually via pdflatex. 18 type Handler interface { 19 // CompileLatex compiles the provided .tex document. 20 CompileLatex(fname string) error 21 } 22 23 var ( 24 // DefaultHandler generates PDFs via the pdflatex executable. 25 // A LaTeX installation is required, as well as the pdflatex command. 26 DefaultHandler = NewHandler("pdflatex") 27 ) 28 29 // NoopLatexHandler is a no-op LaTeX compiler. 30 type NoopHandler struct{} 31 32 func (NoopHandler) CompileLatex(fname string) error { return nil } 33 34 type pdfLatex struct { 35 cmd string 36 } 37 38 // NewHandler returns a Handler compiling .tex documents 39 // with the provided cmd executable. 40 func NewHandler(cmd string) Handler { 41 return &pdfLatex{cmd: cmd} 42 } 43 44 // CompileLatex compiles the provided .tex document. 45 func (pdf *pdfLatex) CompileLatex(fname string) error { 46 tmp, err := os.MkdirTemp("", "hplot-htex-") 47 if err != nil { 48 return fmt.Errorf("htex: could not create tmp dir: %w", err) 49 } 50 defer os.RemoveAll(tmp) 51 52 var ( 53 stdout = new(bytes.Buffer) 54 args = []string{ 55 fmt.Sprintf("-output-directory=%s", tmp), 56 fname, 57 } 58 ) 59 60 cmd := exec.Command(pdf.cmd, args...) 61 cmd.Stdout = stdout 62 cmd.Stderr = stdout 63 64 err = cmd.Run() 65 if err != nil { 66 return fmt.Errorf( 67 "htex: could not generate PDF from vgtex:\n%s\nerror: %w", 68 stdout.Bytes(), 69 err, 70 ) 71 } 72 73 oname := fname[:len(fname)-len(".tex")] + ".pdf" 74 o, err := os.Create(oname) 75 if err != nil { 76 return fmt.Errorf("htex: could not create output PDF file: %w", err) 77 } 78 defer o.Close() 79 80 f, err := os.Open(path.Join(tmp, path.Base(oname))) 81 if err != nil { 82 return fmt.Errorf("htex: could not open generated PDF file: %w", err) 83 } 84 defer f.Close() 85 86 _, err = io.Copy(o, f) 87 if err != nil { 88 return fmt.Errorf("htex: could not copy PDF file: %w", err) 89 } 90 91 err = o.Close() 92 if err != nil { 93 return fmt.Errorf("htex: could not close PDF file: %w", err) 94 } 95 96 return nil 97 } 98 99 var ( 100 _ Handler = (*NoopHandler)(nil) 101 _ Handler = (*pdfLatex)(nil) 102 )