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