summaryrefslogtreecommitdiff
path: root/pdf/create.go
blob: ecec798cac6371bc9c8b2574d17e8901c2e1a7e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// The PDF package of PrintDraftFast creates a PDF out of the Lex markdown parsetree.
package pdf

import (
	"git.kiefte.eu/lapingvino/printdraftfast/lex"
	"git.kiefte.eu/lapingvino/printdraftfast/rules"
	"git.kiefte.eu/lapingvino/printdraftfast/font"

	"strconv"
	"strings"
	"regexp"
	"github.com/phpdave11/gofpdf"
)

type Tree struct {
	PDF   *gofpdf.Fpdf
	Rules rules.Set
	F     lex.Document
	HTML  gofpdf.HTMLBasicType
}

func (t Tree) pr(a string, text string) {
	line(t.PDF, t.Rules.Get(a), t.HTML, t.Rules.Get(a).Prefix+text+t.Rules.Get(a).Postfix)
}

func (t Tree) Render() {
	var block string
	var lastsection int
	for _, row := range t.F {
		switch row.Type {
		case "newpage":
			block = ""
			t.PDF.AddPage()
			t.PDF.SetHeaderFuncMode(func() {
				t.PDF.SetFont("CourierPrime", "", 12)
				t.PDF.SetXY(-1, 0.5)
				t.PDF.Cell(0, 0, strconv.Itoa(t.PDF.PageNo())+".")
			}, true)
			continue
		case "titlepage":
			block = "title"
			t.PDF.SetY(4)
		case "title", "Title":
			t.PDF.SetTitle(row.Contents, true)
		case "metasection":
			block = "meta"
			t.PDF.SetY(-2)
		}

		var contents string
		var level int
		if row.Type == "section" {
			contents = strings.TrimLeft(row.Contents, "#")
			level = len(row.Contents) - len(contents)
			contents = strings.TrimLeft(contents, " ")
			lastsection = level
		} else if row.Type == "scene" {
			level = lastsection + 1
			contents = row.Contents
		}
		if contents != "" {
			t.PDF.Bookmark(contents, level, -1)
		}

		if t.Rules.Get(row.Type).Hide && block == "" {
			continue
		}
		if block != "" {
			row.Type = block
		}
		t.pr(row.Type, row.Contents)
	}
}

var (
	bolditalic = regexp.MustCompile("\\*{3}([^\\*\n]+)\\*{3}")
	bold = regexp.MustCompile("\\*{2}([^\\*\n]+)\\*{2}")
	italic = regexp.MustCompile("\\*{1}([^\\*\n]+)\\*{1}")
	underline = regexp.MustCompile("_{1}([^\\*\n]+)_{1}")
)

func line(pdf *gofpdf.Fpdf, format rules.Format, html gofpdf.HTMLBasicType, text string) {
	pdf.SetFont(format.Font, format.Style, format.Size)
	pdf.SetX(0)
	pdf.SetLeftMargin(format.Left)
	pdf.SetRightMargin(format.Right)

	text = strings.TrimRight(text, "\r\n")

	if strings.ContainsAny(text, "*_") {
		text = bolditalic.ReplaceAllString(text, "<b><i>$1</i></b>")
		text = bold.ReplaceAllString(text, "<b>$1</b>")
		text = italic.ReplaceAllString(text, "<i>$1</i>")
		text = underline.ReplaceAllString(text, "<u>$1</u>")

		if format.Align == "C" {
			text = "<center>"+text+"</center>"
		}
		html.Write(0.165, text)
		pdf.SetY(pdf.GetY()+0.165)
		return
	}

	pdf.MultiCell(0, 0.165, text, "", format.Align, false)
}

func Create(file string, format rules.Set, contents lex.Document) {
	pdf := gofpdf.New("P", "in", "Letter", "")
	pdf.AddUTF8FontFromBytes("CourierPrime", "", font.MustAsset("Courier-Prime.ttf"))
	pdf.AddUTF8FontFromBytes("CourierPrime", "B", font.MustAsset("Courier-Prime-Bold.ttf"))
	pdf.AddUTF8FontFromBytes("CourierPrime", "I", font.MustAsset("Courier-Prime-Italic.ttf"))
	pdf.AddUTF8FontFromBytes("CourierPrime", "BI", font.MustAsset("Courier-Prime-Bold-Italic.ttf"))
	pdf.AddPage()
	pdf.SetMargins(1, 1, 1)
	pdf.SetXY(1, 1)
	f := Tree{
		PDF:   pdf,
		Rules: format,
		F:     contents,
		HTML:  pdf.HTMLBasicNew(),
	}
	f.Render()
	err := pdf.OutputFileAndClose(file)
	if err != nil {
		panic(err)
	}
}