initial commit
This commit is contained in:
commit
b2bf4ca768
|
@ -0,0 +1,2 @@
|
|||
vendor
|
||||
.idea
|
|
@ -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]
|
||||
}
|
|
@ -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
|
||||
)
|
|
@ -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=
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue