implement web handler for QR code generation
This commit is contained in:
90
qrcodegenerator.go
Normal file
90
qrcodegenerator.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package qrbill
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"os"
|
||||
|
||||
"github.com/boombuler/barcode"
|
||||
"github.com/boombuler/barcode/qr"
|
||||
)
|
||||
|
||||
// This is a port of the Java 1.7 reference example from paymentstandards.ch:
|
||||
// https://www.paymentstandards.ch/dam/downloads/qrcodegenerator.java
|
||||
//
|
||||
// The priority was to write idiomatic Go code first, and match the reference
|
||||
// example as good as possible second.
|
||||
|
||||
const (
|
||||
swissCrossEdgeSidePx = 166
|
||||
|
||||
swissCrossEdgeSideMm = 7
|
||||
|
||||
// The edge length of the qrcode inclusive its white border.
|
||||
qrCodeEdgeSideMm = 42 + 13
|
||||
|
||||
qrCodeEdgeSidePx = swissCrossEdgeSidePx / swissCrossEdgeSideMm * qrCodeEdgeSideMm
|
||||
)
|
||||
|
||||
func generateSwissQrCode(payload string) (image.Image, error) {
|
||||
// generate the qr code from the payload
|
||||
qrCodeImage, err := generateQrCodeImage(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// overlay the qr code with a Swiss Cross
|
||||
return overlayWithSwissCross(qrCodeImage)
|
||||
}
|
||||
|
||||
func generateQrCodeImage(payload string) (image.Image, error) {
|
||||
code, err := qr.Encode(payload, qr.M, qr.Unicode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qrcode, err := barcode.Scale(code, qrCodeEdgeSidePx, qrCodeEdgeSidePx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return qrcode, nil
|
||||
}
|
||||
|
||||
func overlayWithSwissCross(qrCodeImage image.Image) (image.Image, error) {
|
||||
// TODO: bundle the swiss cross image instead of reading it
|
||||
const swissCrossPath = "/home/michael/go/src/github.com/stapelberg/qrbill/third_party/swiss-cross/CH-Kreuz_7mm/CH-Kreuz_7mm.png"
|
||||
|
||||
f, err := os.Open(swissCrossPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
swissCrossImage, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
combinedQrCodeImage := image.NewRGBA(qrCodeImage.Bounds())
|
||||
|
||||
{
|
||||
sr := qrCodeImage.Bounds() // source rect
|
||||
destRect := image.Rectangle{image.Point{0, 0}, sr.Size()}
|
||||
draw.Draw(combinedQrCodeImage, destRect, qrCodeImage, sr.Min, draw.Src)
|
||||
}
|
||||
|
||||
{
|
||||
sr := swissCrossImage.Bounds() // source rect
|
||||
const swissCrossPosition = (qrCodeEdgeSidePx / 2) - (swissCrossEdgeSidePx / 2)
|
||||
destPoint := image.Point{
|
||||
X: swissCrossPosition,
|
||||
Y: swissCrossPosition,
|
||||
}
|
||||
// Convert the source image bounds into the destination image’s coordinate
|
||||
// space:
|
||||
destRect := image.Rectangle{
|
||||
destPoint,
|
||||
destPoint.Add(sr.Size()),
|
||||
}
|
||||
draw.Draw(combinedQrCodeImage, destRect, swissCrossImage, sr.Min, draw.Src)
|
||||
}
|
||||
return combinedQrCodeImage, nil
|
||||
}
|
||||
Reference in New Issue
Block a user