mailinglabelmaker/main.go

124 lines
3.3 KiB
Go

package main
import (
"bytes"
"flag"
"fmt"
"os"
"strings"
"text/template"
"github.com/jung-kurt/gofpdf"
)
var (
flagInputCsv = flag.String("csv", "", "CSV file (downloaded from Patreon)")
flagOutputPdf = flag.String("o", "out.pdf", "filename to output PDF to")
flagPortrait = flag.Bool("portrait", true, "portrait mode?")
flagUnitStr = flag.String("unitStr", "mm", "units to use for other measurements")
flagPaperType = flag.String("paper", "Letter", "paper size")
flagCols = flag.Int("cols", 3, "number of columns")
flagRows = flag.Int("row", 10, "number of rows")
flagSkipLabels = flag.Int("skip", 0, "skip labels (useful for printing on partially-printed label sheets")
flagOffsetX = flag.Float64("x", 6.5, "left margin")
flagOffsetY = flag.Float64("y", 12.7, "top margin")
flagLabelWidth = flag.Float64("w", 66.8, "label width")
flagLabelHeight = flag.Float64("h", 25.4, "label height")
flagGapX = flag.Float64("gapx", 3.4, "gap between columns")
flagGapY = flag.Float64("gapy", 0., "gap between rows")
flagDrawLines = flag.Bool("lines", false, "draw lines?")
flagFontSize = flag.Float64("fontsize", 10, "font size")
flagFontFamily = flag.String("fontfamily", "Arial", "font family")
flagFontStyle = flag.String("fontstyle", "", "font style (B for bold)")
flagTemplate = flag.String("template", "{{.Addressee}}\n{{.Street}}\n{{.City}}, {{.State}}\n{{.Zip}}, {{.Country}}\n", "mailing label template")
lineHeight = 4.0
)
func main() {
flag.Parse()
if *flagInputCsv == "" {
fmt.Println("Must specify input csv with -csv")
flag.Usage()
os.Exit(1)
}
pL := "P"
if !*flagPortrait {
pL = "L"
}
pdf := gofpdf.New(pL, *flagUnitStr, *flagPaperType, "")
pdf.SetFont(*flagFontFamily, *flagFontStyle, *flagFontSize)
data := LoadCSVFromFile(*flagInputCsv)
DoTheThing(pdf, data)
err := pdf.OutputFileAndClose(*flagOutputPdf)
if err != nil {
panic(err)
}
}
func DoTheThing(pdf *gofpdf.Fpdf, data CSV) {
tpl, err := template.New("mailing labels").Parse(*flagTemplate)
if err != nil {
panic(err)
}
tr := pdf.UnicodeTranslatorFromDescriptor("")
for i := 0; i < data.NumRecords(); {
AddGriddedPage(pdf)
for x := 0; x < *flagCols; x++ {
for y := 0; y < *flagRows; y++ {
if *flagSkipLabels > 0 {
*flagSkipLabels--
continue
}
for ; i < data.NumRecords() && data.PatreonEmptyAddress(i); i++ {
fmt.Printf("Warning: skipping empty addressee: %s\n", data.GetField(i, "Name"))
fmt.Printf("%v\n", data.Record(i))
}
if i >= data.NumRecords() {
return
}
lx := *flagOffsetX + (*flagLabelWidth + *flagGapX) * float64(x) + 4.
ly := *flagOffsetY + (*flagLabelHeight + *flagGapY) * float64(y) + 8.
var buf bytes.Buffer
err := tpl.Execute(&buf, data.Record(i))
if err != nil {
panic(err)
}
DrawText(pdf, tr(buf.String()), lx, ly)
i++
}
}
}
}
func AddGriddedPage(pdf *gofpdf.Fpdf) {
pdf.AddPage()
if !*flagDrawLines {
return
}
for x := 0; x < *flagCols; x++ {
for y := 0; y < *flagRows; y++ {
lx := *flagOffsetX + (*flagLabelWidth + *flagGapX) * float64(x)
ly := *flagOffsetY + (*flagLabelHeight + *flagGapY) * float64(y)
pdf.Rect(lx, ly, *flagLabelWidth, *flagLabelHeight, "D")
}
}
}
func DrawText(pdf *gofpdf.Fpdf, str string, x, y float64) {
lines := strings.Split(str, "\n")
for _, s := range lines {
pdf.Text(x, y, s)
y += lineHeight
}
}