taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

qrcode.go (15680B)


      1 // go-qrcode
      2 // Copyright 2014 Tom Harwood
      3 
      4 /*
      5 Package qrcode implements a QR Code encoder.
      6 
      7 A QR Code is a matrix (two-dimensional) barcode. Arbitrary content may be
      8 encoded.
      9 
     10 A QR Code contains error recovery information to aid reading damaged or
     11 obscured codes. There are four levels of error recovery: qrcode.{Low, Medium,
     12 High, Highest}. QR Codes with a higher recovery level are more robust to damage,
     13 at the cost of being physically larger.
     14 
     15 Three functions cover most use cases:
     16 
     17 - Create a PNG image:
     18 
     19 	var png []byte
     20 	png, err := qrcode.Encode("https://example.org", qrcode.Medium, 256)
     21 
     22 - Create a PNG image and write to a file:
     23 
     24 	err := qrcode.WriteFile("https://example.org", qrcode.Medium, 256, "qr.png")
     25 
     26 - Create a PNG image with custom colors and write to file:
     27 
     28 	err := qrcode.WriteColorFile("https://example.org", qrcode.Medium, 256, color.Black, color.White, "qr.png")
     29 
     30 All examples use the qrcode.Medium error Recovery Level and create a fixed
     31 256x256px size QR Code. The last function creates a white on black instead of black
     32 on white QR Code.
     33 
     34 To generate a variable sized image instead, specify a negative size (in place of
     35 the 256 above), such as -4 or -5. Larger negative numbers create larger images:
     36 A size of -5 sets each module (QR Code "pixel") to be 5px wide/high.
     37 
     38 - Create a PNG image (variable size, with minimum white padding) and write to a file:
     39 
     40 	err := qrcode.WriteFile("https://example.org", qrcode.Medium, -5, "qr.png")
     41 
     42 The maximum capacity of a QR Code varies according to the content encoded and
     43 the error recovery level. The maximum capacity is 2,953 bytes, 4,296
     44 alphanumeric characters, 7,089 numeric digits, or a combination of these.
     45 
     46 This package implements a subset of QR Code 2005, as defined in ISO/IEC
     47 18004:2006.
     48 */
     49 package qrcode
     50 
     51 import (
     52 	"bytes"
     53 	"errors"
     54 	"fmt"
     55 	"image"
     56 	"image/color"
     57 	"image/png"
     58 	"io"
     59 	"io/ioutil"
     60 	"log"
     61 	"os"
     62 
     63 	bitset "github.com/skip2/go-qrcode/bitset"
     64 	reedsolomon "github.com/skip2/go-qrcode/reedsolomon"
     65 )
     66 
     67 // Encode a QR Code and return a raw PNG image.
     68 //
     69 // size is both the image width and height in pixels. If size is too small then
     70 // a larger image is silently returned. Negative values for size cause a
     71 // variable sized image to be returned: See the documentation for Image().
     72 //
     73 // To serve over HTTP, remember to send a Content-Type: image/png header.
     74 func Encode(content string, level RecoveryLevel, size int) ([]byte, error) {
     75 	var q *QRCode
     76 
     77 	q, err := New(content, level)
     78 
     79 	if err != nil {
     80 		return nil, err
     81 	}
     82 
     83 	return q.PNG(size)
     84 }
     85 
     86 // WriteFile encodes, then writes a QR Code to the given filename in PNG format.
     87 //
     88 // size is both the image width and height in pixels. If size is too small then
     89 // a larger image is silently written. Negative values for size cause a variable
     90 // sized image to be written: See the documentation for Image().
     91 func WriteFile(content string, level RecoveryLevel, size int, filename string) error {
     92 	var q *QRCode
     93 
     94 	q, err := New(content, level)
     95 
     96 	if err != nil {
     97 		return err
     98 	}
     99 
    100 	return q.WriteFile(size, filename)
    101 }
    102 
    103 // WriteColorFile encodes, then writes a QR Code to the given filename in PNG format.
    104 // With WriteColorFile you can also specify the colors you want to use.
    105 //
    106 // size is both the image width and height in pixels. If size is too small then
    107 // a larger image is silently written. Negative values for size cause a variable
    108 // sized image to be written: See the documentation for Image().
    109 func WriteColorFile(content string, level RecoveryLevel, size int, background,
    110 	foreground color.Color, filename string) error {
    111 
    112 	var q *QRCode
    113 
    114 	q, err := New(content, level)
    115 
    116 	q.BackgroundColor = background
    117 	q.ForegroundColor = foreground
    118 
    119 	if err != nil {
    120 		return err
    121 	}
    122 
    123 	return q.WriteFile(size, filename)
    124 }
    125 
    126 // A QRCode represents a valid encoded QRCode.
    127 type QRCode struct {
    128 	// Original content encoded.
    129 	Content string
    130 
    131 	// QR Code type.
    132 	Level         RecoveryLevel
    133 	VersionNumber int
    134 
    135 	// User settable drawing options.
    136 	ForegroundColor color.Color
    137 	BackgroundColor color.Color
    138 
    139 	// Disable the QR Code border.
    140 	DisableBorder bool
    141 
    142 	encoder *dataEncoder
    143 	version qrCodeVersion
    144 
    145 	data   *bitset.Bitset
    146 	symbol *symbol
    147 	mask   int
    148 }
    149 
    150 // New constructs a QRCode.
    151 //
    152 //	var q *qrcode.QRCode
    153 //	q, err := qrcode.New("my content", qrcode.Medium)
    154 //
    155 // An error occurs if the content is too long.
    156 func New(content string, level RecoveryLevel) (*QRCode, error) {
    157 	encoders := []dataEncoderType{dataEncoderType1To9, dataEncoderType10To26,
    158 		dataEncoderType27To40}
    159 
    160 	var encoder *dataEncoder
    161 	var encoded *bitset.Bitset
    162 	var chosenVersion *qrCodeVersion
    163 	var err error
    164 
    165 	for _, t := range encoders {
    166 		encoder = newDataEncoder(t)
    167 		encoded, err = encoder.encode([]byte(content))
    168 
    169 		if err != nil {
    170 			continue
    171 		}
    172 
    173 		chosenVersion = chooseQRCodeVersion(level, encoder, encoded.Len())
    174 
    175 		if chosenVersion != nil {
    176 			break
    177 		}
    178 	}
    179 
    180 	if err != nil {
    181 		return nil, err
    182 	} else if chosenVersion == nil {
    183 		return nil, errors.New("content too long to encode")
    184 	}
    185 
    186 	q := &QRCode{
    187 		Content: content,
    188 
    189 		Level:         level,
    190 		VersionNumber: chosenVersion.version,
    191 
    192 		ForegroundColor: color.Black,
    193 		BackgroundColor: color.White,
    194 
    195 		encoder: encoder,
    196 		data:    encoded,
    197 		version: *chosenVersion,
    198 	}
    199 
    200 	return q, nil
    201 }
    202 
    203 // NewWithForcedVersion constructs a QRCode of a specific version.
    204 //
    205 //	var q *qrcode.QRCode
    206 //	q, err := qrcode.NewWithForcedVersion("my content", 25, qrcode.Medium)
    207 //
    208 // An error occurs in case of invalid version.
    209 func NewWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
    210 	var encoder *dataEncoder
    211 
    212 	switch {
    213 	case version >= 1 && version <= 9:
    214 		encoder = newDataEncoder(dataEncoderType1To9)
    215 	case version >= 10 && version <= 26:
    216 		encoder = newDataEncoder(dataEncoderType10To26)
    217 	case version >= 27 && version <= 40:
    218 		encoder = newDataEncoder(dataEncoderType27To40)
    219 	default:
    220 		return nil, fmt.Errorf("Invalid version %d (expected 1-40 inclusive)", version)
    221 	}
    222 
    223 	var encoded *bitset.Bitset
    224 	encoded, err := encoder.encode([]byte(content))
    225 
    226 	if err != nil {
    227 		return nil, err
    228 	}
    229 
    230 	chosenVersion := getQRCodeVersion(level, version)
    231 
    232 	if chosenVersion == nil {
    233 		return nil, errors.New("cannot find QR Code version")
    234 	}
    235 
    236 	if encoded.Len() > chosenVersion.numDataBits() {
    237 		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)",
    238 			version,
    239 			encoded.Len(),
    240 			chosenVersion.numDataBits())
    241 	}
    242 
    243 	q := &QRCode{
    244 		Content: content,
    245 
    246 		Level:         level,
    247 		VersionNumber: chosenVersion.version,
    248 
    249 		ForegroundColor: color.Black,
    250 		BackgroundColor: color.White,
    251 
    252 		encoder: encoder,
    253 		data:    encoded,
    254 		version: *chosenVersion,
    255 	}
    256 
    257 	return q, nil
    258 }
    259 
    260 // Bitmap returns the QR Code as a 2D array of 1-bit pixels.
    261 //
    262 // bitmap[y][x] is true if the pixel at (x, y) is set.
    263 //
    264 // The bitmap includes the required "quiet zone" around the QR Code to aid
    265 // decoding.
    266 func (q *QRCode) Bitmap() [][]bool {
    267 	// Build QR code.
    268 	q.encode()
    269 
    270 	return q.symbol.bitmap()
    271 }
    272 
    273 // Image returns the QR Code as an image.Image.
    274 //
    275 // A positive size sets a fixed image width and height (e.g. 256 yields an
    276 // 256x256px image).
    277 //
    278 // Depending on the amount of data encoded, fixed size images can have different
    279 // amounts of padding (white space around the QR Code). As an alternative, a
    280 // variable sized image can be generated instead:
    281 //
    282 // A negative size causes a variable sized image to be returned. The image
    283 // returned is the minimum size required for the QR Code. Choose a larger
    284 // negative number to increase the scale of the image. e.g. a size of -5 causes
    285 // each module (QR Code "pixel") to be 5px in size.
    286 func (q *QRCode) Image(size int) image.Image {
    287 	// Build QR code.
    288 	q.encode()
    289 
    290 	// Minimum pixels (both width and height) required.
    291 	realSize := q.symbol.size
    292 
    293 	// Variable size support.
    294 	if size < 0 {
    295 		size = size * -1 * realSize
    296 	}
    297 
    298 	// Actual pixels available to draw the symbol. Automatically increase the
    299 	// image size if it's not large enough.
    300 	if size < realSize {
    301 		size = realSize
    302 	}
    303 
    304 	// Output image.
    305 	rect := image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
    306 
    307 	// Saves a few bytes to have them in this order
    308 	p := color.Palette([]color.Color{q.BackgroundColor, q.ForegroundColor})
    309 	img := image.NewPaletted(rect, p)
    310 	fgClr := uint8(img.Palette.Index(q.ForegroundColor))
    311 
    312 	// QR code bitmap.
    313 	bitmap := q.symbol.bitmap()
    314 
    315 	// Map each image pixel to the nearest QR code module.
    316 	modulesPerPixel := float64(realSize) / float64(size)
    317 	for y := 0; y < size; y++ {
    318 		y2 := int(float64(y) * modulesPerPixel)
    319 		for x := 0; x < size; x++ {
    320 			x2 := int(float64(x) * modulesPerPixel)
    321 
    322 			v := bitmap[y2][x2]
    323 
    324 			if v {
    325 				pos := img.PixOffset(x, y)
    326 				img.Pix[pos] = fgClr
    327 			}
    328 		}
    329 	}
    330 
    331 	return img
    332 }
    333 
    334 // PNG returns the QR Code as a PNG image.
    335 //
    336 // size is both the image width and height in pixels. If size is too small then
    337 // a larger image is silently returned. Negative values for size cause a
    338 // variable sized image to be returned: See the documentation for Image().
    339 func (q *QRCode) PNG(size int) ([]byte, error) {
    340 	img := q.Image(size)
    341 
    342 	encoder := png.Encoder{CompressionLevel: png.BestCompression}
    343 
    344 	var b bytes.Buffer
    345 	err := encoder.Encode(&b, img)
    346 
    347 	if err != nil {
    348 		return nil, err
    349 	}
    350 
    351 	return b.Bytes(), nil
    352 }
    353 
    354 // Write writes the QR Code as a PNG image to io.Writer.
    355 //
    356 // size is both the image width and height in pixels. If size is too small then
    357 // a larger image is silently written. Negative values for size cause a
    358 // variable sized image to be written: See the documentation for Image().
    359 func (q *QRCode) Write(size int, out io.Writer) error {
    360 	var png []byte
    361 
    362 	png, err := q.PNG(size)
    363 
    364 	if err != nil {
    365 		return err
    366 	}
    367 	_, err = out.Write(png)
    368 	return err
    369 }
    370 
    371 // WriteFile writes the QR Code as a PNG image to the specified file.
    372 //
    373 // size is both the image width and height in pixels. If size is too small then
    374 // a larger image is silently written. Negative values for size cause a
    375 // variable sized image to be written: See the documentation for Image().
    376 func (q *QRCode) WriteFile(size int, filename string) error {
    377 	var png []byte
    378 
    379 	png, err := q.PNG(size)
    380 
    381 	if err != nil {
    382 		return err
    383 	}
    384 
    385 	return ioutil.WriteFile(filename, png, os.FileMode(0644))
    386 }
    387 
    388 // encode completes the steps required to encode the QR Code. These include
    389 // adding the terminator bits and padding, splitting the data into blocks and
    390 // applying the error correction, and selecting the best data mask.
    391 func (q *QRCode) encode() {
    392 	numTerminatorBits := q.version.numTerminatorBitsRequired(q.data.Len())
    393 
    394 	q.addTerminatorBits(numTerminatorBits)
    395 	q.addPadding()
    396 
    397 	encoded := q.encodeBlocks()
    398 
    399 	const numMasks int = 8
    400 	penalty := 0
    401 
    402 	for mask := 0; mask < numMasks; mask++ {
    403 		var s *symbol
    404 		var err error
    405 
    406 		s, err = buildRegularSymbol(q.version, mask, encoded, !q.DisableBorder)
    407 
    408 		if err != nil {
    409 			log.Panic(err.Error())
    410 		}
    411 
    412 		numEmptyModules := s.numEmptyModules()
    413 		if numEmptyModules != 0 {
    414 			log.Panicf("bug: numEmptyModules is %d (expected 0) (version=%d)",
    415 				numEmptyModules, q.VersionNumber)
    416 		}
    417 
    418 		p := s.penaltyScore()
    419 
    420 		//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())
    421 
    422 		if q.symbol == nil || p < penalty {
    423 			q.symbol = s
    424 			q.mask = mask
    425 			penalty = p
    426 		}
    427 	}
    428 }
    429 
    430 // addTerminatorBits adds final terminator bits to the encoded data.
    431 //
    432 // The number of terminator bits required is determined when the QR Code version
    433 // is chosen (which itself depends on the length of the data encoded). The
    434 // terminator bits are thus added after the QR Code version
    435 // is chosen, rather than at the data encoding stage.
    436 func (q *QRCode) addTerminatorBits(numTerminatorBits int) {
    437 	q.data.AppendNumBools(numTerminatorBits, false)
    438 }
    439 
    440 // encodeBlocks takes the completed (terminated & padded) encoded data, splits
    441 // the data into blocks (as specified by the QR Code version), applies error
    442 // correction to each block, then interleaves the blocks together.
    443 //
    444 // The QR Code's final data sequence is returned.
    445 func (q *QRCode) encodeBlocks() *bitset.Bitset {
    446 	// Split into blocks.
    447 	type dataBlock struct {
    448 		data          *bitset.Bitset
    449 		ecStartOffset int
    450 	}
    451 
    452 	block := make([]dataBlock, q.version.numBlocks())
    453 
    454 	start := 0
    455 	end := 0
    456 	blockID := 0
    457 
    458 	for _, b := range q.version.block {
    459 		for j := 0; j < b.numBlocks; j++ {
    460 			start = end
    461 			end = start + b.numDataCodewords*8
    462 
    463 			// Apply error correction to each block.
    464 			numErrorCodewords := b.numCodewords - b.numDataCodewords
    465 			block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords)
    466 			block[blockID].ecStartOffset = end - start
    467 
    468 			blockID++
    469 		}
    470 	}
    471 
    472 	// Interleave the blocks.
    473 
    474 	result := bitset.New()
    475 
    476 	// Combine data blocks.
    477 	working := true
    478 	for i := 0; working; i += 8 {
    479 		working = false
    480 
    481 		for j, b := range block {
    482 			if i >= block[j].ecStartOffset {
    483 				continue
    484 			}
    485 
    486 			result.Append(b.data.Substr(i, i+8))
    487 
    488 			working = true
    489 		}
    490 	}
    491 
    492 	// Combine error correction blocks.
    493 	working = true
    494 	for i := 0; working; i += 8 {
    495 		working = false
    496 
    497 		for j, b := range block {
    498 			offset := i + block[j].ecStartOffset
    499 			if offset >= block[j].data.Len() {
    500 				continue
    501 			}
    502 
    503 			result.Append(b.data.Substr(offset, offset+8))
    504 
    505 			working = true
    506 		}
    507 	}
    508 
    509 	// Append remainder bits.
    510 	result.AppendNumBools(q.version.numRemainderBits, false)
    511 
    512 	return result
    513 }
    514 
    515 // max returns the maximum of a and b.
    516 func max(a int, b int) int {
    517 	if a > b {
    518 		return a
    519 	}
    520 
    521 	return b
    522 }
    523 
    524 // addPadding pads the encoded data upto the full length required.
    525 func (q *QRCode) addPadding() {
    526 	numDataBits := q.version.numDataBits()
    527 
    528 	if q.data.Len() == numDataBits {
    529 		return
    530 	}
    531 
    532 	// Pad to the nearest codeword boundary.
    533 	q.data.AppendNumBools(q.version.numBitsToPadToCodeword(q.data.Len()), false)
    534 
    535 	// Pad codewords 0b11101100 and 0b00010001.
    536 	padding := [2]*bitset.Bitset{
    537 		bitset.New(true, true, true, false, true, true, false, false),
    538 		bitset.New(false, false, false, true, false, false, false, true),
    539 	}
    540 
    541 	// Insert pad codewords alternately.
    542 	i := 0
    543 	for numDataBits-q.data.Len() >= 8 {
    544 		q.data.Append(padding[i])
    545 
    546 		i = 1 - i // Alternate between 0 and 1.
    547 	}
    548 
    549 	if q.data.Len() != numDataBits {
    550 		log.Panicf("BUG: got len %d, expected %d", q.data.Len(), numDataBits)
    551 	}
    552 }
    553 
    554 // ToString produces a multi-line string that forms a QR-code image.
    555 func (q *QRCode) ToString(inverseColor bool) string {
    556 	bits := q.Bitmap()
    557 	var buf bytes.Buffer
    558 	for y := range bits {
    559 		for x := range bits[y] {
    560 			if bits[y][x] != inverseColor {
    561 				buf.WriteString("  ")
    562 			} else {
    563 				buf.WriteString("██")
    564 			}
    565 		}
    566 		buf.WriteString("\n")
    567 	}
    568 	return buf.String()
    569 }
    570 
    571 // ToSmallString produces a multi-line string that forms a QR-code image, a
    572 // factor two smaller in x and y then ToString.
    573 func (q *QRCode) ToSmallString(inverseColor bool) string {
    574 	bits := q.Bitmap()
    575 	var buf bytes.Buffer
    576 	// if there is an odd number of rows, the last one needs special treatment
    577 	for y := 0; y < len(bits)-1; y += 2 {
    578 		for x := range bits[y] {
    579 			if bits[y][x] == bits[y+1][x] {
    580 				if bits[y][x] != inverseColor {
    581 					buf.WriteString(" ")
    582 				} else {
    583 					buf.WriteString("█")
    584 				}
    585 			} else {
    586 				if bits[y][x] != inverseColor {
    587 					buf.WriteString("▄")
    588 				} else {
    589 					buf.WriteString("▀")
    590 				}
    591 			}
    592 		}
    593 		buf.WriteString("\n")
    594 	}
    595 	// special treatment for the last row if odd
    596 	if len(bits)%2 == 1 {
    597 		y := len(bits) - 1
    598 		for x := range bits[y] {
    599 			if bits[y][x] != inverseColor {
    600 				buf.WriteString(" ")
    601 			} else {
    602 				buf.WriteString("▀")
    603 			}
    604 		}
    605 		buf.WriteString("\n")
    606 	}
    607 	return buf.String()
    608 }