本站源代码
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.

417 lines
15KB

  1. // Package qr can be used to create QR barcodes.
  2. package qr
  3. import (
  4. "image"
  5. "github.com/boombuler/barcode"
  6. "github.com/boombuler/barcode/utils"
  7. )
  8. type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error)
  9. // Encoding mode for QR Codes.
  10. type Encoding byte
  11. const (
  12. // Auto will choose ths best matching encoding
  13. Auto Encoding = iota
  14. // Numeric encoding only encodes numbers [0-9]
  15. Numeric
  16. // AlphaNumeric encoding only encodes uppercase letters, numbers and [Space], $, %, *, +, -, ., /, :
  17. AlphaNumeric
  18. // Unicode encoding encodes the string as utf-8
  19. Unicode
  20. // only for testing purpose
  21. unknownEncoding
  22. )
  23. func (e Encoding) getEncoder() encodeFn {
  24. switch e {
  25. case Auto:
  26. return encodeAuto
  27. case Numeric:
  28. return encodeNumeric
  29. case AlphaNumeric:
  30. return encodeAlphaNumeric
  31. case Unicode:
  32. return encodeUnicode
  33. }
  34. return nil
  35. }
  36. func (e Encoding) String() string {
  37. switch e {
  38. case Auto:
  39. return "Auto"
  40. case Numeric:
  41. return "Numeric"
  42. case AlphaNumeric:
  43. return "AlphaNumeric"
  44. case Unicode:
  45. return "Unicode"
  46. }
  47. return ""
  48. }
  49. // Encode returns a QR barcode with the given content, error correction level and uses the given encoding
  50. func Encode(content string, level ErrorCorrectionLevel, mode Encoding) (barcode.Barcode, error) {
  51. bits, vi, err := mode.getEncoder()(content, level)
  52. if err != nil {
  53. return nil, err
  54. }
  55. blocks := splitToBlocks(bits.IterateBytes(), vi)
  56. data := blocks.interleave(vi)
  57. result := render(data, vi)
  58. result.content = content
  59. return result, nil
  60. }
  61. func render(data []byte, vi *versionInfo) *qrcode {
  62. dim := vi.modulWidth()
  63. results := make([]*qrcode, 8)
  64. for i := 0; i < 8; i++ {
  65. results[i] = newBarcode(dim)
  66. }
  67. occupied := newBarcode(dim)
  68. setAll := func(x int, y int, val bool) {
  69. occupied.Set(x, y, true)
  70. for i := 0; i < 8; i++ {
  71. results[i].Set(x, y, val)
  72. }
  73. }
  74. drawFinderPatterns(vi, setAll)
  75. drawAlignmentPatterns(occupied, vi, setAll)
  76. //Timing Pattern:
  77. var i int
  78. for i = 0; i < dim; i++ {
  79. if !occupied.Get(i, 6) {
  80. setAll(i, 6, i%2 == 0)
  81. }
  82. if !occupied.Get(6, i) {
  83. setAll(6, i, i%2 == 0)
  84. }
  85. }
  86. // Dark Module
  87. setAll(8, dim-8, true)
  88. drawVersionInfo(vi, setAll)
  89. drawFormatInfo(vi, -1, occupied.Set)
  90. for i := 0; i < 8; i++ {
  91. drawFormatInfo(vi, i, results[i].Set)
  92. }
  93. // Write the data
  94. var curBitNo int
  95. for pos := range iterateModules(occupied) {
  96. var curBit bool
  97. if curBitNo < len(data)*8 {
  98. curBit = ((data[curBitNo/8] >> uint(7-(curBitNo%8))) & 1) == 1
  99. } else {
  100. curBit = false
  101. }
  102. for i := 0; i < 8; i++ {
  103. setMasked(pos.X, pos.Y, curBit, i, results[i].Set)
  104. }
  105. curBitNo++
  106. }
  107. lowestPenalty := ^uint(0)
  108. lowestPenaltyIdx := -1
  109. for i := 0; i < 8; i++ {
  110. p := results[i].calcPenalty()
  111. if p < lowestPenalty {
  112. lowestPenalty = p
  113. lowestPenaltyIdx = i
  114. }
  115. }
  116. return results[lowestPenaltyIdx]
  117. }
  118. func setMasked(x, y int, val bool, mask int, set func(int, int, bool)) {
  119. switch mask {
  120. case 0:
  121. val = val != (((y + x) % 2) == 0)
  122. break
  123. case 1:
  124. val = val != ((y % 2) == 0)
  125. break
  126. case 2:
  127. val = val != ((x % 3) == 0)
  128. break
  129. case 3:
  130. val = val != (((y + x) % 3) == 0)
  131. break
  132. case 4:
  133. val = val != (((y/2 + x/3) % 2) == 0)
  134. break
  135. case 5:
  136. val = val != (((y*x)%2)+((y*x)%3) == 0)
  137. break
  138. case 6:
  139. val = val != ((((y*x)%2)+((y*x)%3))%2 == 0)
  140. break
  141. case 7:
  142. val = val != ((((y+x)%2)+((y*x)%3))%2 == 0)
  143. }
  144. set(x, y, val)
  145. }
  146. func iterateModules(occupied *qrcode) <-chan image.Point {
  147. result := make(chan image.Point)
  148. allPoints := make(chan image.Point)
  149. go func() {
  150. curX := occupied.dimension - 1
  151. curY := occupied.dimension - 1
  152. isUpward := true
  153. for true {
  154. if isUpward {
  155. allPoints <- image.Pt(curX, curY)
  156. allPoints <- image.Pt(curX-1, curY)
  157. curY--
  158. if curY < 0 {
  159. curY = 0
  160. curX -= 2
  161. if curX == 6 {
  162. curX--
  163. }
  164. if curX < 0 {
  165. break
  166. }
  167. isUpward = false
  168. }
  169. } else {
  170. allPoints <- image.Pt(curX, curY)
  171. allPoints <- image.Pt(curX-1, curY)
  172. curY++
  173. if curY >= occupied.dimension {
  174. curY = occupied.dimension - 1
  175. curX -= 2
  176. if curX == 6 {
  177. curX--
  178. }
  179. isUpward = true
  180. if curX < 0 {
  181. break
  182. }
  183. }
  184. }
  185. }
  186. close(allPoints)
  187. }()
  188. go func() {
  189. for pt := range allPoints {
  190. if !occupied.Get(pt.X, pt.Y) {
  191. result <- pt
  192. }
  193. }
  194. close(result)
  195. }()
  196. return result
  197. }
  198. func drawFinderPatterns(vi *versionInfo, set func(int, int, bool)) {
  199. dim := vi.modulWidth()
  200. drawPattern := func(xoff int, yoff int) {
  201. for x := -1; x < 8; x++ {
  202. for y := -1; y < 8; y++ {
  203. val := (x == 0 || x == 6 || y == 0 || y == 6 || (x > 1 && x < 5 && y > 1 && y < 5)) && (x <= 6 && y <= 6 && x >= 0 && y >= 0)
  204. if x+xoff >= 0 && x+xoff < dim && y+yoff >= 0 && y+yoff < dim {
  205. set(x+xoff, y+yoff, val)
  206. }
  207. }
  208. }
  209. }
  210. drawPattern(0, 0)
  211. drawPattern(0, dim-7)
  212. drawPattern(dim-7, 0)
  213. }
  214. func drawAlignmentPatterns(occupied *qrcode, vi *versionInfo, set func(int, int, bool)) {
  215. drawPattern := func(xoff int, yoff int) {
  216. for x := -2; x <= 2; x++ {
  217. for y := -2; y <= 2; y++ {
  218. val := x == -2 || x == 2 || y == -2 || y == 2 || (x == 0 && y == 0)
  219. set(x+xoff, y+yoff, val)
  220. }
  221. }
  222. }
  223. positions := vi.alignmentPatternPlacements()
  224. for _, x := range positions {
  225. for _, y := range positions {
  226. if occupied.Get(x, y) {
  227. continue
  228. }
  229. drawPattern(x, y)
  230. }
  231. }
  232. }
  233. var formatInfos = map[ErrorCorrectionLevel]map[int][]bool{
  234. L: {
  235. 0: []bool{true, true, true, false, true, true, true, true, true, false, false, false, true, false, false},
  236. 1: []bool{true, true, true, false, false, true, false, true, true, true, true, false, false, true, true},
  237. 2: []bool{true, true, true, true, true, false, true, true, false, true, false, true, false, true, false},
  238. 3: []bool{true, true, true, true, false, false, false, true, false, false, true, true, true, false, true},
  239. 4: []bool{true, true, false, false, true, true, false, false, false, true, false, true, true, true, true},
  240. 5: []bool{true, true, false, false, false, true, true, false, false, false, true, true, false, false, false},
  241. 6: []bool{true, true, false, true, true, false, false, false, true, false, false, false, false, false, true},
  242. 7: []bool{true, true, false, true, false, false, true, false, true, true, true, false, true, true, false},
  243. },
  244. M: {
  245. 0: []bool{true, false, true, false, true, false, false, false, false, false, true, false, false, true, false},
  246. 1: []bool{true, false, true, false, false, false, true, false, false, true, false, false, true, false, true},
  247. 2: []bool{true, false, true, true, true, true, false, false, true, true, true, true, true, false, false},
  248. 3: []bool{true, false, true, true, false, true, true, false, true, false, false, true, false, true, true},
  249. 4: []bool{true, false, false, false, true, false, true, true, true, true, true, true, false, false, true},
  250. 5: []bool{true, false, false, false, false, false, false, true, true, false, false, true, true, true, false},
  251. 6: []bool{true, false, false, true, true, true, true, true, false, false, true, false, true, true, true},
  252. 7: []bool{true, false, false, true, false, true, false, true, false, true, false, false, false, false, false},
  253. },
  254. Q: {
  255. 0: []bool{false, true, true, false, true, false, true, false, true, false, true, true, true, true, true},
  256. 1: []bool{false, true, true, false, false, false, false, false, true, true, false, true, false, false, false},
  257. 2: []bool{false, true, true, true, true, true, true, false, false, true, true, false, false, false, true},
  258. 3: []bool{false, true, true, true, false, true, false, false, false, false, false, false, true, true, false},
  259. 4: []bool{false, true, false, false, true, false, false, true, false, true, true, false, true, false, false},
  260. 5: []bool{false, true, false, false, false, false, true, true, false, false, false, false, false, true, true},
  261. 6: []bool{false, true, false, true, true, true, false, true, true, false, true, true, false, true, false},
  262. 7: []bool{false, true, false, true, false, true, true, true, true, true, false, true, true, false, true},
  263. },
  264. H: {
  265. 0: []bool{false, false, true, false, true, true, false, true, false, false, false, true, false, false, true},
  266. 1: []bool{false, false, true, false, false, true, true, true, false, true, true, true, true, true, false},
  267. 2: []bool{false, false, true, true, true, false, false, true, true, true, false, false, true, true, true},
  268. 3: []bool{false, false, true, true, false, false, true, true, true, false, true, false, false, false, false},
  269. 4: []bool{false, false, false, false, true, true, true, false, true, true, false, false, false, true, false},
  270. 5: []bool{false, false, false, false, false, true, false, false, true, false, true, false, true, false, true},
  271. 6: []bool{false, false, false, true, true, false, true, false, false, false, false, true, true, false, false},
  272. 7: []bool{false, false, false, true, false, false, false, false, false, true, true, true, false, true, true},
  273. },
  274. }
  275. func drawFormatInfo(vi *versionInfo, usedMask int, set func(int, int, bool)) {
  276. var formatInfo []bool
  277. if usedMask == -1 {
  278. formatInfo = []bool{true, true, true, true, true, true, true, true, true, true, true, true, true, true, true} // Set all to true cause -1 --> occupied mask.
  279. } else {
  280. formatInfo = formatInfos[vi.Level][usedMask]
  281. }
  282. if len(formatInfo) == 15 {
  283. dim := vi.modulWidth()
  284. set(0, 8, formatInfo[0])
  285. set(1, 8, formatInfo[1])
  286. set(2, 8, formatInfo[2])
  287. set(3, 8, formatInfo[3])
  288. set(4, 8, formatInfo[4])
  289. set(5, 8, formatInfo[5])
  290. set(7, 8, formatInfo[6])
  291. set(8, 8, formatInfo[7])
  292. set(8, 7, formatInfo[8])
  293. set(8, 5, formatInfo[9])
  294. set(8, 4, formatInfo[10])
  295. set(8, 3, formatInfo[11])
  296. set(8, 2, formatInfo[12])
  297. set(8, 1, formatInfo[13])
  298. set(8, 0, formatInfo[14])
  299. set(8, dim-1, formatInfo[0])
  300. set(8, dim-2, formatInfo[1])
  301. set(8, dim-3, formatInfo[2])
  302. set(8, dim-4, formatInfo[3])
  303. set(8, dim-5, formatInfo[4])
  304. set(8, dim-6, formatInfo[5])
  305. set(8, dim-7, formatInfo[6])
  306. set(dim-8, 8, formatInfo[7])
  307. set(dim-7, 8, formatInfo[8])
  308. set(dim-6, 8, formatInfo[9])
  309. set(dim-5, 8, formatInfo[10])
  310. set(dim-4, 8, formatInfo[11])
  311. set(dim-3, 8, formatInfo[12])
  312. set(dim-2, 8, formatInfo[13])
  313. set(dim-1, 8, formatInfo[14])
  314. }
  315. }
  316. var versionInfoBitsByVersion = map[byte][]bool{
  317. 7: []bool{false, false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false},
  318. 8: []bool{false, false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false},
  319. 9: []bool{false, false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true},
  320. 10: []bool{false, false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true},
  321. 11: []bool{false, false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false},
  322. 12: []bool{false, false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false},
  323. 13: []bool{false, false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true},
  324. 14: []bool{false, false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true},
  325. 15: []bool{false, false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false},
  326. 16: []bool{false, true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false},
  327. 17: []bool{false, true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true},
  328. 18: []bool{false, true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true},
  329. 19: []bool{false, true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false},
  330. 20: []bool{false, true, false, true, false, false, true, false, false, true, true, false, true, false, false, true, true, false},
  331. 21: []bool{false, true, false, true, false, true, false, true, true, false, true, false, false, false, false, false, true, true},
  332. 22: []bool{false, true, false, true, true, false, true, false, false, false, true, true, false, false, true, false, false, true},
  333. 23: []bool{false, true, false, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false},
  334. 24: []bool{false, true, true, false, false, false, true, true, true, false, true, true, false, false, false, true, false, false},
  335. 25: []bool{false, true, true, false, false, true, false, false, false, true, true, true, true, false, false, false, false, true},
  336. 26: []bool{false, true, true, false, true, false, true, true, true, true, true, false, true, false, true, false, true, true},
  337. 27: []bool{false, true, true, false, true, true, false, false, false, false, true, false, false, false, true, true, true, false},
  338. 28: []bool{false, true, true, true, false, false, true, true, false, false, false, false, false, true, true, false, true, false},
  339. 29: []bool{false, true, true, true, false, true, false, false, true, true, false, false, true, true, true, true, true, true},
  340. 30: []bool{false, true, true, true, true, false, true, true, false, true, false, true, true, true, false, true, false, true},
  341. 31: []bool{false, true, true, true, true, true, false, false, true, false, false, true, false, true, false, false, false, false},
  342. 32: []bool{true, false, false, false, false, false, true, false, false, true, true, true, false, true, false, true, false, true},
  343. 33: []bool{true, false, false, false, false, true, false, true, true, false, true, true, true, true, false, false, false, false},
  344. 34: []bool{true, false, false, false, true, false, true, false, false, false, true, false, true, true, true, false, true, false},
  345. 35: []bool{true, false, false, false, true, true, false, true, true, true, true, false, false, true, true, true, true, true},
  346. 36: []bool{true, false, false, true, false, false, true, false, true, true, false, false, false, false, true, false, true, true},
  347. 37: []bool{true, false, false, true, false, true, false, true, false, false, false, false, true, false, true, true, true, false},
  348. 38: []bool{true, false, false, true, true, false, true, false, true, false, false, true, true, false, false, true, false, false},
  349. 39: []bool{true, false, false, true, true, true, false, true, false, true, false, true, false, false, false, false, false, true},
  350. 40: []bool{true, false, true, false, false, false, true, true, false, false, false, true, true, false, true, false, false, true},
  351. }
  352. func drawVersionInfo(vi *versionInfo, set func(int, int, bool)) {
  353. versionInfoBits, ok := versionInfoBitsByVersion[vi.Version]
  354. if ok && len(versionInfoBits) > 0 {
  355. for i := 0; i < len(versionInfoBits); i++ {
  356. x := (vi.modulWidth() - 11) + i%3
  357. y := i / 3
  358. set(x, y, versionInfoBits[len(versionInfoBits)-i-1])
  359. set(y, x, versionInfoBits[len(versionInfoBits)-i-1])
  360. }
  361. }
  362. }
  363. func addPaddingAndTerminator(bl *utils.BitList, vi *versionInfo) {
  364. for i := 0; i < 4 && bl.Len() < vi.totalDataBytes()*8; i++ {
  365. bl.AddBit(false)
  366. }
  367. for bl.Len()%8 != 0 {
  368. bl.AddBit(false)
  369. }
  370. for i := 0; bl.Len() < vi.totalDataBytes()*8; i++ {
  371. if i%2 == 0 {
  372. bl.AddByte(236)
  373. } else {
  374. bl.AddByte(17)
  375. }
  376. }
  377. }
上海开阖软件有限公司 沪ICP备12045867号-1