highlevel.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package aztec
  2. import (
  3. "github.com/boombuler/barcode/utils"
  4. )
  5. func highlevelEncode(data []byte) *utils.BitList {
  6. states := stateSlice{initialState}
  7. for index := 0; index < len(data); index++ {
  8. pairCode := 0
  9. nextChar := byte(0)
  10. if index+1 < len(data) {
  11. nextChar = data[index+1]
  12. }
  13. switch cur := data[index]; {
  14. case cur == '\r' && nextChar == '\n':
  15. pairCode = 2
  16. case cur == '.' && nextChar == ' ':
  17. pairCode = 3
  18. case cur == ',' && nextChar == ' ':
  19. pairCode = 4
  20. case cur == ':' && nextChar == ' ':
  21. pairCode = 5
  22. }
  23. if pairCode > 0 {
  24. // We have one of the four special PUNCT pairs. Treat them specially.
  25. // Get a new set of states for the two new characters.
  26. states = updateStateListForPair(states, data, index, pairCode)
  27. index++
  28. } else {
  29. // Get a new set of states for the new character.
  30. states = updateStateListForChar(states, data, index)
  31. }
  32. }
  33. minBitCnt := int((^uint(0)) >> 1)
  34. var result *state = nil
  35. for _, s := range states {
  36. if s.bitCount < minBitCnt {
  37. minBitCnt = s.bitCount
  38. result = s
  39. }
  40. }
  41. if result != nil {
  42. return result.toBitList(data)
  43. } else {
  44. return new(utils.BitList)
  45. }
  46. }
  47. func simplifyStates(states stateSlice) stateSlice {
  48. var result stateSlice = nil
  49. for _, newState := range states {
  50. add := true
  51. var newResult stateSlice = nil
  52. for _, oldState := range result {
  53. if add && oldState.isBetterThanOrEqualTo(newState) {
  54. add = false
  55. }
  56. if !(add && newState.isBetterThanOrEqualTo(oldState)) {
  57. newResult = append(newResult, oldState)
  58. }
  59. }
  60. if add {
  61. result = append(newResult, newState)
  62. } else {
  63. result = newResult
  64. }
  65. }
  66. return result
  67. }
  68. // We update a set of states for a new character by updating each state
  69. // for the new character, merging the results, and then removing the
  70. // non-optimal states.
  71. func updateStateListForChar(states stateSlice, data []byte, index int) stateSlice {
  72. var result stateSlice = nil
  73. for _, s := range states {
  74. if r := updateStateForChar(s, data, index); len(r) > 0 {
  75. result = append(result, r...)
  76. }
  77. }
  78. return simplifyStates(result)
  79. }
  80. // Return a set of states that represent the possible ways of updating this
  81. // state for the next character. The resulting set of states are added to
  82. // the "result" list.
  83. func updateStateForChar(s *state, data []byte, index int) stateSlice {
  84. var result stateSlice = nil
  85. ch := data[index]
  86. charInCurrentTable := charMap[s.mode][ch] > 0
  87. var stateNoBinary *state = nil
  88. for mode := mode_upper; mode <= mode_punct; mode++ {
  89. charInMode := charMap[mode][ch]
  90. if charInMode > 0 {
  91. if stateNoBinary == nil {
  92. // Only create stateNoBinary the first time it's required.
  93. stateNoBinary = s.endBinaryShift(index)
  94. }
  95. // Try generating the character by latching to its mode
  96. if !charInCurrentTable || mode == s.mode || mode == mode_digit {
  97. // If the character is in the current table, we don't want to latch to
  98. // any other mode except possibly digit (which uses only 4 bits). Any
  99. // other latch would be equally successful *after* this character, and
  100. // so wouldn't save any bits.
  101. res := stateNoBinary.latchAndAppend(mode, charInMode)
  102. result = append(result, res)
  103. }
  104. // Try generating the character by switching to its mode.
  105. if _, ok := shiftTable[s.mode][mode]; !charInCurrentTable && ok {
  106. // It never makes sense to temporarily shift to another mode if the
  107. // character exists in the current mode. That can never save bits.
  108. res := stateNoBinary.shiftAndAppend(mode, charInMode)
  109. result = append(result, res)
  110. }
  111. }
  112. }
  113. if s.bShiftByteCount > 0 || charMap[s.mode][ch] == 0 {
  114. // It's never worthwhile to go into binary shift mode if you're not already
  115. // in binary shift mode, and the character exists in your current mode.
  116. // That can never save bits over just outputting the char in the current mode.
  117. res := s.addBinaryShiftChar(index)
  118. result = append(result, res)
  119. }
  120. return result
  121. }
  122. // We update a set of states for a new character by updating each state
  123. // for the new character, merging the results, and then removing the
  124. // non-optimal states.
  125. func updateStateListForPair(states stateSlice, data []byte, index int, pairCode int) stateSlice {
  126. var result stateSlice = nil
  127. for _, s := range states {
  128. if r := updateStateForPair(s, data, index, pairCode); len(r) > 0 {
  129. result = append(result, r...)
  130. }
  131. }
  132. return simplifyStates(result)
  133. }
  134. func updateStateForPair(s *state, data []byte, index int, pairCode int) stateSlice {
  135. var result stateSlice
  136. stateNoBinary := s.endBinaryShift(index)
  137. // Possibility 1. Latch to MODE_PUNCT, and then append this code
  138. result = append(result, stateNoBinary.latchAndAppend(mode_punct, pairCode))
  139. if s.mode != mode_punct {
  140. // Possibility 2. Shift to MODE_PUNCT, and then append this code.
  141. // Every state except MODE_PUNCT (handled above) can shift
  142. result = append(result, stateNoBinary.shiftAndAppend(mode_punct, pairCode))
  143. }
  144. if pairCode == 3 || pairCode == 4 {
  145. // both characters are in DIGITS. Sometimes better to just add two digits
  146. digitState := stateNoBinary.
  147. latchAndAppend(mode_digit, 16-pairCode). // period or comma in DIGIT
  148. latchAndAppend(mode_digit, 1) // space in DIGIT
  149. result = append(result, digitState)
  150. }
  151. if s.bShiftByteCount > 0 {
  152. // It only makes sense to do the characters as binary if we're already
  153. // in binary mode.
  154. result = append(result, s.addBinaryShiftChar(index).addBinaryShiftChar(index+1))
  155. }
  156. return result
  157. }