Add dep
This commit is contained in:
554
vendor/github.com/skip2/go-qrcode/qrcode.go
generated
vendored
Normal file
554
vendor/github.com/skip2/go-qrcode/qrcode.go
generated
vendored
Normal file
@ -0,0 +1,554 @@
|
||||
// go-qrcode
|
||||
// Copyright 2014 Tom Harwood
|
||||
|
||||
/*
|
||||
Package qrcode implements a QR Code encoder.
|
||||
|
||||
A QR Code is a matrix (two-dimensional) barcode. Arbitrary content may be
|
||||
encoded.
|
||||
|
||||
A QR Code contains error recovery information to aid reading damaged or
|
||||
obscured codes. There are four levels of error recovery: qrcode.{Low, Medium,
|
||||
High, Highest}. QR Codes with a higher recovery level are more robust to damage,
|
||||
at the cost of being physically larger.
|
||||
|
||||
Three functions cover most use cases:
|
||||
|
||||
- Create a PNG image:
|
||||
|
||||
var png []byte
|
||||
png, err := qrcode.Encode("https://example.org", qrcode.Medium, 256)
|
||||
|
||||
- Create a PNG image and write to a file:
|
||||
|
||||
err := qrcode.WriteFile("https://example.org", qrcode.Medium, 256, "qr.png")
|
||||
|
||||
- Create a PNG image with custom colors and write to file:
|
||||
|
||||
err := qrcode.WriteColorFile("https://example.org", qrcode.Medium, 256, color.Black, color.White, "qr.png")
|
||||
|
||||
All examples use the qrcode.Medium error Recovery Level and create a fixed
|
||||
256x256px size QR Code. The last function creates a white on black instead of black
|
||||
on white QR Code.
|
||||
|
||||
To generate a variable sized image instead, specify a negative size (in place of
|
||||
the 256 above), such as -4 or -5. Larger negative numbers create larger images:
|
||||
A size of -5 sets each module (QR Code "pixel") to be 5px wide/high.
|
||||
|
||||
- Create a PNG image (variable size, with minimum white padding) and write to a file:
|
||||
|
||||
err := qrcode.WriteFile("https://example.org", qrcode.Medium, -5, "qr.png")
|
||||
|
||||
The maximum capacity of a QR Code varies according to the content encoded and
|
||||
the error recovery level. The maximum capacity is 2,953 bytes, 4,296
|
||||
alphanumeric characters, 7,089 numeric digits, or a combination of these.
|
||||
|
||||
This package implements a subset of QR Code 2005, as defined in ISO/IEC
|
||||
18004:2006.
|
||||
*/
|
||||
package qrcode
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
bitset "github.com/skip2/go-qrcode/bitset"
|
||||
reedsolomon "github.com/skip2/go-qrcode/reedsolomon"
|
||||
)
|
||||
|
||||
// Encode a QR Code and return a raw PNG image.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently returned. Negative values for size cause a
|
||||
// variable sized image to be returned: See the documentation for Image().
|
||||
//
|
||||
// To serve over HTTP, remember to send a Content-Type: image/png header.
|
||||
func Encode(content string, level RecoveryLevel, size int) ([]byte, error) {
|
||||
var q *QRCode
|
||||
|
||||
q, err := New(content, level)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return q.PNG(size)
|
||||
}
|
||||
|
||||
// WriteFile encodes, then writes a QR Code to the given filename in PNG format.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently written. Negative values for size cause a variable
|
||||
// sized image to be written: See the documentation for Image().
|
||||
func WriteFile(content string, level RecoveryLevel, size int, filename string) error {
|
||||
var q *QRCode
|
||||
|
||||
q, err := New(content, level)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return q.WriteFile(size, filename)
|
||||
}
|
||||
|
||||
// WriteColorFile encodes, then writes a QR Code to the given filename in PNG format.
|
||||
// With WriteColorFile you can also specify the colors you want to use.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently written. Negative values for size cause a variable
|
||||
// sized image to be written: See the documentation for Image().
|
||||
func WriteColorFile(content string, level RecoveryLevel, size int, background,
|
||||
foreground color.Color, filename string) error {
|
||||
|
||||
var q *QRCode
|
||||
|
||||
q, err := New(content, level)
|
||||
|
||||
q.BackgroundColor = background
|
||||
q.ForegroundColor = foreground
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return q.WriteFile(size, filename)
|
||||
}
|
||||
|
||||
// A QRCode represents a valid encoded QRCode.
|
||||
type QRCode struct {
|
||||
// Original content encoded.
|
||||
Content string
|
||||
|
||||
// QR Code type.
|
||||
Level RecoveryLevel
|
||||
VersionNumber int
|
||||
|
||||
// User settable drawing options.
|
||||
ForegroundColor color.Color
|
||||
BackgroundColor color.Color
|
||||
|
||||
encoder *dataEncoder
|
||||
version qrCodeVersion
|
||||
|
||||
data *bitset.Bitset
|
||||
symbol *symbol
|
||||
mask int
|
||||
}
|
||||
|
||||
// New constructs a QRCode.
|
||||
//
|
||||
// var q *qrcode.QRCode
|
||||
// q, err := qrcode.New("my content", qrcode.Medium)
|
||||
//
|
||||
// An error occurs if the content is too long.
|
||||
func New(content string, level RecoveryLevel) (*QRCode, error) {
|
||||
encoders := []dataEncoderType{dataEncoderType1To9, dataEncoderType10To26,
|
||||
dataEncoderType27To40}
|
||||
|
||||
var encoder *dataEncoder
|
||||
var encoded *bitset.Bitset
|
||||
var chosenVersion *qrCodeVersion
|
||||
var err error
|
||||
|
||||
for _, t := range encoders {
|
||||
encoder = newDataEncoder(t)
|
||||
encoded, err = encoder.encode([]byte(content))
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
chosenVersion = chooseQRCodeVersion(level, encoder, encoded.Len())
|
||||
|
||||
if chosenVersion != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if chosenVersion == nil {
|
||||
return nil, errors.New("content too long to encode")
|
||||
}
|
||||
|
||||
q := &QRCode{
|
||||
Content: content,
|
||||
|
||||
Level: level,
|
||||
VersionNumber: chosenVersion.version,
|
||||
|
||||
ForegroundColor: color.Black,
|
||||
BackgroundColor: color.White,
|
||||
|
||||
encoder: encoder,
|
||||
data: encoded,
|
||||
version: *chosenVersion,
|
||||
}
|
||||
|
||||
q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
|
||||
var encoder *dataEncoder
|
||||
|
||||
switch {
|
||||
case version >= 1 && version <= 9:
|
||||
encoder = newDataEncoder(dataEncoderType1To9)
|
||||
case version >= 10 && version <= 26:
|
||||
encoder = newDataEncoder(dataEncoderType10To26)
|
||||
case version >= 27 && version <= 40:
|
||||
encoder = newDataEncoder(dataEncoderType27To40)
|
||||
default:
|
||||
log.Fatalf("Invalid version %d (expected 1-40 inclusive)", version)
|
||||
}
|
||||
|
||||
var encoded *bitset.Bitset
|
||||
encoded, err := encoder.encode([]byte(content))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chosenVersion := getQRCodeVersion(level, version)
|
||||
|
||||
if chosenVersion == nil {
|
||||
return nil, errors.New("cannot find QR Code version")
|
||||
}
|
||||
|
||||
q := &QRCode{
|
||||
Content: content,
|
||||
|
||||
Level: level,
|
||||
VersionNumber: chosenVersion.version,
|
||||
|
||||
ForegroundColor: color.Black,
|
||||
BackgroundColor: color.White,
|
||||
|
||||
encoder: encoder,
|
||||
data: encoded,
|
||||
version: *chosenVersion,
|
||||
}
|
||||
|
||||
q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
// Bitmap returns the QR Code as a 2D array of 1-bit pixels.
|
||||
//
|
||||
// bitmap[y][x] is true if the pixel at (x, y) is set.
|
||||
//
|
||||
// The bitmap includes the required "quiet zone" around the QR Code to aid
|
||||
// decoding.
|
||||
func (q *QRCode) Bitmap() [][]bool {
|
||||
return q.symbol.bitmap()
|
||||
}
|
||||
|
||||
// Image returns the QR Code as an image.Image.
|
||||
//
|
||||
// A positive size sets a fixed image width and height (e.g. 256 yields an
|
||||
// 256x256px image).
|
||||
//
|
||||
// Depending on the amount of data encoded, fixed size images can have different
|
||||
// amounts of padding (white space around the QR Code). As an alternative, a
|
||||
// variable sized image can be generated instead:
|
||||
//
|
||||
// A negative size causes a variable sized image to be returned. The image
|
||||
// returned is the minimum size required for the QR Code. Choose a larger
|
||||
// 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 {
|
||||
// Minimum pixels (both width and height) required.
|
||||
realSize := q.symbol.size
|
||||
|
||||
// Variable size support.
|
||||
if size < 0 {
|
||||
size = size * -1 * realSize
|
||||
}
|
||||
|
||||
// Actual pixels available to draw the symbol. Automatically increase the
|
||||
// image size if it's not large enough.
|
||||
if size < realSize {
|
||||
size = realSize
|
||||
}
|
||||
|
||||
// Size of each module drawn.
|
||||
pixelsPerModule := size / realSize
|
||||
|
||||
// Center the symbol within the image.
|
||||
offset := (size - realSize*pixelsPerModule) / 2
|
||||
|
||||
rect := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
|
||||
|
||||
// Saves a few bytes to have them in this order
|
||||
p := color.Palette([]color.Color{q.BackgroundColor, q.ForegroundColor})
|
||||
img := image.NewPaletted(rect, p)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
for j := 0; j < size; j++ {
|
||||
img.Set(i, j, q.BackgroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
bitmap := q.symbol.bitmap()
|
||||
for y, row := range bitmap {
|
||||
for x, v := range row {
|
||||
if v {
|
||||
startX := x*pixelsPerModule + offset
|
||||
startY := y*pixelsPerModule + offset
|
||||
for i := startX; i < startX+pixelsPerModule; i++ {
|
||||
for j := startY; j < startY+pixelsPerModule; j++ {
|
||||
img.Set(i, j, q.ForegroundColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
// PNG returns the QR Code as a PNG image.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently returned. Negative values for size cause a
|
||||
// variable sized image to be returned: See the documentation for Image().
|
||||
func (q *QRCode) PNG(size int) ([]byte, error) {
|
||||
img := q.Image(size)
|
||||
|
||||
encoder := png.Encoder{CompressionLevel: png.BestCompression}
|
||||
|
||||
var b bytes.Buffer
|
||||
err := encoder.Encode(&b, img)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
// Write writes the QR Code as a PNG image to io.Writer.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently written. Negative values for size cause a
|
||||
// variable sized image to be written: See the documentation for Image().
|
||||
func (q *QRCode) Write(size int, out io.Writer) error {
|
||||
var png []byte
|
||||
|
||||
png, err := q.PNG(size)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = out.Write(png)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteFile writes the QR Code as a PNG image to the specified file.
|
||||
//
|
||||
// size is both the image width and height in pixels. If size is too small then
|
||||
// a larger image is silently written. Negative values for size cause a
|
||||
// variable sized image to be written: See the documentation for Image().
|
||||
func (q *QRCode) WriteFile(size int, filename string) error {
|
||||
var png []byte
|
||||
|
||||
png, err := q.PNG(size)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filename, png, os.FileMode(0644))
|
||||
}
|
||||
|
||||
// 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) {
|
||||
q.addTerminatorBits(numTerminatorBits)
|
||||
q.addPadding()
|
||||
|
||||
encoded := q.encodeBlocks()
|
||||
|
||||
const numMasks int = 8
|
||||
penalty := 0
|
||||
|
||||
for mask := 0; mask < numMasks; mask++ {
|
||||
var s *symbol
|
||||
var err error
|
||||
|
||||
s, err = buildRegularSymbol(q.version, mask, encoded)
|
||||
|
||||
if err != nil {
|
||||
log.Panic(err.Error())
|
||||
}
|
||||
|
||||
numEmptyModules := s.numEmptyModules()
|
||||
if numEmptyModules != 0 {
|
||||
log.Panicf("bug: numEmptyModules is %d (expected 0) (version=%d)",
|
||||
numEmptyModules, q.VersionNumber)
|
||||
}
|
||||
|
||||
p := s.penaltyScore()
|
||||
|
||||
//log.Printf("mask=%d p=%3d p1=%3d p2=%3d p3=%3d p4=%d\n", mask, p, s.penalty1(), s.penalty2(), s.penalty3(), s.penalty4())
|
||||
|
||||
if q.symbol == nil || p < penalty {
|
||||
q.symbol = s
|
||||
q.mask = mask
|
||||
penalty = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addTerminatorBits adds final terminator bits to the encoded data.
|
||||
//
|
||||
// The number of terminator bits required is determined when the QR Code version
|
||||
// is chosen (which itself depends on the length of the data encoded). The
|
||||
// terminator bits are thus added after the QR Code version
|
||||
// is chosen, rather than at the data encoding stage.
|
||||
func (q *QRCode) addTerminatorBits(numTerminatorBits int) {
|
||||
q.data.AppendNumBools(numTerminatorBits, false)
|
||||
}
|
||||
|
||||
// encodeBlocks takes the completed (terminated & padded) encoded data, splits
|
||||
// the data into blocks (as specified by the QR Code version), applies error
|
||||
// correction to each block, then interleaves the blocks together.
|
||||
//
|
||||
// The QR Code's final data sequence is returned.
|
||||
func (q *QRCode) encodeBlocks() *bitset.Bitset {
|
||||
// Split into blocks.
|
||||
type dataBlock struct {
|
||||
data *bitset.Bitset
|
||||
ecStartOffset int
|
||||
}
|
||||
|
||||
block := make([]dataBlock, q.version.numBlocks())
|
||||
|
||||
start := 0
|
||||
end := 0
|
||||
blockID := 0
|
||||
|
||||
for _, b := range q.version.block {
|
||||
for j := 0; j < b.numBlocks; j++ {
|
||||
start = end
|
||||
end = start + b.numDataCodewords*8
|
||||
|
||||
// Apply error correction to each block.
|
||||
numErrorCodewords := b.numCodewords - b.numDataCodewords
|
||||
block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords)
|
||||
block[blockID].ecStartOffset = end - start
|
||||
|
||||
blockID++
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave the blocks.
|
||||
|
||||
result := bitset.New()
|
||||
|
||||
// Combine data blocks.
|
||||
working := true
|
||||
for i := 0; working; i += 8 {
|
||||
working = false
|
||||
|
||||
for j, b := range block {
|
||||
if i >= block[j].ecStartOffset {
|
||||
continue
|
||||
}
|
||||
|
||||
result.Append(b.data.Substr(i, i+8))
|
||||
|
||||
working = true
|
||||
}
|
||||
}
|
||||
|
||||
// Combine error correction blocks.
|
||||
working = true
|
||||
for i := 0; working; i += 8 {
|
||||
working = false
|
||||
|
||||
for j, b := range block {
|
||||
offset := i + block[j].ecStartOffset
|
||||
if offset >= block[j].data.Len() {
|
||||
continue
|
||||
}
|
||||
|
||||
result.Append(b.data.Substr(offset, offset+8))
|
||||
|
||||
working = true
|
||||
}
|
||||
}
|
||||
|
||||
// Append remainder bits.
|
||||
result.AppendNumBools(q.version.numRemainderBits, false)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// max returns the maximum of a and b.
|
||||
func max(a int, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// addPadding pads the encoded data upto the full length required.
|
||||
func (q *QRCode) addPadding() {
|
||||
numDataBits := q.version.numDataBits()
|
||||
|
||||
if q.data.Len() == numDataBits {
|
||||
return
|
||||
}
|
||||
|
||||
// Pad to the nearest codeword boundary.
|
||||
q.data.AppendNumBools(q.version.numBitsToPadToCodeword(q.data.Len()), false)
|
||||
|
||||
// Pad codewords 0b11101100 and 0b00010001.
|
||||
padding := [2]*bitset.Bitset{
|
||||
bitset.New(true, true, true, false, true, true, false, false),
|
||||
bitset.New(false, false, false, true, false, false, false, true),
|
||||
}
|
||||
|
||||
// Insert pad codewords alternately.
|
||||
i := 0
|
||||
for numDataBits-q.data.Len() >= 8 {
|
||||
q.data.Append(padding[i])
|
||||
|
||||
i = 1 - i // Alternate between 0 and 1.
|
||||
}
|
||||
|
||||
if q.data.Len() != numDataBits {
|
||||
log.Panicf("BUG: got len %d, expected %d", q.data.Len(), numDataBits)
|
||||
}
|
||||
}
|
||||
|
||||
// ToString produces a multi-line string that forms a QR-code image.
|
||||
func (q *QRCode) ToString(inverseColor bool) string {
|
||||
bits := q.Bitmap()
|
||||
var buf bytes.Buffer
|
||||
for y := range bits {
|
||||
for x := range bits[y] {
|
||||
if bits[y][x] != inverseColor {
|
||||
buf.WriteString(" ")
|
||||
} else {
|
||||
buf.WriteString("██")
|
||||
}
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
return buf.String()
|
||||
}
|
Reference in New Issue
Block a user