From 66ccdc29e9d745d48ff1474b6c9ad8a342018146 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Wed, 26 Feb 2025 22:59:11 +0100 Subject: [PATCH] fix qr-code generation for large configurations (#374) --- go.mod | 1 + go.sum | 2 + internal/app/configfile/manager.go | 18 ++++-- internal/app/configfile/qrwriter.go | 88 ----------------------------- 4 files changed, 16 insertions(+), 93 deletions(-) delete mode 100644 internal/app/configfile/qrwriter.go diff --git a/go.mod b/go.mod index c4b86eec..e74539db 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/vishvananda/netlink v1.3.0 github.com/xhit/go-simple-mail/v2 v2.16.0 github.com/yeqown/go-qrcode/v2 v2.2.5 + github.com/yeqown/go-qrcode/writer/compressed v1.0.1 golang.org/x/crypto v0.34.0 golang.org/x/oauth2 v0.26.0 golang.org/x/sys v0.30.0 diff --git a/go.sum b/go.sum index ef255fb9..c4122e0b 100644 --- a/go.sum +++ b/go.sum @@ -284,6 +284,8 @@ github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICL github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk= github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw= +github.com/yeqown/go-qrcode/writer/compressed v1.0.1 h1:0el6zOppx3oPiYWMUJWRYGvxWYh8MDmUU0j3rSWGWlI= +github.com/yeqown/go-qrcode/writer/compressed v1.0.1/go.mod h1:BJScsGUIKM+eg0CCLCcVaDTaclDM1IEXtq2r8qQnDKk= github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0= github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/internal/app/configfile/manager.go b/internal/app/configfile/manager.go index 3ec1a961..9a7269c4 100644 --- a/internal/app/configfile/manager.go +++ b/internal/app/configfile/manager.go @@ -15,6 +15,7 @@ import ( "github.com/sirupsen/logrus" evbus "github.com/vardius/message-bus" "github.com/yeqown/go-qrcode/v2" + "github.com/yeqown/go-qrcode/writer/compressed" ) type Manager struct { @@ -27,7 +28,13 @@ type Manager struct { wg WireguardDatabaseRepo } -func NewConfigFileManager(cfg *config.Config, bus evbus.MessageBus, users UserDatabaseRepo, wg WireguardDatabaseRepo, fsRepo FileSystemRepo) (*Manager, error) { +func NewConfigFileManager( + cfg *config.Config, + bus evbus.MessageBus, + users UserDatabaseRepo, + wg WireguardDatabaseRepo, + fsRepo FileSystemRepo, +) (*Manager, error) { tplHandler, err := newTemplateHandler() if err != nil { return nil, fmt.Errorf("failed to initialize template handler: %w", err) @@ -156,18 +163,19 @@ func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifi return nil, fmt.Errorf("failed to read peer config for %s: %w", id, err) } - code, err := qrcode.New(sb.String()) + code, err := qrcode.NewWith(sb.String(), + qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow), qrcode.WithEncodingMode(qrcode.EncModeByte)) if err != nil { - return nil, fmt.Errorf("failed to initializeqr code for %s: %w", id, err) + return nil, fmt.Errorf("failed to initialize qr code for %s: %w", id, err) } buf := bytes.NewBuffer(nil) wr := nopCloser{Writer: buf} - option := Option{ + option := compressed.Option{ Padding: 8, // padding pixels around the qr code. BlockSize: 4, // block pixels which represents a bit data. } - qrWriter := NewCompressedWriter(wr, &option) + qrWriter := compressed.NewWithWriter(wr, &option) err = code.Save(qrWriter) if err != nil { return nil, fmt.Errorf("failed to write code for %s: %w", id, err) diff --git a/internal/app/configfile/qrwriter.go b/internal/app/configfile/qrwriter.go deleted file mode 100644 index 2646319e..00000000 --- a/internal/app/configfile/qrwriter.go +++ /dev/null @@ -1,88 +0,0 @@ -package configfile - -// waiting for https://github.com/yeqown/go-qrcode/pull/85 to get merged -// meanwhile we use our own writer implementation - -import ( - "image" - "image/color" - "image/png" - "io" - - "github.com/yeqown/go-qrcode/v2" -) - -type Option struct { - Padding int - BlockSize int -} - -// compressedWriter implements issue#69, generating compressed images -// in some special situations, such as, network transferring. -// https://github.com/yeqown/go-qrcode/issues/69 -type compressedWriter struct { - fd io.WriteCloser - - option *Option -} - -var ( - backgroundColor = color.Gray{Y: 0xff} - foregroundColor = color.Gray{Y: 0x00} -) - -func NewCompressedWriter(writer io.WriteCloser, opt *Option) qrcode.Writer { - return compressedWriter{fd: writer, option: opt} -} - -func (w compressedWriter) Write(mat qrcode.Matrix) error { - padding := w.option.Padding - blockWidth := w.option.BlockSize - width := mat.Width()*blockWidth + 2*padding - height := width - - img := image.NewPaletted( - image.Rect(0, 0, width, height), - color.Palette([]color.Color{backgroundColor, foregroundColor}), - ) - bgColor := uint8(img.Palette.Index(backgroundColor)) - fgColor := uint8(img.Palette.Index(foregroundColor)) - - rectangle := func(x1, y1 int, x2, y2 int, img *image.Paletted, color uint8) { - for x := x1; x < x2; x++ { - for y := y1; y < y2; y++ { - pos := img.PixOffset(x, y) - img.Pix[pos] = color - } - } - } - - // background - rectangle(0, 0, width, height, img, bgColor) - - mat.Iterate(qrcode.IterDirection_COLUMN, func(x int, y int, v qrcode.QRValue) { - sx := x*blockWidth + padding - sy := y*blockWidth + padding - es := (x+1)*blockWidth + padding - ey := (y+1)*blockWidth + padding - - if v.IsSet() { - rectangle(sx, sy, es, ey, img, fgColor) - } - - //switch v.IsSet() { - //case false: - // gray = backgroundColor - //default: - // gray = foregroundColor - //} - - }) - - encoder := png.Encoder{CompressionLevel: png.BestCompression} - return encoder.Encode(w.fd, img) -} - -func (w compressedWriter) Close() error { - return w.fd.Close() -}