Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

ZXAztecHighLevelEncoder.m 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright 2014 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "ZXAztecHighLevelEncoder.h"
  17. #import "ZXAztecState.h"
  18. #import "ZXByteArray.h"
  19. NSArray *ZX_AZTEC_MODE_NAMES = nil;
  20. const int ZX_AZTEC_MODE_UPPER = 0; // 5 bits
  21. const int ZX_AZTEC_MODE_LOWER = 1; // 5 bits
  22. const int ZX_AZTEC_MODE_DIGIT = 2; // 4 bits
  23. const int ZX_AZTEC_MODE_MIXED = 3; // 5 bits
  24. const int ZX_AZTEC_MODE_PUNCT = 4; // 5 bits
  25. // The Latch Table shows, for each pair of Modes, the optimal method for
  26. // getting from one mode to another. In the worst possible case, this can
  27. // be up to 14 bits. In the best possible case, we are already there!
  28. // The high half-word of each entry gives the number of bits.
  29. // The low half-word of each entry are the actual bits necessary to change
  30. const int ZX_AZTEC_LATCH_TABLE[][5] = {
  31. {
  32. 0,
  33. (5 << 16) + 28, // UPPER -> LOWER
  34. (5 << 16) + 30, // UPPER -> DIGIT
  35. (5 << 16) + 29, // UPPER -> MIXED
  36. (10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
  37. },
  38. {
  39. (9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
  40. 0,
  41. (5 << 16) + 30, // LOWER -> DIGIT
  42. (5 << 16) + 29, // LOWER -> MIXED
  43. (10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
  44. },
  45. {
  46. (4 << 16) + 14, // DIGIT -> UPPER
  47. (9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
  48. 0,
  49. (9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
  50. (14 << 16) + (14 << 10) + (29 << 5) + 30,
  51. // DIGIT -> UPPER -> MIXED -> PUNCT
  52. },
  53. {
  54. (5 << 16) + 29, // MIXED -> UPPER
  55. (5 << 16) + 28, // MIXED -> LOWER
  56. (10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
  57. 0,
  58. (5 << 16) + 30, // MIXED -> PUNCT
  59. },
  60. {
  61. (5 << 16) + 31, // PUNCT -> UPPER
  62. (10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
  63. (10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
  64. (10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
  65. 0,
  66. },
  67. };
  68. // A reverse mapping from [mode][char] to the encoding for that character
  69. // in that mode. An entry of 0 indicates no mapping exists.
  70. const int ZX_AZTEC_CHAR_MAP_HEIGHT = 5;
  71. const int ZX_AZTEC_CHAR_MAP_WIDTH = 256;
  72. static int ZX_AZTEC_CHAR_MAP[ZX_AZTEC_CHAR_MAP_HEIGHT][ZX_AZTEC_CHAR_MAP_WIDTH];
  73. // A map showing the available shift codes. (The shifts to BINARY are not
  74. // shown
  75. int ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_SHIFT_TABLE_SIZE][ZX_AZTEC_SHIFT_TABLE_SIZE];
  76. @interface ZXAztecHighLevelEncoder ()
  77. @property (nonatomic, assign, readonly) ZXByteArray *text;
  78. @end
  79. @implementation ZXAztecHighLevelEncoder
  80. + (void)load {
  81. ZX_AZTEC_MODE_NAMES = @[@"UPPER", @"LOWER", @"DIGIT", @"MIXED", @"PUNCT"];
  82. memset(ZX_AZTEC_CHAR_MAP, 0, ZX_AZTEC_CHAR_MAP_HEIGHT * ZX_AZTEC_CHAR_MAP_WIDTH * sizeof(int));
  83. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_UPPER][' '] = 1;
  84. for (int c = 'A'; c <= 'Z'; c++) {
  85. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_UPPER][c] = c - 'A' + 2;
  86. }
  87. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_LOWER][' '] = 1;
  88. for (int c = 'a'; c <= 'z'; c++) {
  89. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_LOWER][c] = c - 'a' + 2;
  90. }
  91. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][' '] = 1;
  92. for (int c = '0'; c <= '9'; c++) {
  93. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][c] = c - '0' + 2;
  94. }
  95. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][','] = 12;
  96. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT]['.'] = 13;
  97. const int mixedTable[] = {
  98. '\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n',
  99. '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^',
  100. '_', '`', '|', '~', '\177'
  101. };
  102. for (int i = 0; i < sizeof(mixedTable) / sizeof(int); i++) {
  103. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_MIXED][mixedTable[i]] = i;
  104. }
  105. const int punctTable[] = {
  106. '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
  107. '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
  108. '[', ']', '{', '}'
  109. };
  110. for (int i = 0; i < sizeof(punctTable) / sizeof(int); i++) {
  111. if (punctTable[i] > 0) {
  112. ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_PUNCT][punctTable[i]] = i;
  113. }
  114. }
  115. memset(ZX_AZTEC_SHIFT_TABLE, -1, ZX_AZTEC_SHIFT_TABLE_SIZE * ZX_AZTEC_SHIFT_TABLE_SIZE * sizeof(int));
  116. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_UPPER][ZX_AZTEC_MODE_PUNCT] = 0;
  117. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_LOWER][ZX_AZTEC_MODE_PUNCT] = 0;
  118. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_LOWER][ZX_AZTEC_MODE_UPPER] = 28;
  119. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_MIXED][ZX_AZTEC_MODE_PUNCT] = 0;
  120. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_DIGIT][ZX_AZTEC_MODE_PUNCT] = 0;
  121. ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_DIGIT][ZX_AZTEC_MODE_UPPER] = 15;
  122. }
  123. - (id)initWithText:(ZXByteArray *)text {
  124. if (self = [super init]) {
  125. _text = text;
  126. }
  127. return self;
  128. }
  129. - (ZXBitArray *)encode {
  130. NSArray *states = @[[ZXAztecState initialState]];
  131. for (int index = 0; index < self.text.length; index++) {
  132. int pairCode;
  133. int nextChar = index + 1 < self.text.length ? self.text.array[index + 1] : 0;
  134. switch (self.text.array[index]) {
  135. case '\r':
  136. pairCode = nextChar == '\n' ? 2 : 0;
  137. break;
  138. case '.' :
  139. pairCode = nextChar == ' ' ? 3 : 0;
  140. break;
  141. case ',' :
  142. pairCode = nextChar == ' ' ? 4 : 0;
  143. break;
  144. case ':' :
  145. pairCode = nextChar == ' ' ? 5 : 0;
  146. break;
  147. default:
  148. pairCode = 0;
  149. }
  150. if (pairCode > 0) {
  151. // We have one of the four special PUNCT pairs. Treat them specially.
  152. // Get a new set of states for the two new characters.
  153. states = [self updateStateListForPair:states index:index pairCode:pairCode];
  154. index++;
  155. } else {
  156. // Get a new set of states for the new character.
  157. states = [self updateStateListForChar:states index:index];
  158. }
  159. }
  160. // We are left with a set of states. Find the shortest one.
  161. ZXAztecState *minState = [[states sortedArrayUsingComparator:^NSComparisonResult(ZXAztecState *a, ZXAztecState *b) {
  162. return a.bitCount - b.bitCount;
  163. }] firstObject];
  164. // Convert it to a bit array, and return.
  165. return [minState toBitArray:self.text];
  166. }
  167. // We update a set of states for a new character by updating each state
  168. // for the new character, merging the results, and then removing the
  169. // non-optimal states.
  170. - (NSArray *)updateStateListForChar:(NSArray *)states index:(int)index {
  171. NSMutableArray *result = [NSMutableArray array];
  172. for (ZXAztecState *state in states) {
  173. [self updateStateForChar:state index:index result:result];
  174. }
  175. return [self simplifyStates:result];
  176. }
  177. // Return a set of states that represent the possible ways of updating this
  178. // state for the next character. The resulting set of states are added to
  179. // the "result" list.
  180. - (void)updateStateForChar:(ZXAztecState *)state index:(int)index result:(NSMutableArray *)result {
  181. unichar ch = (unichar) (self.text.array[index] & 0xFF);
  182. BOOL charInCurrentTable = ZX_AZTEC_CHAR_MAP[state.mode][ch] > 0;
  183. ZXAztecState *stateNoBinary = nil;
  184. for (int mode = 0; mode <= ZX_AZTEC_MODE_PUNCT; mode++) {
  185. int charInMode = ZX_AZTEC_CHAR_MAP[mode][ch];
  186. if (charInMode > 0) {
  187. if (!stateNoBinary) {
  188. // Only create stateNoBinary the first time it's required.
  189. stateNoBinary = [state endBinaryShift:index];
  190. }
  191. // Try generating the character by latching to its mode
  192. if (!charInCurrentTable || mode == state.mode || mode == ZX_AZTEC_MODE_DIGIT) {
  193. // If the character is in the current table, we don't want to latch to
  194. // any other mode except possibly digit (which uses only 4 bits). Any
  195. // other latch would be equally successful *after* this character, and
  196. // so wouldn't save any bits.
  197. ZXAztecState *latch_state = [stateNoBinary latchAndAppend:mode value:charInMode];
  198. [result addObject:latch_state];
  199. }
  200. // Try generating the character by switching to its mode.
  201. if (!charInCurrentTable && ZX_AZTEC_SHIFT_TABLE[state.mode][mode] >= 0) {
  202. // It never makes sense to temporarily shift to another mode if the
  203. // character exists in the current mode. That can never save bits.
  204. ZXAztecState *shift_state = [stateNoBinary shiftAndAppend:mode value:charInMode];
  205. [result addObject:shift_state];
  206. }
  207. }
  208. }
  209. if (state.binaryShiftByteCount > 0 || ZX_AZTEC_CHAR_MAP[state.mode][ch] == 0) {
  210. // It's never worthwhile to go into binary shift mode if you're not already
  211. // in binary shift mode, and the character exists in your current mode.
  212. // That can never save bits over just outputting the char in the current mode.
  213. ZXAztecState *binaryState = [state addBinaryShiftChar:index];
  214. [result addObject:binaryState];
  215. }
  216. }
  217. - (NSArray *)updateStateListForPair:(NSArray *)states index:(int)index pairCode:(int)pairCode {
  218. NSMutableArray *result = [NSMutableArray array];
  219. for (ZXAztecState *state in states) {
  220. [self updateStateForPair:state index:index pairCode:pairCode result:result];
  221. }
  222. return [self simplifyStates:result];
  223. }
  224. - (void)updateStateForPair:(ZXAztecState *)state index:(int)index pairCode:(int)pairCode result:(NSMutableArray *)result {
  225. ZXAztecState *stateNoBinary = [state endBinaryShift:index];
  226. // Possibility 1. Latch to ZX_AZTEC_MODE_PUNCT, and then append this code
  227. [result addObject:[stateNoBinary latchAndAppend:ZX_AZTEC_MODE_PUNCT value:pairCode]];
  228. if (state.mode != ZX_AZTEC_MODE_PUNCT) {
  229. // Possibility 2. Shift to ZX_AZTEC_MODE_PUNCT, and then append this code.
  230. // Every state except ZX_AZTEC_MODE_PUNCT (handled above) can shift
  231. [result addObject:[stateNoBinary shiftAndAppend:ZX_AZTEC_MODE_PUNCT value:pairCode]];
  232. }
  233. if (pairCode == 3 || pairCode == 4) {
  234. // both characters are in DIGITS. Sometimes better to just add two digits
  235. ZXAztecState *digit_state = [[stateNoBinary
  236. latchAndAppend:ZX_AZTEC_MODE_DIGIT value:16 - pairCode] // period or comma in DIGIT
  237. latchAndAppend:ZX_AZTEC_MODE_DIGIT value:1]; // space in DIGIT
  238. [result addObject:digit_state];
  239. }
  240. if (state.binaryShiftByteCount > 0) {
  241. // It only makes sense to do the characters as binary if we're already
  242. // in binary mode.
  243. ZXAztecState *binaryState = [[state addBinaryShiftChar:index] addBinaryShiftChar:index + 1];
  244. [result addObject:binaryState];
  245. }
  246. }
  247. - (NSArray *)simplifyStates:(NSArray *)states {
  248. NSMutableArray *result = [NSMutableArray array];
  249. for (ZXAztecState *newState in states) {
  250. BOOL add = YES;
  251. NSArray *resultCopy = [NSArray arrayWithArray:result];
  252. for (ZXAztecState *oldState in resultCopy) {
  253. if ([oldState isBetterThanOrEqualTo:newState]) {
  254. add = NO;
  255. break;
  256. }
  257. if ([newState isBetterThanOrEqualTo:oldState]) {
  258. [result removeObject:oldState];
  259. }
  260. }
  261. if (add) {
  262. [result addObject:newState];
  263. }
  264. }
  265. return result;
  266. }
  267. @end