encoder.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package aztec
  2. import (
  3. "fmt"
  4. "github.com/boombuler/barcode"
  5. "github.com/boombuler/barcode/utils"
  6. )
  7. const (
  8. DEFAULT_EC_PERCENT = 33
  9. DEFAULT_LAYERS = 0
  10. max_nb_bits = 32
  11. max_nb_bits_compact = 4
  12. )
  13. var (
  14. word_size = []int{
  15. 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
  16. 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
  17. }
  18. )
  19. func totalBitsInLayer(layers int, compact bool) int {
  20. tmp := 112
  21. if compact {
  22. tmp = 88
  23. }
  24. return (tmp + 16*layers) * layers
  25. }
  26. func stuffBits(bits *utils.BitList, wordSize int) *utils.BitList {
  27. out := new(utils.BitList)
  28. n := bits.Len()
  29. mask := (1 << uint(wordSize)) - 2
  30. for i := 0; i < n; i += wordSize {
  31. word := 0
  32. for j := 0; j < wordSize; j++ {
  33. if i+j >= n || bits.GetBit(i+j) {
  34. word |= 1 << uint(wordSize-1-j)
  35. }
  36. }
  37. if (word & mask) == mask {
  38. out.AddBits(word&mask, byte(wordSize))
  39. i--
  40. } else if (word & mask) == 0 {
  41. out.AddBits(word|1, byte(wordSize))
  42. i--
  43. } else {
  44. out.AddBits(word, byte(wordSize))
  45. }
  46. }
  47. return out
  48. }
  49. func generateModeMessage(compact bool, layers, messageSizeInWords int) *utils.BitList {
  50. modeMessage := new(utils.BitList)
  51. if compact {
  52. modeMessage.AddBits(layers-1, 2)
  53. modeMessage.AddBits(messageSizeInWords-1, 6)
  54. modeMessage = generateCheckWords(modeMessage, 28, 4)
  55. } else {
  56. modeMessage.AddBits(layers-1, 5)
  57. modeMessage.AddBits(messageSizeInWords-1, 11)
  58. modeMessage = generateCheckWords(modeMessage, 40, 4)
  59. }
  60. return modeMessage
  61. }
  62. func drawModeMessage(matrix *aztecCode, compact bool, matrixSize int, modeMessage *utils.BitList) {
  63. center := matrixSize / 2
  64. if compact {
  65. for i := 0; i < 7; i++ {
  66. offset := center - 3 + i
  67. if modeMessage.GetBit(i) {
  68. matrix.set(offset, center-5)
  69. }
  70. if modeMessage.GetBit(i + 7) {
  71. matrix.set(center+5, offset)
  72. }
  73. if modeMessage.GetBit(20 - i) {
  74. matrix.set(offset, center+5)
  75. }
  76. if modeMessage.GetBit(27 - i) {
  77. matrix.set(center-5, offset)
  78. }
  79. }
  80. } else {
  81. for i := 0; i < 10; i++ {
  82. offset := center - 5 + i + i/5
  83. if modeMessage.GetBit(i) {
  84. matrix.set(offset, center-7)
  85. }
  86. if modeMessage.GetBit(i + 10) {
  87. matrix.set(center+7, offset)
  88. }
  89. if modeMessage.GetBit(29 - i) {
  90. matrix.set(offset, center+7)
  91. }
  92. if modeMessage.GetBit(39 - i) {
  93. matrix.set(center-7, offset)
  94. }
  95. }
  96. }
  97. }
  98. func drawBullsEye(matrix *aztecCode, center, size int) {
  99. for i := 0; i < size; i += 2 {
  100. for j := center - i; j <= center+i; j++ {
  101. matrix.set(j, center-i)
  102. matrix.set(j, center+i)
  103. matrix.set(center-i, j)
  104. matrix.set(center+i, j)
  105. }
  106. }
  107. matrix.set(center-size, center-size)
  108. matrix.set(center-size+1, center-size)
  109. matrix.set(center-size, center-size+1)
  110. matrix.set(center+size, center-size)
  111. matrix.set(center+size, center-size+1)
  112. matrix.set(center+size, center+size-1)
  113. }
  114. // Encode returns an aztec barcode with the given content
  115. func Encode(data []byte, minECCPercent int, userSpecifiedLayers int) (barcode.Barcode, error) {
  116. bits := highlevelEncode(data)
  117. eccBits := ((bits.Len() * minECCPercent) / 100) + 11
  118. totalSizeBits := bits.Len() + eccBits
  119. var layers, TotalBitsInLayer, wordSize int
  120. var compact bool
  121. var stuffedBits *utils.BitList
  122. if userSpecifiedLayers != DEFAULT_LAYERS {
  123. compact = userSpecifiedLayers < 0
  124. if compact {
  125. layers = -userSpecifiedLayers
  126. } else {
  127. layers = userSpecifiedLayers
  128. }
  129. if (compact && layers > max_nb_bits_compact) || (!compact && layers > max_nb_bits) {
  130. return nil, fmt.Errorf("Illegal value %d for layers", userSpecifiedLayers)
  131. }
  132. TotalBitsInLayer = totalBitsInLayer(layers, compact)
  133. wordSize = word_size[layers]
  134. usableBitsInLayers := TotalBitsInLayer - (TotalBitsInLayer % wordSize)
  135. stuffedBits = stuffBits(bits, wordSize)
  136. if stuffedBits.Len()+eccBits > usableBitsInLayers {
  137. return nil, fmt.Errorf("Data to large for user specified layer")
  138. }
  139. if compact && stuffedBits.Len() > wordSize*64 {
  140. return nil, fmt.Errorf("Data to large for user specified layer")
  141. }
  142. } else {
  143. wordSize = 0
  144. stuffedBits = nil
  145. // We look at the possible table sizes in the order Compact1, Compact2, Compact3,
  146. // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1)
  147. // is the same size, but has more data.
  148. for i := 0; ; i++ {
  149. if i > max_nb_bits {
  150. return nil, fmt.Errorf("Data too large for an aztec code")
  151. }
  152. compact = i <= 3
  153. layers = i
  154. if compact {
  155. layers = i + 1
  156. }
  157. TotalBitsInLayer = totalBitsInLayer(layers, compact)
  158. if totalSizeBits > TotalBitsInLayer {
  159. continue
  160. }
  161. // [Re]stuff the bits if this is the first opportunity, or if the
  162. // wordSize has changed
  163. if wordSize != word_size[layers] {
  164. wordSize = word_size[layers]
  165. stuffedBits = stuffBits(bits, wordSize)
  166. }
  167. usableBitsInLayers := TotalBitsInLayer - (TotalBitsInLayer % wordSize)
  168. if compact && stuffedBits.Len() > wordSize*64 {
  169. // Compact format only allows 64 data words, though C4 can hold more words than that
  170. continue
  171. }
  172. if stuffedBits.Len()+eccBits <= usableBitsInLayers {
  173. break
  174. }
  175. }
  176. }
  177. messageBits := generateCheckWords(stuffedBits, TotalBitsInLayer, wordSize)
  178. messageSizeInWords := stuffedBits.Len() / wordSize
  179. modeMessage := generateModeMessage(compact, layers, messageSizeInWords)
  180. // allocate symbol
  181. var baseMatrixSize int
  182. if compact {
  183. baseMatrixSize = 11 + layers*4
  184. } else {
  185. baseMatrixSize = 14 + layers*4
  186. }
  187. alignmentMap := make([]int, baseMatrixSize)
  188. var matrixSize int
  189. if compact {
  190. // no alignment marks in compact mode, alignmentMap is a no-op
  191. matrixSize = baseMatrixSize
  192. for i := 0; i < len(alignmentMap); i++ {
  193. alignmentMap[i] = i
  194. }
  195. } else {
  196. matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2-1)/15)
  197. origCenter := baseMatrixSize / 2
  198. center := matrixSize / 2
  199. for i := 0; i < origCenter; i++ {
  200. newOffset := i + i/15
  201. alignmentMap[origCenter-i-1] = center - newOffset - 1
  202. alignmentMap[origCenter+i] = center + newOffset + 1
  203. }
  204. }
  205. code := newAztecCode(matrixSize)
  206. code.content = data
  207. // draw data bits
  208. for i, rowOffset := 0, 0; i < layers; i++ {
  209. rowSize := (layers - i) * 4
  210. if compact {
  211. rowSize += 9
  212. } else {
  213. rowSize += 12
  214. }
  215. for j := 0; j < rowSize; j++ {
  216. columnOffset := j * 2
  217. for k := 0; k < 2; k++ {
  218. if messageBits.GetBit(rowOffset + columnOffset + k) {
  219. code.set(alignmentMap[i*2+k], alignmentMap[i*2+j])
  220. }
  221. if messageBits.GetBit(rowOffset + rowSize*2 + columnOffset + k) {
  222. code.set(alignmentMap[i*2+j], alignmentMap[baseMatrixSize-1-i*2-k])
  223. }
  224. if messageBits.GetBit(rowOffset + rowSize*4 + columnOffset + k) {
  225. code.set(alignmentMap[baseMatrixSize-1-i*2-k], alignmentMap[baseMatrixSize-1-i*2-j])
  226. }
  227. if messageBits.GetBit(rowOffset + rowSize*6 + columnOffset + k) {
  228. code.set(alignmentMap[baseMatrixSize-1-i*2-j], alignmentMap[i*2+k])
  229. }
  230. }
  231. }
  232. rowOffset += rowSize * 8
  233. }
  234. // draw mode message
  235. drawModeMessage(code, compact, matrixSize, modeMessage)
  236. // draw alignment marks
  237. if compact {
  238. drawBullsEye(code, matrixSize/2, 5)
  239. } else {
  240. drawBullsEye(code, matrixSize/2, 7)
  241. for i, j := 0, 0; i < baseMatrixSize/2-1; i, j = i+15, j+16 {
  242. for k := (matrixSize / 2) & 1; k < matrixSize; k += 2 {
  243. code.set(matrixSize/2-j, k)
  244. code.set(matrixSize/2+j, k)
  245. code.set(k, matrixSize/2-j)
  246. code.set(k, matrixSize/2+j)
  247. }
  248. }
  249. }
  250. return code, nil
  251. }