bundle swiss cross image file to avoid file system dependency
This commit is contained in:
7
GENERATED_swisscross.go
Normal file
7
GENERATED_swisscross.go
Normal file
File diff suppressed because one or more lines are too long
3
generate.go
Normal file
3
generate.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package qrbill
|
||||||
|
|
||||||
|
//go:generate sh -c "go run goembed.go -package qrbill -var swisscross third_party/swiss-cross/CH-Kreuz_7mm/CH-Kreuz_7mm.png > GENERATED_swisscross.go && gofmt -w GENERATED_swisscross.go"
|
||||||
190
goembed.go
Normal file
190
goembed.go
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// copied from https://github.com/dsymonds/goembed/ with pull requests applied
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
// goembed generates a Go source file from an input file.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"text/template"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
packageFlag = flag.String("package", "", "Go package name")
|
||||||
|
varFlag = flag.String("var", "", "Go var name")
|
||||||
|
gzipFlag = flag.Bool("gzip", false, "Whether to gzip contents")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
fmt.Printf("package %s\n\n", *packageFlag)
|
||||||
|
|
||||||
|
if *gzipFlag {
|
||||||
|
err := gzipPrologue.Execute(os.Stdout, map[string]interface{}{
|
||||||
|
"Args": flag.Args(),
|
||||||
|
"VarName": *varFlag,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag.NArg() > 0 {
|
||||||
|
fmt.Println("// Table of contents")
|
||||||
|
fmt.Printf("var %v = map[string][]byte{\n", *varFlag)
|
||||||
|
for i, filename := range flag.Args() {
|
||||||
|
fmt.Printf("\t%#v: %s_%d,\n", filename, *varFlag, i)
|
||||||
|
}
|
||||||
|
fmt.Println("}")
|
||||||
|
|
||||||
|
// Using a separate variable for each []byte, instead of
|
||||||
|
// combining them into a single map literal, enables a storage
|
||||||
|
// optimization: the compiler places the data directly in the
|
||||||
|
// program's noptrdata section instead of the heap.
|
||||||
|
for i, filename := range flag.Args() {
|
||||||
|
if err := oneVar(fmt.Sprintf("%s_%d", *varFlag, i), filename); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := oneVarReader(*varFlag, os.Stdin); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneVar(varName, filename string) error {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
return oneVarReader(varName, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneVarReader(varName string, r io.Reader) error {
|
||||||
|
// Generate []byte(<big string constant>) instead of []byte{<list of byte values>}.
|
||||||
|
// The latter causes a memory explosion in the compiler (60 MB of input chews over 9 GB RAM).
|
||||||
|
// Doing a string conversion avoids some of that, but incurs a slight startup cost.
|
||||||
|
if !*gzipFlag {
|
||||||
|
fmt.Printf(`var %s = []byte("`, varName)
|
||||||
|
} else {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
gzw, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||||
|
if _, err := io.Copy(gzw, r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := gzw.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("var %s []byte // set in init\n\n", varName)
|
||||||
|
fmt.Printf(`var %s_gzip = []byte("`, varName)
|
||||||
|
r = &buf
|
||||||
|
}
|
||||||
|
|
||||||
|
bufw := bufio.NewWriter(os.Stdout)
|
||||||
|
if _, err := io.Copy(&writer{w: bufw}, r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := bufw.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(`")`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type writer struct {
|
||||||
|
w io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writer) Write(data []byte) (n int, err error) {
|
||||||
|
n = len(data)
|
||||||
|
|
||||||
|
for err == nil && len(data) > 0 {
|
||||||
|
// https://golang.org/ref/spec#String_literals: "Within the quotes, any
|
||||||
|
// character may appear except newline and unescaped double quote. The
|
||||||
|
// text between the quotes forms the value of the literal, with backslash
|
||||||
|
// escapes interpreted as they are in rune literals […]."
|
||||||
|
switch b := data[0]; b {
|
||||||
|
case '\\':
|
||||||
|
_, err = w.w.Write([]byte(`\\`))
|
||||||
|
case '"':
|
||||||
|
_, err = w.w.Write([]byte(`\"`))
|
||||||
|
case '\n':
|
||||||
|
_, err = w.w.Write([]byte(`\n`))
|
||||||
|
|
||||||
|
case '\x00':
|
||||||
|
// https://golang.org/ref/spec#Source_code_representation: "Implementation
|
||||||
|
// restriction: For compatibility with other tools, a compiler may
|
||||||
|
// disallow the NUL character (U+0000) in the source text."
|
||||||
|
_, err = w.w.Write([]byte(`\x00`))
|
||||||
|
|
||||||
|
default:
|
||||||
|
// https://golang.org/ref/spec#Source_code_representation: "Implementation
|
||||||
|
// restriction: […] A byte order mark may be disallowed anywhere else in
|
||||||
|
// the source."
|
||||||
|
const byteOrderMark = '\uFEFF'
|
||||||
|
|
||||||
|
if r, size := utf8.DecodeRune(data); r != utf8.RuneError && r != byteOrderMark {
|
||||||
|
_, err = w.w.Write(data[:size])
|
||||||
|
data = data[size:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fmt.Fprintf(w.w, `\x%02x`, b)
|
||||||
|
}
|
||||||
|
data = data[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return n - len(data), err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gzipPrologue = template.Must(template.New("").Parse(`
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var (
|
||||||
|
r *gzip.Reader
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
{{ if gt (len .Args) 0 }}
|
||||||
|
{{ range $idx, $var := .Args }}
|
||||||
|
{{ $n := printf "%s_%d" $.VarName $idx }}
|
||||||
|
r, err = gzip.NewReader(bytes.NewReader({{ $n }}_gzip))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
{{ $n }}, err = ioutil.ReadAll(r)
|
||||||
|
r.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ else }}
|
||||||
|
r, err = gzip.NewReader(bytes.NewReader({{ .VarName }}_gzip))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
{{ .VarName }}, err = ioutil.ReadAll(r)
|
||||||
|
r.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
}
|
||||||
|
`))
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package qrbill
|
package qrbill
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/boombuler/barcode"
|
"github.com/boombuler/barcode"
|
||||||
"github.com/boombuler/barcode/qr"
|
"github.com/boombuler/barcode/qr"
|
||||||
@@ -50,15 +50,8 @@ func generateQrCodeImage(payload string) (image.Image, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func overlayWithSwissCross(qrCodeImage image.Image) (image.Image, error) {
|
func overlayWithSwissCross(qrCodeImage image.Image) (image.Image, error) {
|
||||||
// TODO: bundle the swiss cross image instead of reading it
|
b := swisscross["third_party/swiss-cross/CH-Kreuz_7mm/CH-Kreuz_7mm.png"]
|
||||||
const swissCrossPath = "/home/michael/go/src/github.com/stapelberg/qrbill/third_party/swiss-cross/CH-Kreuz_7mm/CH-Kreuz_7mm.png"
|
swissCrossImage, _, err := image.Decode(bytes.NewReader(b))
|
||||||
|
|
||||||
f, err := os.Open(swissCrossPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
swissCrossImage, _, err := image.Decode(f)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user