2 * Copyright 2009 ZXing authors
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.google.zxing.pdf417.decoder;
\r
19 import com.google.zxing.ReaderException;
\r
20 import com.google.zxing.common.DecoderResult;
\r
23 * <p>This class contains the methods for decoding the PDF417 codewords.</p>
\r
25 * @author SITA Lab (kevin.osullivan@sita.aero)
\r
27 final class DecodedBitStreamParser {
\r
29 private static final int TEXT_COMPACTION_MODE_LATCH = 900;
\r
30 private static final int BYTE_COMPACTION_MODE_LATCH = 901;
\r
31 private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;
\r
32 private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;
\r
33 private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;
\r
34 private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
\r
35 private static final int MACRO_PDF417_TERMINATOR = 922;
\r
36 private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;
\r
37 private static final int MAX_NUMERIC_CODEWORDS = 15;
\r
39 private static final int ALPHA = 0;
\r
40 private static final int LOWER = 1;
\r
41 private static final int MIXED = 2;
\r
42 private static final int PUNCT = 3;
\r
43 private static final int PUNCT_SHIFT = 4;
\r
45 private static final int PL = 25;
\r
46 private static final int LL = 27;
\r
47 private static final int AS = 27;
\r
48 private static final int ML = 28;
\r
49 private static final int AL = 28;
\r
50 private static final int PS = 29;
\r
51 private static final int PAL = 29;
\r
53 private static final char[] PUNCT_CHARS = {';', '<', '>', '@', '[', 92, '}', '_', 96, '~', '!',
\r
54 13, 9, ',', ':', 10, '-', '.', '$', '/', 34, '|', '*',
\r
55 '(', ')', '?', '{', '}', 39};
\r
57 private static final char[] MIXED_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&',
\r
58 13, 9, ',', ':', '#', '-', '.', '$', '/', '+', '%', '*',
\r
61 // Table containing values for the exponent of 900.
\r
62 // This is used in the numeric compaction decode algorithm.
\r
63 private static final String[] EXP900 =
\r
64 { "000000000000000000000000000000000000000000001",
\r
65 "000000000000000000000000000000000000000000900",
\r
66 "000000000000000000000000000000000000000810000",
\r
67 "000000000000000000000000000000000000729000000",
\r
68 "000000000000000000000000000000000656100000000",
\r
69 "000000000000000000000000000000590490000000000",
\r
70 "000000000000000000000000000531441000000000000",
\r
71 "000000000000000000000000478296900000000000000",
\r
72 "000000000000000000000430467210000000000000000",
\r
73 "000000000000000000387420489000000000000000000",
\r
74 "000000000000000348678440100000000000000000000",
\r
75 "000000000000313810596090000000000000000000000",
\r
76 "000000000282429536481000000000000000000000000",
\r
77 "000000254186582832900000000000000000000000000",
\r
78 "000228767924549610000000000000000000000000000",
\r
79 "205891132094649000000000000000000000000000000"};
\r
81 private DecodedBitStreamParser() {
\r
84 static DecoderResult decode(int[] codewords) throws ReaderException {
\r
85 StringBuffer result = new StringBuffer(100);
\r
86 // Get compaction mode
\r
88 int code = codewords[codeIndex++];
\r
89 while (codeIndex < codewords[0]) {
\r
91 case TEXT_COMPACTION_MODE_LATCH: {
\r
92 codeIndex = textCompaction(codewords, codeIndex, result);
\r
95 case BYTE_COMPACTION_MODE_LATCH: {
\r
96 codeIndex = byteCompaction(code, codewords, codeIndex, result);
\r
99 case NUMERIC_COMPACTION_MODE_LATCH: {
\r
100 codeIndex = numericCompaction(codewords, codeIndex, result);
\r
103 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {
\r
104 codeIndex = byteCompaction(code, codewords, codeIndex, result);
\r
107 case BYTE_COMPACTION_MODE_LATCH_6: {
\r
108 codeIndex = byteCompaction(code, codewords, codeIndex, result);
\r
112 // Default to text compaction. During testing numberous barcodes
\r
113 // appeared to be missing the starting mode. In these cases defaulting
\r
114 // to text compaction seems to work.
\r
116 codeIndex = textCompaction(codewords, codeIndex, result);
\r
120 if (codeIndex < codewords.length) {
\r
121 code = codewords[codeIndex++];
\r
123 throw ReaderException.getInstance();
\r
126 return new DecoderResult(null, result.toString(), null, null);
\r
130 * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be
\r
131 * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as
\r
132 * well as selected control characters.
\r
134 * @param codewords The array of codewords (data + error)
\r
135 * @param codeIndex The current index into the codeword array.
\r
136 * @param result The decoded data is appended to the result.
\r
137 * @return The next index into the codeword array.
\r
139 private static int textCompaction(int[] codewords, int codeIndex, StringBuffer result) {
\r
140 // 2 character per codeword
\r
141 int[] textCompactionData = new int[codewords[0] * 2];
\r
142 // Used to hold the byte compaction value if there is a mode shift
\r
143 int[] byteCompactionData = new int[codewords[0] * 2];
\r
147 boolean end = false;
\r
148 while ((codeIndex < codewords[0]) && !end) {
\r
149 code = codewords[codeIndex++];
\r
150 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
151 textCompactionData[index] = code / 30;
\r
152 textCompactionData[index + 1] = code % 30;
\r
156 case TEXT_COMPACTION_MODE_LATCH: {
\r
161 case BYTE_COMPACTION_MODE_LATCH: {
\r
166 case NUMERIC_COMPACTION_MODE_LATCH: {
\r
171 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {
\r
172 // The Mode Shift codeword 913 shall cause a temporary
\r
173 // switch from Text Compaction mode to Byte Compaction mode.
\r
174 // This switch shall be in effect for only the next codeword,
\r
175 // after which the mode shall revert to the prevailing sub-mode
\r
176 // of the Text Compaction mode. Codeword 913 is only available
\r
177 // in Text Compaction mode; its use is described in 5.4.2.4.
\r
178 textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
\r
179 byteCompactionData[index] = code; //Integer.toHexString(code);
\r
183 case BYTE_COMPACTION_MODE_LATCH_6: {
\r
191 decodeTextCompaction(textCompactionData, byteCompactionData, index, result);
\r
196 * The Text Compaction mode includes all the printable ASCII characters
\r
197 * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
\r
198 * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
\r
199 * return (ASCII value 13). The Text Compaction mode also includes various latch
\r
200 * and shift characters which are used exclusively within the mode. The Text
\r
201 * Compaction mode encodes up to 2 characters per codeword. The compaction rules
\r
202 * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
\r
203 * switches are defined in 5.4.2.3.
\r
205 * @param textCompactionData The text compaction data.
\r
206 * @param byteCompactionData The byte compaction data if there
\r
207 * was a mode shift.
\r
208 * @param length The size of the text compaction and byte compaction data.
\r
209 * @param result The decoded data is appended to the result.
\r
211 private static void decodeTextCompaction(int[] textCompactionData,
\r
212 int[] byteCompactionData,
\r
214 StringBuffer result) {
\r
215 // Beginning from an initial state of the Alpha sub-mode
\r
216 // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
\r
217 // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
\r
218 // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.
\r
219 int subMode = ALPHA;
\r
220 int priorToShiftMode = ALPHA;
\r
222 while (i < length) {
\r
223 int subModeCh = textCompactionData[i];
\r
227 // Alpha (uppercase alphabetic)
\r
228 if (subModeCh < 26) {
\r
229 // Upper case Alpha Character
\r
230 ch = (char) ('A' + subModeCh);
\r
232 if (subModeCh == 26) {
\r
234 } else if (subModeCh == LL) {
\r
236 } else if (subModeCh == ML) {
\r
238 } else if (subModeCh == PS) {
\r
239 // Shift to punctuation
\r
240 priorToShiftMode = subMode;
\r
241 subMode = PUNCT_SHIFT;
\r
242 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
243 result.append((char) byteCompactionData[i]);
\r
249 // Lower (lowercase alphabetic)
\r
250 if (subModeCh < 26) {
\r
251 ch = (char) ('a' + subModeCh);
\r
253 if (subModeCh == 26) {
\r
255 } else if (subModeCh == AL) {
\r
257 } else if (subModeCh == ML) {
\r
259 } else if (subModeCh == PS) {
\r
260 // Shift to punctuation
\r
261 priorToShiftMode = subMode;
\r
262 subMode = PUNCT_SHIFT;
\r
263 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
264 result.append((char) byteCompactionData[i]);
\r
270 // Mixed (numeric and some punctuation)
\r
271 if (subModeCh < PL) {
\r
272 ch = MIXED_CHARS[subModeCh];
\r
274 if (subModeCh == PL) {
\r
276 } else if (subModeCh == 26) {
\r
278 } else if (subModeCh == AS) {
\r
279 //mode_change = true;
\r
280 } else if (subModeCh == AL) {
\r
282 } else if (subModeCh == PS) {
\r
283 // Shift to punctuation
\r
284 priorToShiftMode = subMode;
\r
285 subMode = PUNCT_SHIFT;
\r
286 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
287 result.append((char) byteCompactionData[i]);
\r
294 if (subModeCh < PS) {
\r
295 ch = PUNCT_CHARS[subModeCh];
\r
297 if (subModeCh == PAL) {
\r
299 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
300 result.append((char) byteCompactionData[i]);
\r
306 // Restore sub-mode
\r
307 subMode = priorToShiftMode;
\r
308 if (subModeCh < PS) {
\r
309 ch = PUNCT_CHARS[subModeCh];
\r
311 if (subModeCh == PAL) {
\r
318 // Append decoded character to result
\r
326 * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
\r
327 * This includes all ASCII characters value 0 to 127 inclusive and provides for international
\r
328 * character set support.
\r
330 * @param mode The byte compaction mode i.e. 901 or 924
\r
331 * @param codewords The array of codewords (data + error)
\r
332 * @param codeIndex The current index into the codeword array.
\r
333 * @param result The decoded data is appended to the result.
\r
334 * @return The next index into the codeword array.
\r
336 private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuffer result) {
\r
337 if (mode == BYTE_COMPACTION_MODE_LATCH) {
\r
338 // Total number of Byte Compaction characters to be encoded
\r
339 // is not a multiple of 6
\r
342 char[] decodedData = new char[6];
\r
343 int[] byteCompactedCodewords = new int[6];
\r
345 boolean end = false;
\r
346 while ((codeIndex < codewords[0]) && !end) {
\r
347 code = codewords[codeIndex++];
\r
348 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
349 byteCompactedCodewords[count] = code;
\r
355 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
356 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
357 (code == NUMERIC_COMPACTION_MODE_LATCH) ||
\r
358 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
359 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
360 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
361 (code == MACRO_PDF417_TERMINATOR)) {
\r
366 if ((count % 5 == 0) && (count > 0)) {
\r
367 // Decode every 5 codewords
\r
368 // Convert to Base 256
\r
369 for (int j = 0; j < 6; ++j) {
\r
370 decodedData[5 - j] = (char) (value % 256);
\r
373 result.append(decodedData);
\r
377 // If Byte Compaction mode is invoked with codeword 901,
\r
378 // the final group of codewords is interpreted directly
\r
379 // as one byte per codeword, without compaction.
\r
380 for (int i = ((count / 5) * 5); i < count; i++) {
\r
381 result.append((char) byteCompactedCodewords[i]);
\r
384 } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {
\r
385 // Total number of Byte Compaction characters to be encoded
\r
386 // is an integer multiple of 6
\r
390 boolean end = false;
\r
391 while ((codeIndex < codewords[0]) && !end) {
\r
392 code = codewords[codeIndex++];
\r
393 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
399 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
400 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
401 (code == NUMERIC_COMPACTION_MODE_LATCH) ||
\r
402 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
403 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
404 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
405 (code == MACRO_PDF417_TERMINATOR)) {
\r
410 if ((count % 5 == 0) && (count > 0)) {
\r
411 // Decode every 5 codewords
\r
412 // Convert to Base 256
\r
413 char[] decodedData = new char[6];
\r
414 for (int j = 0; j < 6; ++j) {
\r
415 decodedData[5 - j] = (char) (value % 256);
\r
418 result.append(decodedData);
\r
426 * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
\r
428 * @param codewords The array of codewords (data + error)
\r
429 * @param codeIndex The current index into the codeword array.
\r
430 * @param result The decoded data is appended to the result.
\r
431 * @return The next index into the codeword array.
\r
433 private static int numericCompaction(int[] codewords, int codeIndex, StringBuffer result) {
\r
435 boolean end = false;
\r
437 int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];
\r
439 while ((codeIndex < codewords.length) && !end) {
\r
440 int code = codewords[codeIndex++];
\r
441 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
442 numericCodewords[count] = code;
\r
445 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
446 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
447 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
448 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
449 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
450 (code == MACRO_PDF417_TERMINATOR)) {
\r
455 if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||
\r
456 code == NUMERIC_COMPACTION_MODE_LATCH) {
\r
457 // Re-invoking Numeric Compaction mode (by using codeword 902
\r
458 // while in Numeric Compaction mode) serves to terminate the
\r
459 // current Numeric Compaction mode grouping as described in 5.4.4.2,
\r
460 // and then to start a new one grouping.
\r
461 String s = decodeBase900toBase10(numericCodewords, count);
\r
470 * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
\r
472 * @param codewords The array of codewords
\r
473 * @param count The number of codewords
\r
474 * @return The decoded string representing the Numeric data.
\r
478 Encode the fifteen digit numeric string 000213298174000
\r
479 Prefix the numeric string with a 1 and set the initial value of
\r
480 t = 1 000 213 298 174 000
\r
481 Calculate codeword 0
\r
482 d0 = 1 000 213 298 174 000 mod 900 = 200
\r
484 t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
\r
485 Calculate codeword 1
\r
486 d1 = 1 111 348 109 082 mod 900 = 282
\r
488 t = 1 111 348 109 082 div 900 = 1 234 831 232
\r
489 Calculate codeword 2
\r
490 d2 = 1 234 831 232 mod 900 = 632
\r
492 t = 1 234 831 232 div 900 = 1 372 034
\r
493 Calculate codeword 3
\r
494 d3 = 1 372 034 mod 900 = 434
\r
496 t = 1 372 034 div 900 = 1 524
\r
497 Calculate codeword 4
\r
498 d4 = 1 524 mod 900 = 624
\r
500 t = 1 524 div 900 = 1
\r
501 Calculate codeword 5
\r
504 Codeword sequence is: 1, 624, 434, 632, 282, 200
\r
506 Decode the above codewords involves
\r
507 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
\r
508 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
\r
510 Remove leading 1 => Result is 000213298174000
\r
512 As there are huge numbers involved here we must use fake out the maths using string
\r
513 tokens for the numbers.
\r
514 BigDecimal is not supported by J2ME.
\r
516 private static String decodeBase900toBase10(int[] codewords, int count) {
\r
517 StringBuffer accum = null;
\r
518 StringBuffer value = null;
\r
519 for (int i = 0; i < count; i++) {
\r
520 value = multiply(EXP900[count - i - 1], codewords[i]);
\r
521 if (accum == null) {
\r
522 // First time in accum=0
\r
525 accum = add(accum.toString(), value.toString());
\r
528 String result = null;
\r
529 // Remove leading '1' which was inserted to preserce
\r
531 for (int i = 0; i < accum.length(); i++) {
\r
532 if (accum.charAt(i) == '1') {
\r
533 //result = accum.substring(i + 1);
\r
534 result = accum.toString().substring(i + 1);
\r
538 if (result == null) {
\r
539 // No leading 1 => just write the converted number.
\r
540 result = accum.toString();
\r
546 * Multiplies two String numbers
\r
548 * @param value1 Any number represented as a string.
\r
549 * @param value2 A number <= 999.
\r
550 * @return the result of value1 * value2.
\r
552 private static StringBuffer multiply(String value1, int value2) {
\r
553 StringBuffer result = new StringBuffer(value1.length());
\r
554 for (int i = 0; i < value1.length(); i++) {
\r
555 // Put zeros into the result.
\r
556 result.append('0');
\r
558 int hundreds = value2 / 100;
\r
559 int tens = (value2 / 10) % 10;
\r
560 int ones = value2 % 10;
\r
561 // Multiply by ones
\r
562 for (int j = 0; j < ones; j++) {
\r
563 result = add(result.toString(), value1);
\r
565 // Multiply by tens
\r
566 for (int j = 0; j < tens; j++) {
\r
567 result = add(result.toString(), (value1 + '0').substring(1));
\r
569 // Multiply by hundreds
\r
570 for (int j = 0; j < hundreds; j++) {
\r
571 result = add(result.toString(), (value1 + "00").substring(2));
\r
577 * Add two numbers which are represented as strings.
\r
581 * @return the result of value1 + value2
\r
583 private static StringBuffer add(String value1, String value2) {
\r
584 StringBuffer temp1 = new StringBuffer(5);
\r
585 StringBuffer temp2 = new StringBuffer(5);
\r
586 StringBuffer result = new StringBuffer(value1.length());
\r
587 for (int i = 0; i < value1.length(); i++) {
\r
588 // Put zeros into the result.
\r
589 result.append('0');
\r
592 for (int i = value1.length() - 3; i > -1; i -= 3) {
\r
594 temp1.setLength(0);
\r
595 temp1.append(value1.charAt(i));
\r
596 temp1.append(value1.charAt(i + 1));
\r
597 temp1.append(value1.charAt(i + 2));
\r
599 temp2.setLength(0);
\r
600 temp2.append(value2.charAt(i));
\r
601 temp2.append(value2.charAt(i + 1));
\r
602 temp2.append(value2.charAt(i + 2));
\r
604 int intValue1 = Integer.parseInt(temp1.toString());
\r
605 int intValue2 = Integer.parseInt(temp2.toString());
\r
607 int sumval = (intValue1 + intValue2 + carry) % 1000;
\r
608 carry = (intValue1 + intValue2 + carry) / 1000;
\r
610 result.setCharAt(i + 2, (char) ((sumval % 10) + '0'));
\r
611 result.setCharAt(i + 1, (char) (((sumval / 10) % 10) + '0'));
\r
612 result.setCharAt(i, (char) ((sumval / 100) + '0'));
\r
618 private static String decodeBase900toBase10(int codewords[], int count) {
\r
619 BigInteger accum = BigInteger.valueOf(0);
\r
620 BigInteger value = null;
\r
621 for (int i = 0; i < count; i++) {
\r
622 value = BigInteger.valueOf(900).pow(count - i - 1);
\r
623 value = value.multiply(BigInteger.valueOf(codewords[i]));
\r
624 accum = accum.add(value);
\r
626 if (debug) System.out.println("Big Integer " + accum);
\r
627 String result = accum.toString().substring(1);
\r