encoder.go 7.3 KB

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