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 }