You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

555 lines
14 KiB

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