You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Copyright 2013 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 "ZXAztecCode.h"
  17. #import "ZXAztecEncoder.h"
  18. #import "ZXAztecHighLevelEncoder.h"
  19. #import "ZXBitArray.h"
  20. #import "ZXBitMatrix.h"
  21. #import "ZXByteArray.h"
  22. #import "ZXGenericGF.h"
  23. #import "ZXIntArray.h"
  24. #import "ZXReedSolomonEncoder.h"
  25. const int ZX_AZTEC_DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words
  26. const int ZX_AZTEC_DEFAULT_LAYERS = 0;
  27. const int ZX_AZTEC_MAX_NB_BITS = 32;
  28. const int ZX_AZTEC_MAX_NB_BITS_COMPACT = 4;
  29. const int ZX_AZTEC_WORD_SIZE[] = {
  30. 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
  31. 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
  32. };
  33. @implementation ZXAztecEncoder
  34. + (ZXAztecCode *)encode:(ZXByteArray *)data {
  35. return [self encode:data minECCPercent:ZX_AZTEC_DEFAULT_EC_PERCENT userSpecifiedLayers:ZX_AZTEC_DEFAULT_LAYERS];
  36. }
  37. + (ZXAztecCode *)encode:(ZXByteArray *)data minECCPercent:(int)minECCPercent userSpecifiedLayers:(int)userSpecifiedLayers {
  38. // High-level encode
  39. ZXBitArray *bits = [[[ZXAztecHighLevelEncoder alloc] initWithText:data] encode];
  40. // stuff bits and choose symbol size
  41. int eccBits = bits.size * minECCPercent / 100 + 11;
  42. int totalSizeBits = bits.size + eccBits;
  43. BOOL compact;
  44. int layers;
  45. int totalBitsInLayer;
  46. int wordSize = ZX_AZTEC_WORD_SIZE[0];
  47. ZXBitArray *stuffedBits;
  48. if (userSpecifiedLayers != ZX_AZTEC_DEFAULT_LAYERS) {
  49. compact = userSpecifiedLayers < 0;
  50. layers = abs(userSpecifiedLayers);
  51. if (layers > (compact ? ZX_AZTEC_MAX_NB_BITS_COMPACT : ZX_AZTEC_MAX_NB_BITS)) {
  52. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  53. reason:[NSString stringWithFormat:@"Illegal value %d for layers", userSpecifiedLayers]
  54. userInfo:nil];
  55. }
  56. totalBitsInLayer = [self totalBitsInLayer:layers compact:compact];
  57. wordSize = ZX_AZTEC_WORD_SIZE[layers];
  58. int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize);
  59. stuffedBits = [self stuffBits:bits wordSize:wordSize];
  60. if (stuffedBits.size + eccBits > usableBitsInLayers) {
  61. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  62. reason:@"Data too large for user specified layer"
  63. userInfo:nil];
  64. }
  65. if (compact && stuffedBits.size > wordSize * 64) {
  66. // Compact format only allows 64 data words, though C4 can hold more words than that
  67. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  68. reason:@"Data too large for user specified layer"
  69. userInfo:nil];
  70. }
  71. } else {
  72. // We look at the possible table sizes in the order Compact1, Compact2, Compact3,
  73. // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1)
  74. // is the same size, but has more data.
  75. for (int i = 0; ; i++) {
  76. if (i > ZX_AZTEC_MAX_NB_BITS) {
  77. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  78. reason:@"Data too large for an Aztec code"
  79. userInfo:nil];
  80. }
  81. compact = i <= 3;
  82. layers = compact ? i + 1 : i;
  83. totalBitsInLayer = [self totalBitsInLayer:layers compact:compact];
  84. if (totalSizeBits > totalBitsInLayer) {
  85. continue;
  86. }
  87. // [Re]stuff the bits if this is the first opportunity, or if the
  88. // wordSize has changed
  89. if (wordSize != ZX_AZTEC_WORD_SIZE[layers]) {
  90. wordSize = ZX_AZTEC_WORD_SIZE[layers];
  91. stuffedBits = [self stuffBits:bits wordSize:wordSize];
  92. }
  93. int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize);
  94. if (compact && stuffedBits.size > wordSize * 64) {
  95. // Compact format only allows 64 data words, though C4 can hold more words than that
  96. continue;
  97. }
  98. if (stuffedBits.size + eccBits <= usableBitsInLayers) {
  99. break;
  100. }
  101. }
  102. }
  103. ZXBitArray *messageBits = [self generateCheckWords:stuffedBits totalBits:totalBitsInLayer wordSize:wordSize];
  104. // generate check words
  105. int messageSizeInWords = stuffedBits.size / wordSize;
  106. ZXBitArray *modeMessage = [self generateModeMessageCompact:compact layers:layers messageSizeInWords:messageSizeInWords];
  107. // allocate symbol
  108. int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines
  109. int alignmentMap[baseMatrixSize];
  110. memset(alignmentMap, 0, baseMatrixSize * sizeof(int));
  111. int matrixSize;
  112. if (compact) {
  113. // no alignment marks in compact mode, alignmentMap is a no-op
  114. matrixSize = baseMatrixSize;
  115. for (int i = 0; i < baseMatrixSize; i++) {
  116. alignmentMap[i] = i;
  117. }
  118. } else {
  119. matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
  120. int origCenter = baseMatrixSize / 2;
  121. int center = matrixSize / 2;
  122. for (int i = 0; i < origCenter; i++) {
  123. int newOffset = i + i / 15;
  124. alignmentMap[origCenter - i - 1] = center - newOffset - 1;
  125. alignmentMap[origCenter + i] = center + newOffset + 1;
  126. }
  127. }
  128. ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithDimension:matrixSize];
  129. // draw data bits
  130. for (int i = 0, rowOffset = 0; i < layers; i++) {
  131. int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12;
  132. for (int j = 0; j < rowSize; j++) {
  133. int columnOffset = j * 2;
  134. for (int k = 0; k < 2; k++) {
  135. if ([messageBits get:rowOffset + columnOffset + k]) {
  136. [matrix setX:alignmentMap[i * 2 + k] y:alignmentMap[i * 2 + j]];
  137. }
  138. if ([messageBits get:rowOffset + rowSize * 2 + columnOffset + k]) {
  139. [matrix setX:alignmentMap[i * 2 + j] y:alignmentMap[baseMatrixSize - 1 - i * 2 - k]];
  140. }
  141. if ([messageBits get:rowOffset + rowSize * 4 + columnOffset + k]) {
  142. [matrix setX:alignmentMap[baseMatrixSize - 1 - i * 2 - k] y:alignmentMap[baseMatrixSize - 1 - i * 2 - j]];
  143. }
  144. if ([messageBits get:rowOffset + rowSize * 6 + columnOffset + k]) {
  145. [matrix setX:alignmentMap[baseMatrixSize - 1 - i * 2 - j] y:alignmentMap[i * 2 + k]];
  146. }
  147. }
  148. }
  149. rowOffset += rowSize * 8;
  150. }
  151. // draw mode message
  152. [self drawModeMessage:matrix compact:compact matrixSize:matrixSize modeMessage:modeMessage];
  153. // draw alignment marks
  154. if (compact) {
  155. [self drawBullsEye:matrix center:matrixSize / 2 size:5];
  156. } else {
  157. [self drawBullsEye:matrix center:matrixSize / 2 size:7];
  158. for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16) {
  159. for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2) {
  160. [matrix setX:matrixSize / 2 - j y:k];
  161. [matrix setX:matrixSize / 2 + j y:k];
  162. [matrix setX:k y:matrixSize / 2 - j];
  163. [matrix setX:k y:matrixSize / 2 + j];
  164. }
  165. }
  166. }
  167. ZXAztecCode *aztec = [[ZXAztecCode alloc] init];
  168. aztec.compact = compact;
  169. aztec.size = matrixSize;
  170. aztec.layers = layers;
  171. aztec.codeWords = messageSizeInWords;
  172. aztec.matrix = matrix;
  173. return aztec;
  174. }
  175. + (void)drawBullsEye:(ZXBitMatrix *)matrix center:(int)center size:(int)size {
  176. for (int i = 0; i < size; i += 2) {
  177. for (int j = center - i; j <= center + i; j++) {
  178. [matrix setX:j y:center - i];
  179. [matrix setX:j y:center + i];
  180. [matrix setX:center - i y:j];
  181. [matrix setX:center + i y:j];
  182. }
  183. }
  184. [matrix setX:center - size y:center - size];
  185. [matrix setX:center - size + 1 y:center - size];
  186. [matrix setX:center - size y:center - size + 1];
  187. [matrix setX:center + size y:center - size];
  188. [matrix setX:center + size y:center - size + 1];
  189. [matrix setX:center + size y:center + size - 1];
  190. }
  191. + (ZXBitArray *)generateModeMessageCompact:(BOOL)compact layers:(int)layers messageSizeInWords:(int)messageSizeInWords {
  192. ZXBitArray *modeMessage = [[ZXBitArray alloc] init];
  193. if (compact) {
  194. [modeMessage appendBits:layers - 1 numBits:2];
  195. [modeMessage appendBits:messageSizeInWords - 1 numBits:6];
  196. modeMessage = [self generateCheckWords:modeMessage totalBits:28 wordSize:4];
  197. } else {
  198. [modeMessage appendBits:layers - 1 numBits:5];
  199. [modeMessage appendBits:messageSizeInWords - 1 numBits:11];
  200. modeMessage = [self generateCheckWords:modeMessage totalBits:40 wordSize:4];
  201. }
  202. return modeMessage;
  203. }
  204. + (void)drawModeMessage:(ZXBitMatrix *)matrix compact:(BOOL)compact matrixSize:(int)matrixSize modeMessage:(ZXBitArray *)modeMessage {
  205. int center = matrixSize / 2;
  206. if (compact) {
  207. for (int i = 0; i < 7; i++) {
  208. int offset = center - 3 + i;
  209. if ([modeMessage get:i]) {
  210. [matrix setX:offset y:center - 5];
  211. }
  212. if ([modeMessage get:i + 7]) {
  213. [matrix setX:center + 5 y:offset];
  214. }
  215. if ([modeMessage get:20 - i]) {
  216. [matrix setX:offset y:center + 5];
  217. }
  218. if ([modeMessage get:27 - i]) {
  219. [matrix setX:center - 5 y:offset];
  220. }
  221. }
  222. } else {
  223. for (int i = 0; i < 10; i++) {
  224. int offset = center - 5 + i + i / 5;
  225. if ([modeMessage get:i]) {
  226. [matrix setX:offset y:center - 7];
  227. }
  228. if ([modeMessage get:i + 10]) {
  229. [matrix setX:center + 7 y:offset];
  230. }
  231. if ([modeMessage get:29 - i]) {
  232. [matrix setX:offset y:center + 7];
  233. }
  234. if ([modeMessage get:39 - i]) {
  235. [matrix setX:center - 7 y:offset];
  236. }
  237. }
  238. }
  239. }
  240. + (ZXBitArray *)generateCheckWords:(ZXBitArray *)bitArray totalBits:(int)totalBits wordSize:(int)wordSize {
  241. // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
  242. int messageSizeInWords = bitArray.size / wordSize;
  243. ZXReedSolomonEncoder *rs = [[ZXReedSolomonEncoder alloc] initWithField:[self getGF:wordSize]];
  244. int totalWords = totalBits / wordSize;
  245. ZXIntArray *messageWords = [self bitsToWords:bitArray wordSize:wordSize totalWords:totalWords];
  246. [rs encode:messageWords ecBytes:totalWords - messageSizeInWords];
  247. int startPad = totalBits % wordSize;
  248. ZXBitArray *messageBits = [[ZXBitArray alloc] init];
  249. [messageBits appendBits:0 numBits:startPad];
  250. for (int i = 0; i < totalWords; i++) {
  251. [messageBits appendBits:messageWords.array[i] numBits:wordSize];
  252. }
  253. return messageBits;
  254. }
  255. + (ZXIntArray *)bitsToWords:(ZXBitArray *)stuffedBits wordSize:(int)wordSize totalWords:(int)totalWords {
  256. ZXIntArray *message = [[ZXIntArray alloc] initWithLength:totalWords];
  257. int i;
  258. int n;
  259. for (i = 0, n = stuffedBits.size / wordSize; i < n; i++) {
  260. int32_t value = 0;
  261. for (int j = 0; j < wordSize; j++) {
  262. value |= [stuffedBits get:i * wordSize + j] ? (1 << (wordSize - j - 1)) : 0;
  263. }
  264. message.array[i] = value;
  265. }
  266. return message;
  267. }
  268. + (ZXGenericGF *)getGF:(int)wordSize {
  269. switch (wordSize) {
  270. case 4:
  271. return [ZXGenericGF AztecParam];
  272. case 6:
  273. return [ZXGenericGF AztecData6];
  274. case 8:
  275. return [ZXGenericGF AztecData8];
  276. case 10:
  277. return [ZXGenericGF AztecData10];
  278. case 12:
  279. return [ZXGenericGF AztecData12];
  280. default:
  281. return nil;
  282. }
  283. }
  284. + (ZXBitArray *)stuffBits:(ZXBitArray *)bits wordSize:(int)wordSize {
  285. ZXBitArray *arrayOut = [[ZXBitArray alloc] init];
  286. int n = bits.size;
  287. int mask = (1 << wordSize) - 2;
  288. for (int i = 0; i < n; i += wordSize) {
  289. int word = 0;
  290. for (int j = 0; j < wordSize; j++) {
  291. if (i + j >= n || [bits get:i + j]) {
  292. word |= 1 << (wordSize - 1 - j);
  293. }
  294. }
  295. if ((word & mask) == mask) {
  296. [arrayOut appendBits:word & mask numBits:wordSize];
  297. i--;
  298. } else if ((word & mask) == 0) {
  299. [arrayOut appendBits:word | 1 numBits:wordSize];
  300. i--;
  301. } else {
  302. [arrayOut appendBits:word numBits:wordSize];
  303. }
  304. }
  305. return arrayOut;
  306. }
  307. + (int)totalBitsInLayer:(int)layers compact:(BOOL)compact {
  308. return ((compact ? 88 : 112) + 16 * layers) * layers;
  309. }
  310. @end