Skip to content

Instantly share code, notes, and snippets.

@henkman
Last active October 11, 2018 13:26
Show Gist options
  • Save henkman/5870bfe0b20c88976395f8ffe3347dae to your computer and use it in GitHub Desktop.
Save henkman/5870bfe0b20c88976395f8ffe3347dae to your computer and use it in GitHub Desktop.
markdown to pdf converter
package main
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/jung-kurt/gofpdf"
blackfriday "gopkg.in/russross/blackfriday.v2"
)
const FONT = "Times"
func renderHeading(pdf *gofpdf.Fpdf, node *blackfriday.Node) {
text := node.FirstChild
if text != nil {
switch node.HeadingData.Level {
case 1:
pdf.SetFont(FONT, "B", 32)
case 2:
pdf.SetFont(FONT, "B", 24)
case 3:
pdf.SetFont(FONT, "B", 18.72)
case 4:
pdf.SetFont(FONT, "B", 18.4)
case 5:
pdf.SetFont(FONT, "B", 13.28)
case 6:
fallthrough
default:
pdf.SetFont(FONT, "B", 10.72)
}
_, ht := pdf.GetFontSize()
pdf.Cell(0, ht, string(text.Literal))
pdf.Ln(16)
}
}
func renderParagraph(pdf *gofpdf.Fpdf, node *blackfriday.Node, margin float64) {
cn := node.FirstChild
for cn != nil {
switch cn.Type {
case blackfriday.Text:
pdf.SetFont(FONT, "", 12)
_, ht := pdf.GetFontSize()
pdf.Write(ht, pdf.UnicodeTranslatorFromDescriptor("")(string(cn.Literal)))
case blackfriday.Link:
pdf.SetFont(FONT, "", 12)
_, ht := pdf.GetFontSize()
tit := cn.LinkData.Destination
if cn.FirstChild != nil {
tit = cn.FirstChild.Literal
}
trans := pdf.UnicodeTranslatorFromDescriptor("")
pdf.WriteLinkString(ht, trans(string(tit)), string(cn.LinkData.Destination))
default:
fmt.Println("renderParagraph new type:", cn.Type)
}
cn = cn.Next
}
pdf.Ln(margin)
}
func renderList(pdf *gofpdf.Fpdf, node *blackfriday.Node, margin float64) {
left, _, _, _ := pdf.GetMargins()
pdf.SetLeftMargin(left * 2)
item := node.FirstChild
for item != nil {
c := item.FirstChild
for c != nil {
switch c.Type {
case blackfriday.Paragraph:
pdf.SetFont(FONT, "", 12)
_, ht := pdf.GetFontSize()
pdf.Write(ht, "- ")
renderParagraph(pdf, c, 5)
case blackfriday.List:
renderList(pdf, c, 0)
default:
fmt.Println("renderParagraph new type:", c.Type)
}
c = c.Next
}
item = item.Next
}
pdf.SetLeftMargin(left)
pdf.Ln(margin)
}
func main() {
var opts struct {
In string
Out string
}
flag.StringVar(&opts.In, "i", "", "input markdown file, if not supplied use stdin")
flag.StringVar(&opts.Out, "o", "", "output pdf file, if not supplied use stdout")
flag.Parse()
var in io.Reader
if opts.In == "" {
in = os.Stdin
} else {
fd, err := os.Open(opts.In)
if err != nil {
panic(err)
}
defer fd.Close()
in = fd
}
var out io.Writer
if opts.Out == "" {
out = os.Stdout
} else {
fd, err := os.OpenFile(opts.Out, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0750)
if err != nil {
panic(err)
}
defer fd.Close()
out = fd
}
raw, err := ioutil.ReadAll(in)
if err != nil {
panic(err)
}
root := blackfriday.New().Parse(raw)
node := root.FirstChild
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
for node != nil {
switch node.Type {
case blackfriday.Heading:
renderHeading(pdf, node)
case blackfriday.Paragraph:
renderParagraph(pdf, node, 10)
case blackfriday.List:
renderList(pdf, node, 5)
case blackfriday.HorizontalRule:
_, y := pdf.GetXY()
left, _, right, _ := pdf.GetMargins()
w, _ := pdf.GetPageSize()
pdf.Line(left, y, w-right, y)
pdf.DrawPath("")
pdf.Ln(5)
}
node = node.Next
}
if err := pdf.Output(out); err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment