initial commit

This commit is contained in:
erinn 2019-12-18 11:53:51 -08:00
commit b2bf4ca768
5 changed files with 213 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
vendor
.idea

57
csv.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"encoding/csv"
"os"
)
type CSV struct {
index map[string]int
records [][]string
}
func LoadCSVFromFile(filename string) CSV {
f, err := os.Open(filename)
if err != nil {
panic(err)
}
r := csv.NewReader(f)
records, err := r.ReadAll()
index := make(map[string]int)
if err != nil {
panic(err)
}
for i := 0; i < len(records[0]); i++ {
index[records[0][i]] = i
}
csvo := CSV{index: index, records: records[1:]}
return csvo
}
func (this *CSV) NumRecords() int {
return len(this.records)
}
func (this *CSV) Record(index int) map[string]string {
ret := make(map[string]string)
for k, idx := range this.index {
ret[k] = this.records[index][idx]
}
return ret
}
func (this *CSV) GetField(index int, fieldLabel string) string {
return this.records[index][this.indexOfField(fieldLabel)]
}
func (this *CSV) PatreonEmptyAddress(index int) bool {
r := this.Record(index)
return r["Addressee"] == "" && r["Street"] == "" && r["City"] == "" && r["State"] == "" && r["Zip"] == "" && r["Country"] == ""
}
func (this *CSV) indexOfField(fieldLabel string) int {
return this.index[fieldLabel]
}

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module git.openprivacy.ca/erinn/pdftest
go 1.12
require (
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8 // indirect
github.com/jung-kurt/gofpdf v1.16.2
)

23
go.sum Normal file
View File

@ -0,0 +1,23 @@
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8 h1:HVoyxfivFaEtkfO5K3piD6oq6MQB1qGF5IB2EYXeCW8=
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8/go.mod h1:6I+vO9Aagv3/yUWv+e7A57H8tgXgR67FCjfSj9Pp970=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

123
main.go Normal file
View File

@ -0,0 +1,123 @@
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"))
}
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
}
}