|
@@ -51,6 +51,7 @@ package qrcode
|
|
|
import (
|
|
import (
|
|
|
"bytes"
|
|
"bytes"
|
|
|
"errors"
|
|
"errors"
|
|
|
|
|
+ "fmt"
|
|
|
"image"
|
|
"image"
|
|
|
"image/color"
|
|
"image/color"
|
|
|
"image/png"
|
|
"image/png"
|
|
@@ -135,6 +136,9 @@ type QRCode struct {
|
|
|
ForegroundColor color.Color
|
|
ForegroundColor color.Color
|
|
|
BackgroundColor color.Color
|
|
BackgroundColor color.Color
|
|
|
|
|
|
|
|
|
|
+ // Disable the QR Code border.
|
|
|
|
|
+ DisableBorder bool
|
|
|
|
|
+
|
|
|
encoder *dataEncoder
|
|
encoder *dataEncoder
|
|
|
version qrCodeVersion
|
|
version qrCodeVersion
|
|
|
|
|
|
|
@@ -193,12 +197,16 @@ func New(content string, level RecoveryLevel) (*QRCode, error) {
|
|
|
version: *chosenVersion,
|
|
version: *chosenVersion,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
|
|
|
|
-
|
|
|
|
|
return q, nil
|
|
return q, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
|
|
|
|
|
|
|
+// NewWithForcedVersion constructs a QRCode of a specific version.
|
|
|
|
|
+//
|
|
|
|
|
+// var q *qrcode.QRCode
|
|
|
|
|
+// q, err := qrcode.NewWithForcedVersion("my content", 25, qrcode.Medium)
|
|
|
|
|
+//
|
|
|
|
|
+// An error occurs in case of invalid version.
|
|
|
|
|
+func NewWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
|
|
|
var encoder *dataEncoder
|
|
var encoder *dataEncoder
|
|
|
|
|
|
|
|
switch {
|
|
switch {
|
|
@@ -209,7 +217,7 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR
|
|
|
case version >= 27 && version <= 40:
|
|
case version >= 27 && version <= 40:
|
|
|
encoder = newDataEncoder(dataEncoderType27To40)
|
|
encoder = newDataEncoder(dataEncoderType27To40)
|
|
|
default:
|
|
default:
|
|
|
- log.Fatalf("Invalid version %d (expected 1-40 inclusive)", version)
|
|
|
|
|
|
|
+ return nil, fmt.Errorf("Invalid version %d (expected 1-40 inclusive)", version)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var encoded *bitset.Bitset
|
|
var encoded *bitset.Bitset
|
|
@@ -225,6 +233,13 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR
|
|
|
return nil, errors.New("cannot find QR Code version")
|
|
return nil, errors.New("cannot find QR Code version")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if encoded.Len() > chosenVersion.numDataBits() {
|
|
|
|
|
+ return nil, fmt.Errorf("Cannot encode QR code: content too large for fixed size QR Code version %d (encoded length is %d bits, maximum length is %d bits)",
|
|
|
|
|
+ version,
|
|
|
|
|
+ encoded.Len(),
|
|
|
|
|
+ chosenVersion.numDataBits())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
q := &QRCode{
|
|
q := &QRCode{
|
|
|
Content: content,
|
|
Content: content,
|
|
|
|
|
|
|
@@ -239,8 +254,6 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR
|
|
|
version: *chosenVersion,
|
|
version: *chosenVersion,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
|
|
|
|
-
|
|
|
|
|
return q, nil
|
|
return q, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -251,6 +264,9 @@ func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QR
|
|
|
// The bitmap includes the required "quiet zone" around the QR Code to aid
|
|
// The bitmap includes the required "quiet zone" around the QR Code to aid
|
|
|
// decoding.
|
|
// decoding.
|
|
|
func (q *QRCode) Bitmap() [][]bool {
|
|
func (q *QRCode) Bitmap() [][]bool {
|
|
|
|
|
+ // Build QR code.
|
|
|
|
|
+ q.encode()
|
|
|
|
|
+
|
|
|
return q.symbol.bitmap()
|
|
return q.symbol.bitmap()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -268,6 +284,9 @@ func (q *QRCode) Bitmap() [][]bool {
|
|
|
// negative number to increase the scale of the image. e.g. a size of -5 causes
|
|
// 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.
|
|
// each module (QR Code "pixel") to be 5px in size.
|
|
|
func (q *QRCode) Image(size int) image.Image {
|
|
func (q *QRCode) Image(size int) image.Image {
|
|
|
|
|
+ // Build QR code.
|
|
|
|
|
+ q.encode()
|
|
|
|
|
+
|
|
|
// Minimum pixels (both width and height) required.
|
|
// Minimum pixels (both width and height) required.
|
|
|
realSize := q.symbol.size
|
|
realSize := q.symbol.size
|
|
|
|
|
|
|
@@ -282,12 +301,7 @@ func (q *QRCode) Image(size int) image.Image {
|
|
|
size = realSize
|
|
size = realSize
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Size of each module drawn.
|
|
|
|
|
- pixelsPerModule := size / realSize
|
|
|
|
|
-
|
|
|
|
|
- // Center the symbol within the image.
|
|
|
|
|
- offset := (size - realSize*pixelsPerModule) / 2
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // Output image.
|
|
|
rect := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
|
|
rect := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
|
|
|
|
|
|
|
|
// Saves a few bytes to have them in this order
|
|
// Saves a few bytes to have them in this order
|
|
@@ -295,18 +309,21 @@ func (q *QRCode) Image(size int) image.Image {
|
|
|
img := image.NewPaletted(rect, p)
|
|
img := image.NewPaletted(rect, p)
|
|
|
fgClr := uint8(img.Palette.Index(q.ForegroundColor))
|
|
fgClr := uint8(img.Palette.Index(q.ForegroundColor))
|
|
|
|
|
|
|
|
|
|
+ // QR code bitmap.
|
|
|
bitmap := q.symbol.bitmap()
|
|
bitmap := q.symbol.bitmap()
|
|
|
- for y, row := range bitmap {
|
|
|
|
|
- for x, v := range row {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 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++ {
|
|
|
|
|
+ x2 := int(float64(x) * modulesPerPixel)
|
|
|
|
|
+
|
|
|
|
|
+ v := bitmap[y2][x2]
|
|
|
|
|
+
|
|
|
if v {
|
|
if v {
|
|
|
- startX := x*pixelsPerModule + offset
|
|
|
|
|
- startY := y*pixelsPerModule + offset
|
|
|
|
|
- for i := startX; i < startX+pixelsPerModule; i++ {
|
|
|
|
|
- for j := startY; j < startY+pixelsPerModule; j++ {
|
|
|
|
|
- pos := img.PixOffset(i, j)
|
|
|
|
|
- img.Pix[pos] = fgClr
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ pos := img.PixOffset(x, y)
|
|
|
|
|
+ img.Pix[pos] = fgClr
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -371,7 +388,9 @@ func (q *QRCode) WriteFile(size int, filename string) error {
|
|
|
// encode completes the steps required to encode the QR Code. These include
|
|
// encode completes the steps required to encode the QR Code. These include
|
|
|
// adding the terminator bits and padding, splitting the data into blocks and
|
|
// adding the terminator bits and padding, splitting the data into blocks and
|
|
|
// applying the error correction, and selecting the best data mask.
|
|
// 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.addTerminatorBits(numTerminatorBits)
|
|
|
q.addPadding()
|
|
q.addPadding()
|
|
|
|
|
|
|
@@ -384,7 +403,7 @@ func (q *QRCode) encode(numTerminatorBits int) {
|
|
|
var s *symbol
|
|
var s *symbol
|
|
|
var err error
|
|
var err error
|
|
|
|
|
|
|
|
- s, err = buildRegularSymbol(q.version, mask, encoded)
|
|
|
|
|
|
|
+ s, err = buildRegularSymbol(q.version, mask, encoded, !q.DisableBorder)
|
|
|
|
|
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
log.Panic(err.Error())
|
|
log.Panic(err.Error())
|