versioninfo.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package qr
  2. import "math"
  3. // ErrorCorrectionLevel indicates the amount of "backup data" stored in the QR code
  4. type ErrorCorrectionLevel byte
  5. const (
  6. // L recovers 7% of data
  7. L ErrorCorrectionLevel = iota
  8. // M recovers 15% of data
  9. M
  10. // Q recovers 25% of data
  11. Q
  12. // H recovers 30% of data
  13. H
  14. )
  15. func (ecl ErrorCorrectionLevel) String() string {
  16. switch ecl {
  17. case L:
  18. return "L"
  19. case M:
  20. return "M"
  21. case Q:
  22. return "Q"
  23. case H:
  24. return "H"
  25. }
  26. return "unknown"
  27. }
  28. type encodingMode byte
  29. const (
  30. numericMode encodingMode = 1
  31. alphaNumericMode encodingMode = 2
  32. byteMode encodingMode = 4
  33. kanjiMode encodingMode = 8
  34. )
  35. type versionInfo struct {
  36. Version byte
  37. Level ErrorCorrectionLevel
  38. ErrorCorrectionCodewordsPerBlock byte
  39. NumberOfBlocksInGroup1 byte
  40. DataCodeWordsPerBlockInGroup1 byte
  41. NumberOfBlocksInGroup2 byte
  42. DataCodeWordsPerBlockInGroup2 byte
  43. }
  44. var versionInfos = []*versionInfo{
  45. &versionInfo{1, L, 7, 1, 19, 0, 0},
  46. &versionInfo{1, M, 10, 1, 16, 0, 0},
  47. &versionInfo{1, Q, 13, 1, 13, 0, 0},
  48. &versionInfo{1, H, 17, 1, 9, 0, 0},
  49. &versionInfo{2, L, 10, 1, 34, 0, 0},
  50. &versionInfo{2, M, 16, 1, 28, 0, 0},
  51. &versionInfo{2, Q, 22, 1, 22, 0, 0},
  52. &versionInfo{2, H, 28, 1, 16, 0, 0},
  53. &versionInfo{3, L, 15, 1, 55, 0, 0},
  54. &versionInfo{3, M, 26, 1, 44, 0, 0},
  55. &versionInfo{3, Q, 18, 2, 17, 0, 0},
  56. &versionInfo{3, H, 22, 2, 13, 0, 0},
  57. &versionInfo{4, L, 20, 1, 80, 0, 0},
  58. &versionInfo{4, M, 18, 2, 32, 0, 0},
  59. &versionInfo{4, Q, 26, 2, 24, 0, 0},
  60. &versionInfo{4, H, 16, 4, 9, 0, 0},
  61. &versionInfo{5, L, 26, 1, 108, 0, 0},
  62. &versionInfo{5, M, 24, 2, 43, 0, 0},
  63. &versionInfo{5, Q, 18, 2, 15, 2, 16},
  64. &versionInfo{5, H, 22, 2, 11, 2, 12},
  65. &versionInfo{6, L, 18, 2, 68, 0, 0},
  66. &versionInfo{6, M, 16, 4, 27, 0, 0},
  67. &versionInfo{6, Q, 24, 4, 19, 0, 0},
  68. &versionInfo{6, H, 28, 4, 15, 0, 0},
  69. &versionInfo{7, L, 20, 2, 78, 0, 0},
  70. &versionInfo{7, M, 18, 4, 31, 0, 0},
  71. &versionInfo{7, Q, 18, 2, 14, 4, 15},
  72. &versionInfo{7, H, 26, 4, 13, 1, 14},
  73. &versionInfo{8, L, 24, 2, 97, 0, 0},
  74. &versionInfo{8, M, 22, 2, 38, 2, 39},
  75. &versionInfo{8, Q, 22, 4, 18, 2, 19},
  76. &versionInfo{8, H, 26, 4, 14, 2, 15},
  77. &versionInfo{9, L, 30, 2, 116, 0, 0},
  78. &versionInfo{9, M, 22, 3, 36, 2, 37},
  79. &versionInfo{9, Q, 20, 4, 16, 4, 17},
  80. &versionInfo{9, H, 24, 4, 12, 4, 13},
  81. &versionInfo{10, L, 18, 2, 68, 2, 69},
  82. &versionInfo{10, M, 26, 4, 43, 1, 44},
  83. &versionInfo{10, Q, 24, 6, 19, 2, 20},
  84. &versionInfo{10, H, 28, 6, 15, 2, 16},
  85. &versionInfo{11, L, 20, 4, 81, 0, 0},
  86. &versionInfo{11, M, 30, 1, 50, 4, 51},
  87. &versionInfo{11, Q, 28, 4, 22, 4, 23},
  88. &versionInfo{11, H, 24, 3, 12, 8, 13},
  89. &versionInfo{12, L, 24, 2, 92, 2, 93},
  90. &versionInfo{12, M, 22, 6, 36, 2, 37},
  91. &versionInfo{12, Q, 26, 4, 20, 6, 21},
  92. &versionInfo{12, H, 28, 7, 14, 4, 15},
  93. &versionInfo{13, L, 26, 4, 107, 0, 0},
  94. &versionInfo{13, M, 22, 8, 37, 1, 38},
  95. &versionInfo{13, Q, 24, 8, 20, 4, 21},
  96. &versionInfo{13, H, 22, 12, 11, 4, 12},
  97. &versionInfo{14, L, 30, 3, 115, 1, 116},
  98. &versionInfo{14, M, 24, 4, 40, 5, 41},
  99. &versionInfo{14, Q, 20, 11, 16, 5, 17},
  100. &versionInfo{14, H, 24, 11, 12, 5, 13},
  101. &versionInfo{15, L, 22, 5, 87, 1, 88},
  102. &versionInfo{15, M, 24, 5, 41, 5, 42},
  103. &versionInfo{15, Q, 30, 5, 24, 7, 25},
  104. &versionInfo{15, H, 24, 11, 12, 7, 13},
  105. &versionInfo{16, L, 24, 5, 98, 1, 99},
  106. &versionInfo{16, M, 28, 7, 45, 3, 46},
  107. &versionInfo{16, Q, 24, 15, 19, 2, 20},
  108. &versionInfo{16, H, 30, 3, 15, 13, 16},
  109. &versionInfo{17, L, 28, 1, 107, 5, 108},
  110. &versionInfo{17, M, 28, 10, 46, 1, 47},
  111. &versionInfo{17, Q, 28, 1, 22, 15, 23},
  112. &versionInfo{17, H, 28, 2, 14, 17, 15},
  113. &versionInfo{18, L, 30, 5, 120, 1, 121},
  114. &versionInfo{18, M, 26, 9, 43, 4, 44},
  115. &versionInfo{18, Q, 28, 17, 22, 1, 23},
  116. &versionInfo{18, H, 28, 2, 14, 19, 15},
  117. &versionInfo{19, L, 28, 3, 113, 4, 114},
  118. &versionInfo{19, M, 26, 3, 44, 11, 45},
  119. &versionInfo{19, Q, 26, 17, 21, 4, 22},
  120. &versionInfo{19, H, 26, 9, 13, 16, 14},
  121. &versionInfo{20, L, 28, 3, 107, 5, 108},
  122. &versionInfo{20, M, 26, 3, 41, 13, 42},
  123. &versionInfo{20, Q, 30, 15, 24, 5, 25},
  124. &versionInfo{20, H, 28, 15, 15, 10, 16},
  125. &versionInfo{21, L, 28, 4, 116, 4, 117},
  126. &versionInfo{21, M, 26, 17, 42, 0, 0},
  127. &versionInfo{21, Q, 28, 17, 22, 6, 23},
  128. &versionInfo{21, H, 30, 19, 16, 6, 17},
  129. &versionInfo{22, L, 28, 2, 111, 7, 112},
  130. &versionInfo{22, M, 28, 17, 46, 0, 0},
  131. &versionInfo{22, Q, 30, 7, 24, 16, 25},
  132. &versionInfo{22, H, 24, 34, 13, 0, 0},
  133. &versionInfo{23, L, 30, 4, 121, 5, 122},
  134. &versionInfo{23, M, 28, 4, 47, 14, 48},
  135. &versionInfo{23, Q, 30, 11, 24, 14, 25},
  136. &versionInfo{23, H, 30, 16, 15, 14, 16},
  137. &versionInfo{24, L, 30, 6, 117, 4, 118},
  138. &versionInfo{24, M, 28, 6, 45, 14, 46},
  139. &versionInfo{24, Q, 30, 11, 24, 16, 25},
  140. &versionInfo{24, H, 30, 30, 16, 2, 17},
  141. &versionInfo{25, L, 26, 8, 106, 4, 107},
  142. &versionInfo{25, M, 28, 8, 47, 13, 48},
  143. &versionInfo{25, Q, 30, 7, 24, 22, 25},
  144. &versionInfo{25, H, 30, 22, 15, 13, 16},
  145. &versionInfo{26, L, 28, 10, 114, 2, 115},
  146. &versionInfo{26, M, 28, 19, 46, 4, 47},
  147. &versionInfo{26, Q, 28, 28, 22, 6, 23},
  148. &versionInfo{26, H, 30, 33, 16, 4, 17},
  149. &versionInfo{27, L, 30, 8, 122, 4, 123},
  150. &versionInfo{27, M, 28, 22, 45, 3, 46},
  151. &versionInfo{27, Q, 30, 8, 23, 26, 24},
  152. &versionInfo{27, H, 30, 12, 15, 28, 16},
  153. &versionInfo{28, L, 30, 3, 117, 10, 118},
  154. &versionInfo{28, M, 28, 3, 45, 23, 46},
  155. &versionInfo{28, Q, 30, 4, 24, 31, 25},
  156. &versionInfo{28, H, 30, 11, 15, 31, 16},
  157. &versionInfo{29, L, 30, 7, 116, 7, 117},
  158. &versionInfo{29, M, 28, 21, 45, 7, 46},
  159. &versionInfo{29, Q, 30, 1, 23, 37, 24},
  160. &versionInfo{29, H, 30, 19, 15, 26, 16},
  161. &versionInfo{30, L, 30, 5, 115, 10, 116},
  162. &versionInfo{30, M, 28, 19, 47, 10, 48},
  163. &versionInfo{30, Q, 30, 15, 24, 25, 25},
  164. &versionInfo{30, H, 30, 23, 15, 25, 16},
  165. &versionInfo{31, L, 30, 13, 115, 3, 116},
  166. &versionInfo{31, M, 28, 2, 46, 29, 47},
  167. &versionInfo{31, Q, 30, 42, 24, 1, 25},
  168. &versionInfo{31, H, 30, 23, 15, 28, 16},
  169. &versionInfo{32, L, 30, 17, 115, 0, 0},
  170. &versionInfo{32, M, 28, 10, 46, 23, 47},
  171. &versionInfo{32, Q, 30, 10, 24, 35, 25},
  172. &versionInfo{32, H, 30, 19, 15, 35, 16},
  173. &versionInfo{33, L, 30, 17, 115, 1, 116},
  174. &versionInfo{33, M, 28, 14, 46, 21, 47},
  175. &versionInfo{33, Q, 30, 29, 24, 19, 25},
  176. &versionInfo{33, H, 30, 11, 15, 46, 16},
  177. &versionInfo{34, L, 30, 13, 115, 6, 116},
  178. &versionInfo{34, M, 28, 14, 46, 23, 47},
  179. &versionInfo{34, Q, 30, 44, 24, 7, 25},
  180. &versionInfo{34, H, 30, 59, 16, 1, 17},
  181. &versionInfo{35, L, 30, 12, 121, 7, 122},
  182. &versionInfo{35, M, 28, 12, 47, 26, 48},
  183. &versionInfo{35, Q, 30, 39, 24, 14, 25},
  184. &versionInfo{35, H, 30, 22, 15, 41, 16},
  185. &versionInfo{36, L, 30, 6, 121, 14, 122},
  186. &versionInfo{36, M, 28, 6, 47, 34, 48},
  187. &versionInfo{36, Q, 30, 46, 24, 10, 25},
  188. &versionInfo{36, H, 30, 2, 15, 64, 16},
  189. &versionInfo{37, L, 30, 17, 122, 4, 123},
  190. &versionInfo{37, M, 28, 29, 46, 14, 47},
  191. &versionInfo{37, Q, 30, 49, 24, 10, 25},
  192. &versionInfo{37, H, 30, 24, 15, 46, 16},
  193. &versionInfo{38, L, 30, 4, 122, 18, 123},
  194. &versionInfo{38, M, 28, 13, 46, 32, 47},
  195. &versionInfo{38, Q, 30, 48, 24, 14, 25},
  196. &versionInfo{38, H, 30, 42, 15, 32, 16},
  197. &versionInfo{39, L, 30, 20, 117, 4, 118},
  198. &versionInfo{39, M, 28, 40, 47, 7, 48},
  199. &versionInfo{39, Q, 30, 43, 24, 22, 25},
  200. &versionInfo{39, H, 30, 10, 15, 67, 16},
  201. &versionInfo{40, L, 30, 19, 118, 6, 119},
  202. &versionInfo{40, M, 28, 18, 47, 31, 48},
  203. &versionInfo{40, Q, 30, 34, 24, 34, 25},
  204. &versionInfo{40, H, 30, 20, 15, 61, 16},
  205. }
  206. func (vi *versionInfo) totalDataBytes() int {
  207. g1Data := int(vi.NumberOfBlocksInGroup1) * int(vi.DataCodeWordsPerBlockInGroup1)
  208. g2Data := int(vi.NumberOfBlocksInGroup2) * int(vi.DataCodeWordsPerBlockInGroup2)
  209. return (g1Data + g2Data)
  210. }
  211. func (vi *versionInfo) charCountBits(m encodingMode) byte {
  212. switch m {
  213. case numericMode:
  214. if vi.Version < 10 {
  215. return 10
  216. } else if vi.Version < 27 {
  217. return 12
  218. }
  219. return 14
  220. case alphaNumericMode:
  221. if vi.Version < 10 {
  222. return 9
  223. } else if vi.Version < 27 {
  224. return 11
  225. }
  226. return 13
  227. case byteMode:
  228. if vi.Version < 10 {
  229. return 8
  230. }
  231. return 16
  232. case kanjiMode:
  233. if vi.Version < 10 {
  234. return 8
  235. } else if vi.Version < 27 {
  236. return 10
  237. }
  238. return 12
  239. default:
  240. return 0
  241. }
  242. }
  243. func (vi *versionInfo) modulWidth() int {
  244. return ((int(vi.Version) - 1) * 4) + 21
  245. }
  246. func (vi *versionInfo) alignmentPatternPlacements() []int {
  247. if vi.Version == 1 {
  248. return make([]int, 0)
  249. }
  250. first := 6
  251. last := vi.modulWidth() - 7
  252. space := float64(last - first)
  253. count := int(math.Ceil(space/28)) + 1
  254. result := make([]int, count)
  255. result[0] = first
  256. result[len(result)-1] = last
  257. if count > 2 {
  258. step := int(math.Ceil(float64(last-first) / float64(count-1)))
  259. if step%2 == 1 {
  260. frac := float64(last-first) / float64(count-1)
  261. _, x := math.Modf(frac)
  262. if x >= 0.5 {
  263. frac = math.Ceil(frac)
  264. } else {
  265. frac = math.Floor(frac)
  266. }
  267. if int(frac)%2 == 0 {
  268. step--
  269. } else {
  270. step++
  271. }
  272. }
  273. for i := 1; i <= count-2; i++ {
  274. result[i] = last - (step * (count - 1 - i))
  275. }
  276. }
  277. return result
  278. }
  279. func findSmallestVersionInfo(ecl ErrorCorrectionLevel, mode encodingMode, dataBits int) *versionInfo {
  280. dataBits = dataBits + 4 // mode indicator
  281. for _, vi := range versionInfos {
  282. if vi.Level == ecl {
  283. if (vi.totalDataBytes() * 8) >= (dataBits + int(vi.charCountBits(mode))) {
  284. return vi
  285. }
  286. }
  287. }
  288. return nil
  289. }