Skip to content

Instantly share code, notes, and snippets.

@raylee
Created October 5, 2020 05:34
Show Gist options
  • Save raylee/58574b095ead1a1cedbb5dd6e22edae3 to your computer and use it in GitHub Desktop.
Save raylee/58574b095ead1a1cedbb5dd6e22edae3 to your computer and use it in GitHub Desktop.
Convert markdown to pdf using goldmark and wkhtmltopdf.
package main
import (
"bytes"
"flag"
"io/ioutil"
"log"
"path"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"
pdf "github.com/SebastiaanKlippert/go-wkhtmltopdf"
)
const DisableSandboxing = true
// mdtohtml uses goldmark to render the source from markdown to html
func mdtohtml(source []byte) []byte {
md := goldmark.New(
goldmark.WithExtensions(
extension.GFM,
// extension.NewLinkify(),
extension.Footnote,
extension.NewTable(),
extension.DefinitionList,
extension.NewTypographer(),
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithHardWraps(),
html.WithUnsafe(),
),
)
var buf bytes.Buffer
if err := md.Convert(source, &buf); err != nil {
panic(err)
}
return buf.Bytes()
}
// htmltopdf uses go-wkhtmltopdf to render the source html as a pdf
func htmltopdf(source []byte) []byte {
// Create new PDF generator
pdfg, err := pdf.NewPDFGenerator()
if err != nil {
log.Fatal(err)
}
pdfg.Dpi.Set(600)
pdfg.Orientation.Set(pdf.OrientationPortrait)
pdfg.Grayscale.Set(false)
pdfg.PageSize.Set(pdf.PageSizeLetter)
page := pdf.NewPageReader(bytes.NewReader(source))
// page.FooterRight.Set("[page]")
// page.FooterFontSize.Set(8)
// page.Zoom.Set(0.95)
if DisableSandboxing {
page.Allow.Set(".")
page.EnableLocalFileAccess.Set(true)
}
pdfg.AddPage(page)
// Create PDF document in internal buffer
if err = pdfg.Create(); err != nil {
log.Fatal(err)
}
return pdfg.Buffer().Bytes()
}
var (
savehtml = flag.Bool("html", false, "preserve the html intermediate representation")
)
func SetExt(filename, newext string) string {
ext := path.Ext(filename)
return filename[0:len(filename)-len(ext)] + newext
}
func main() {
flag.Parse()
files := flag.Args()
for _, fn := range files {
md, _ := ioutil.ReadFile(fn)
html := mdtohtml(md)
if *savehtml {
ioutil.WriteFile(SetExt(fn, ".html"), html, 0644)
}
pdf := htmltopdf(html)
ioutil.WriteFile(SetExt(fn, ".pdf"), pdf, 0644)
}
}
@raylee
Copy link
Author

raylee commented Oct 5, 2020

Requires wkhtmltopdf installed as a binary in $PATH.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment