From cb3bf7ba5ad6fdfa39f4e0533bdee90445d8bb89 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 17 Oct 2019 17:33:59 +0100 Subject: [PATCH] Add DisableBorder option to disable the QR Code quiet zone entirely, thus no more margins/borders. Defaults to borders for compatibility. --- example_test.go | 22 ++++++++++++++++++++++ qrcode.go | 22 +++++++++++++++------- qrcode/main.go | 5 +++++ qrcode_test.go | 2 ++ regular_symbol.go | 10 ++++++++-- regular_symbol_test.go | 2 +- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/example_test.go b/example_test.go index 2da3382..5990be0 100644 --- a/example_test.go +++ b/example_test.go @@ -9,6 +9,7 @@ package qrcode import ( "fmt" + "image/color" "os" "testing" ) @@ -29,3 +30,24 @@ func TestExampleWriteFile(t *testing.T) { } } } + +func TestExampleEncodeWithColourAndWithoutBorder(t *testing.T) { + q, err := New("https://example.org", Medium) + if err != nil { + t.Errorf("Error: %s", err) + return + } + + // Optionally, disable the QR Code border. + q.DisableBorder = true + + // Optionally, set the colours. + q.ForegroundColor = color.RGBA{R: 0x33, G: 0x33, B: 0x66, A: 0xff} + q.BackgroundColor = color.RGBA{R: 0xef, G: 0xef, B: 0xef, A: 0xff} + + err = q.WriteFile(256, "example2.png") + if err != nil { + t.Errorf("Error: %s", err) + return + } +} diff --git a/qrcode.go b/qrcode.go index fecee16..74ada71 100644 --- a/qrcode.go +++ b/qrcode.go @@ -135,6 +135,9 @@ type QRCode struct { ForegroundColor color.Color BackgroundColor color.Color + // Disable the QR Code border. + DisableBorder bool + encoder *dataEncoder version qrCodeVersion @@ -193,8 +196,6 @@ func New(content string, level RecoveryLevel) (*QRCode, error) { version: *chosenVersion, } - q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len())) - return q, nil } @@ -239,8 +240,6 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR version: *chosenVersion, } - q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len())) - return q, nil } @@ -251,6 +250,9 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR // The bitmap includes the required "quiet zone" around the QR Code to aid // decoding. func (q *QRCode) Bitmap() [][]bool { + // Build QR code. + q.encode() + return q.symbol.bitmap() } @@ -268,6 +270,9 @@ func (q *QRCode) Bitmap() [][]bool { // negative number to increase the scale of the image. e.g. a size of -5 causes // each module (QR Code "pixel") to be 5px in size. func (q *QRCode) Image(size int) image.Image { + // Build QR code. + q.encode() + // Minimum pixels (both width and height) required. realSize := q.symbol.size @@ -296,11 +301,12 @@ func (q *QRCode) Image(size int) image.Image { // Map each image pixel to the nearest QR code module. modulesPerPixel := float64(realSize) / float64(size) for y := 0; y < size; y++ { + y2 := int(float64(y) * modulesPerPixel) for x := 0; x < size; x++ { - y2 := int(float64(y) * modulesPerPixel) x2 := int(float64(x) * modulesPerPixel) v := bitmap[y2][x2] + if v { pos := img.PixOffset(x, y) img.Pix[pos] = fgClr @@ -368,7 +374,9 @@ func (q *QRCode) WriteFile(size int, filename string) error { // encode completes the steps required to encode the QR Code. These include // adding the terminator bits and padding, splitting the data into blocks and // applying the error correction, and selecting the best data mask. -func (q *QRCode) encode(numTerminatorBits int) { +func (q *QRCode) encode() { + numTerminatorBits := q.version.numTerminatorBitsRequired(q.data.Len()) + q.addTerminatorBits(numTerminatorBits) q.addPadding() @@ -381,7 +389,7 @@ func (q *QRCode) encode(numTerminatorBits int) { var s *symbol var err error - s, err = buildRegularSymbol(q.version, mask, encoded) + s, err = buildRegularSymbol(q.version, mask, encoded, !q.DisableBorder) if err != nil { log.Panic(err.Error()) diff --git a/qrcode/main.go b/qrcode/main.go index e93286e..a38731c 100644 --- a/qrcode/main.go +++ b/qrcode/main.go @@ -17,6 +17,7 @@ func main() { size := flag.Int("s", 256, "image size (pixel)") textArt := flag.Bool("t", false, "print as text-art on stdout") negative := flag.Bool("i", false, "invert black and white") + disableBorder := flag.Bool("d", false, "disable QR Code border") flag.Usage = func() { fmt.Fprintf(os.Stderr, `qrcode -- QR Code encoder in Go https://github.com/skip2/go-qrcode @@ -52,6 +53,10 @@ Usage: q, err = qrcode.New(content, qrcode.Highest) checkError(err) + if *disableBorder { + q.DisableBorder = true + } + if *textArt { art := q.ToString(*negative) fmt.Println(art) diff --git a/qrcode_test.go b/qrcode_test.go index 258f792..dc4887d 100644 --- a/qrcode_test.go +++ b/qrcode_test.go @@ -151,6 +151,8 @@ func TestQRCodeISOAnnexIExample(t *testing.T) { err.Error()) } + q.encode() + const expectedMask int = 2 if q.mask != 2 { diff --git a/regular_symbol.go b/regular_symbol.go index 134be18..51eb148 100644 --- a/regular_symbol.go +++ b/regular_symbol.go @@ -105,13 +105,19 @@ var ( ) func buildRegularSymbol(version qrCodeVersion, mask int, - data *bitset.Bitset) (*symbol, error) { + data *bitset.Bitset, includeQuietZone bool) (*symbol, error) { + + quietZoneSize := 0 + if includeQuietZone { + quietZoneSize = version.quietZoneSize() + } + m := ®ularSymbol{ version: version, mask: mask, data: data, - symbol: newSymbol(version.symbolSize(), version.quietZoneSize()), + symbol: newSymbol(version.symbolSize(), quietZoneSize), size: version.symbolSize(), } diff --git a/regular_symbol_test.go b/regular_symbol_test.go index 9e274db..936fdc0 100644 --- a/regular_symbol_test.go +++ b/regular_symbol_test.go @@ -19,7 +19,7 @@ func TestBuildRegularSymbol(t *testing.T) { data.AppendNumBools(8, false) } - s, err := buildRegularSymbol(*v, k, data) + s, err := buildRegularSymbol(*v, k, data, false) if err != nil { fmt.Println(err.Error())