PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/BlackBerry/BarcodeScanner/OS5/Library/src/org/apache/cordova/plugins/barcodescanner/google/zxing/oned/Code93Reader.java

https://github.com/macdonst/phonegap-plugins
Java | 274 lines | 212 code | 26 blank | 36 comment | 62 complexity | 23025a4dd6831102bc5c400fbc0e32e2 MD5 | raw file
  1. /*
  2. * Copyright 2010 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. package org.apache.cordova.plugins.barcodescanner.google.zxing.oned;
  17. import java.util.Hashtable;
  18. import org.apache.cordova.plugins.barcodescanner.google.zxing.BarcodeFormat;
  19. import org.apache.cordova.plugins.barcodescanner.google.zxing.ChecksumException;
  20. import org.apache.cordova.plugins.barcodescanner.google.zxing.FormatException;
  21. import org.apache.cordova.plugins.barcodescanner.google.zxing.NotFoundException;
  22. import org.apache.cordova.plugins.barcodescanner.google.zxing.Result;
  23. import org.apache.cordova.plugins.barcodescanner.google.zxing.ResultPoint;
  24. import org.apache.cordova.plugins.barcodescanner.google.zxing.common.BitArray;
  25. /**
  26. * <p>Decodes Code 93 barcodes.</p>
  27. *
  28. * @author Sean Owen
  29. * @see Code39Reader
  30. */
  31. public final class Code93Reader extends OneDReader {
  32. // Note that 'abcd' are dummy characters in place of control characters.
  33. private static final String ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*";
  34. private static final char[] ALPHABET = ALPHABET_STRING.toCharArray();
  35. /**
  36. * These represent the encodings of characters, as patterns of wide and narrow bars.
  37. * The 9 least-significant bits of each int correspond to the pattern of wide and narrow.
  38. */
  39. private static final int[] CHARACTER_ENCODINGS = {
  40. 0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, // 0-9
  41. 0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, // A-J
  42. 0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, // K-T
  43. 0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, // U-Z
  44. 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - %
  45. 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-*
  46. };
  47. private static final int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47];
  48. public Result decodeRow(int rowNumber, BitArray row, Hashtable hints)
  49. throws NotFoundException, ChecksumException, FormatException {
  50. int[] start = findAsteriskPattern(row);
  51. int nextStart = start[1];
  52. int end = row.getSize();
  53. // Read off white space
  54. while (nextStart < end && !row.get(nextStart)) {
  55. nextStart++;
  56. }
  57. StringBuffer result = new StringBuffer(20);
  58. int[] counters = new int[6];
  59. char decodedChar;
  60. int lastStart;
  61. do {
  62. recordPattern(row, nextStart, counters);
  63. int pattern = toPattern(counters);
  64. if (pattern < 0) {
  65. throw NotFoundException.getNotFoundInstance();
  66. }
  67. decodedChar = patternToChar(pattern);
  68. result.append(decodedChar);
  69. lastStart = nextStart;
  70. for (int i = 0; i < counters.length; i++) {
  71. nextStart += counters[i];
  72. }
  73. // Read off white space
  74. while (nextStart < end && !row.get(nextStart)) {
  75. nextStart++;
  76. }
  77. } while (decodedChar != '*');
  78. result.deleteCharAt(result.length() - 1); // remove asterisk
  79. // Should be at least one more black module
  80. if (nextStart == end || !row.get(nextStart)) {
  81. throw NotFoundException.getNotFoundInstance();
  82. }
  83. if (result.length() < 2) {
  84. // Almost surely a false positive
  85. throw NotFoundException.getNotFoundInstance();
  86. }
  87. checkChecksums(result);
  88. // Remove checksum digits
  89. result.setLength(result.length() - 2);
  90. String resultString = decodeExtended(result);
  91. float left = (float) (start[1] + start[0]) / 2.0f;
  92. float right = (float) (nextStart + lastStart) / 2.0f;
  93. return new Result(
  94. resultString,
  95. null,
  96. new ResultPoint[]{
  97. new ResultPoint(left, (float) rowNumber),
  98. new ResultPoint(right, (float) rowNumber)},
  99. BarcodeFormat.CODE_93);
  100. }
  101. private static int[] findAsteriskPattern(BitArray row) throws NotFoundException {
  102. int width = row.getSize();
  103. int rowOffset = 0;
  104. while (rowOffset < width) {
  105. if (row.get(rowOffset)) {
  106. break;
  107. }
  108. rowOffset++;
  109. }
  110. int counterPosition = 0;
  111. int[] counters = new int[6];
  112. int patternStart = rowOffset;
  113. boolean isWhite = false;
  114. int patternLength = counters.length;
  115. for (int i = rowOffset; i < width; i++) {
  116. boolean pixel = row.get(i);
  117. if (pixel ^ isWhite) {
  118. counters[counterPosition]++;
  119. } else {
  120. if (counterPosition == patternLength - 1) {
  121. if (toPattern(counters) == ASTERISK_ENCODING) {
  122. return new int[]{patternStart, i};
  123. }
  124. patternStart += counters[0] + counters[1];
  125. for (int y = 2; y < patternLength; y++) {
  126. counters[y - 2] = counters[y];
  127. }
  128. counters[patternLength - 2] = 0;
  129. counters[patternLength - 1] = 0;
  130. counterPosition--;
  131. } else {
  132. counterPosition++;
  133. }
  134. counters[counterPosition] = 1;
  135. isWhite = !isWhite;
  136. }
  137. }
  138. throw NotFoundException.getNotFoundInstance();
  139. }
  140. private static int toPattern(int[] counters) {
  141. int max = counters.length;
  142. int sum = 0;
  143. for (int i = 0; i < max; i++) {
  144. sum += counters[i];
  145. }
  146. int pattern = 0;
  147. for (int i = 0; i < max; i++) {
  148. int scaledShifted = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum;
  149. int scaledUnshifted = scaledShifted >> INTEGER_MATH_SHIFT;
  150. if ((scaledShifted & 0xFF) > 0x7F) {
  151. scaledUnshifted++;
  152. }
  153. if (scaledUnshifted < 1 || scaledUnshifted > 4) {
  154. return -1;
  155. }
  156. if ((i & 0x01) == 0) {
  157. for (int j = 0; j < scaledUnshifted; j++) {
  158. pattern = (pattern << 1) | 0x01;
  159. }
  160. } else {
  161. pattern <<= scaledUnshifted;
  162. }
  163. }
  164. return pattern;
  165. }
  166. private static char patternToChar(int pattern) throws NotFoundException {
  167. for (int i = 0; i < CHARACTER_ENCODINGS.length; i++) {
  168. if (CHARACTER_ENCODINGS[i] == pattern) {
  169. return ALPHABET[i];
  170. }
  171. }
  172. throw NotFoundException.getNotFoundInstance();
  173. }
  174. private static String decodeExtended(StringBuffer encoded) throws FormatException {
  175. int length = encoded.length();
  176. StringBuffer decoded = new StringBuffer(length);
  177. for (int i = 0; i < length; i++) {
  178. char c = encoded.charAt(i);
  179. if (c >= 'a' && c <= 'd') {
  180. char next = encoded.charAt(i + 1);
  181. char decodedChar = '\0';
  182. switch (c) {
  183. case 'd':
  184. // +A to +Z map to a to z
  185. if (next >= 'A' && next <= 'Z') {
  186. decodedChar = (char) (next + 32);
  187. } else {
  188. throw FormatException.getFormatInstance();
  189. }
  190. break;
  191. case 'a':
  192. // $A to $Z map to control codes SH to SB
  193. if (next >= 'A' && next <= 'Z') {
  194. decodedChar = (char) (next - 64);
  195. } else {
  196. throw FormatException.getFormatInstance();
  197. }
  198. break;
  199. case 'b':
  200. // %A to %E map to control codes ESC to US
  201. if (next >= 'A' && next <= 'E') {
  202. decodedChar = (char) (next - 38);
  203. } else if (next >= 'F' && next <= 'W') {
  204. decodedChar = (char) (next - 11);
  205. } else {
  206. throw FormatException.getFormatInstance();
  207. }
  208. break;
  209. case 'c':
  210. // /A to /O map to ! to , and /Z maps to :
  211. if (next >= 'A' && next <= 'O') {
  212. decodedChar = (char) (next - 32);
  213. } else if (next == 'Z') {
  214. decodedChar = ':';
  215. } else {
  216. throw FormatException.getFormatInstance();
  217. }
  218. break;
  219. }
  220. decoded.append(decodedChar);
  221. // bump up i again since we read two characters
  222. i++;
  223. } else {
  224. decoded.append(c);
  225. }
  226. }
  227. return decoded.toString();
  228. }
  229. private static void checkChecksums(StringBuffer result) throws ChecksumException {
  230. int length = result.length();
  231. checkOneChecksum(result, length - 2, 20);
  232. checkOneChecksum(result, length - 1, 15);
  233. }
  234. private static void checkOneChecksum(StringBuffer result, int checkPosition, int weightMax)
  235. throws ChecksumException {
  236. int weight = 1;
  237. int total = 0;
  238. for (int i = checkPosition - 1; i >= 0; i--) {
  239. total += weight * ALPHABET_STRING.indexOf(result.charAt(i));
  240. if (++weight > weightMax) {
  241. weight = 1;
  242. }
  243. }
  244. if (result.charAt(checkPosition) != ALPHABET[total % 47]) {
  245. throw ChecksumException.getChecksumInstance();
  246. }
  247. }
  248. }