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.FormatException;
\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 FormatException {
\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 numerous 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 FormatException.getFormatInstance();
\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] << 1];
\r
142 // Used to hold the byte compaction value if there is a mode shift
\r
143 int[] byteCompactionData = new int[codewords[0] << 1];
\r
146 boolean end = false;
\r
147 while ((codeIndex < codewords[0]) && !end) {
\r
148 int code = codewords[codeIndex++];
\r
149 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
150 textCompactionData[index] = code / 30;
\r
151 textCompactionData[index + 1] = code % 30;
\r
155 case TEXT_COMPACTION_MODE_LATCH: {
\r
160 case BYTE_COMPACTION_MODE_LATCH: {
\r
165 case NUMERIC_COMPACTION_MODE_LATCH: {
\r
170 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: {
\r
171 // The Mode Shift codeword 913 shall cause a temporary
\r
172 // switch from Text Compaction mode to Byte Compaction mode.
\r
173 // This switch shall be in effect for only the next codeword,
\r
174 // after which the mode shall revert to the prevailing sub-mode
\r
175 // of the Text Compaction mode. Codeword 913 is only available
\r
176 // in Text Compaction mode; its use is described in 5.4.2.4.
\r
177 textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
\r
178 byteCompactionData[index] = code; //Integer.toHexString(code);
\r
182 case BYTE_COMPACTION_MODE_LATCH_6: {
\r
190 decodeTextCompaction(textCompactionData, byteCompactionData, index, result);
\r
195 * The Text Compaction mode includes all the printable ASCII characters
\r
196 * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
\r
197 * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
\r
198 * return (ASCII value 13). The Text Compaction mode also includes various latch
\r
199 * and shift characters which are used exclusively within the mode. The Text
\r
200 * Compaction mode encodes up to 2 characters per codeword. The compaction rules
\r
201 * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
\r
202 * switches are defined in 5.4.2.3.
\r
204 * @param textCompactionData The text compaction data.
\r
205 * @param byteCompactionData The byte compaction data if there
\r
206 * was a mode shift.
\r
207 * @param length The size of the text compaction and byte compaction data.
\r
208 * @param result The decoded data is appended to the result.
\r
210 private static void decodeTextCompaction(int[] textCompactionData,
\r
211 int[] byteCompactionData,
\r
213 StringBuffer result) {
\r
214 // Beginning from an initial state of the Alpha sub-mode
\r
215 // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
\r
216 // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
\r
217 // Compaction mode shall always switch to the Text Compaction Alpha sub-mode.
\r
218 int subMode = ALPHA;
\r
219 int priorToShiftMode = ALPHA;
\r
221 while (i < length) {
\r
222 int subModeCh = textCompactionData[i];
\r
226 // Alpha (uppercase alphabetic)
\r
227 if (subModeCh < 26) {
\r
228 // Upper case Alpha Character
\r
229 ch = (char) ('A' + subModeCh);
\r
231 if (subModeCh == 26) {
\r
233 } else if (subModeCh == LL) {
\r
235 } else if (subModeCh == ML) {
\r
237 } else if (subModeCh == PS) {
\r
238 // Shift to punctuation
\r
239 priorToShiftMode = subMode;
\r
240 subMode = PUNCT_SHIFT;
\r
241 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
242 result.append((char) byteCompactionData[i]);
\r
248 // Lower (lowercase alphabetic)
\r
249 if (subModeCh < 26) {
\r
250 ch = (char) ('a' + subModeCh);
\r
252 if (subModeCh == 26) {
\r
254 } else if (subModeCh == AL) {
\r
256 } else if (subModeCh == ML) {
\r
258 } else if (subModeCh == PS) {
\r
259 // Shift to punctuation
\r
260 priorToShiftMode = subMode;
\r
261 subMode = PUNCT_SHIFT;
\r
262 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
263 result.append((char) byteCompactionData[i]);
\r
269 // Mixed (numeric and some punctuation)
\r
270 if (subModeCh < PL) {
\r
271 ch = MIXED_CHARS[subModeCh];
\r
273 if (subModeCh == PL) {
\r
275 } else if (subModeCh == 26) {
\r
277 } else if (subModeCh == AS) {
\r
278 //mode_change = true;
\r
279 } else if (subModeCh == AL) {
\r
281 } else if (subModeCh == PS) {
\r
282 // Shift to punctuation
\r
283 priorToShiftMode = subMode;
\r
284 subMode = PUNCT_SHIFT;
\r
285 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
286 result.append((char) byteCompactionData[i]);
\r
293 if (subModeCh < PS) {
\r
294 ch = PUNCT_CHARS[subModeCh];
\r
296 if (subModeCh == PAL) {
\r
298 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
\r
299 result.append((char) byteCompactionData[i]);
\r
305 // Restore sub-mode
\r
306 subMode = priorToShiftMode;
\r
307 if (subModeCh < PS) {
\r
308 ch = PUNCT_CHARS[subModeCh];
\r
310 if (subModeCh == PAL) {
\r
317 // Append decoded character to result
\r
325 * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
\r
326 * This includes all ASCII characters value 0 to 127 inclusive and provides for international
\r
327 * character set support.
\r
329 * @param mode The byte compaction mode i.e. 901 or 924
\r
330 * @param codewords The array of codewords (data + error)
\r
331 * @param codeIndex The current index into the codeword array.
\r
332 * @param result The decoded data is appended to the result.
\r
333 * @return The next index into the codeword array.
\r
335 private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuffer result) {
\r
336 if (mode == BYTE_COMPACTION_MODE_LATCH) {
\r
337 // Total number of Byte Compaction characters to be encoded
\r
338 // is not a multiple of 6
\r
341 char[] decodedData = new char[6];
\r
342 int[] byteCompactedCodewords = new int[6];
\r
343 boolean end = false;
\r
344 while ((codeIndex < codewords[0]) && !end) {
\r
345 int code = codewords[codeIndex++];
\r
346 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
347 byteCompactedCodewords[count] = code;
\r
353 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
354 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
355 (code == NUMERIC_COMPACTION_MODE_LATCH) ||
\r
356 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
357 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
358 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
359 (code == MACRO_PDF417_TERMINATOR)) {
\r
364 if ((count % 5 == 0) && (count > 0)) {
\r
365 // Decode every 5 codewords
\r
366 // Convert to Base 256
\r
367 for (int j = 0; j < 6; ++j) {
\r
368 decodedData[5 - j] = (char) (value % 256);
\r
371 result.append(decodedData);
\r
375 // If Byte Compaction mode is invoked with codeword 901,
\r
376 // the final group of codewords is interpreted directly
\r
377 // as one byte per codeword, without compaction.
\r
378 for (int i = ((count / 5) * 5); i < count; i++) {
\r
379 result.append((char) byteCompactedCodewords[i]);
\r
382 } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {
\r
383 // Total number of Byte Compaction characters to be encoded
\r
384 // is an integer multiple of 6
\r
387 boolean end = false;
\r
388 while ((codeIndex < codewords[0]) && !end) {
\r
389 int code = codewords[codeIndex++];
\r
390 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
396 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
397 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
398 (code == NUMERIC_COMPACTION_MODE_LATCH) ||
\r
399 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
400 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
401 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
402 (code == MACRO_PDF417_TERMINATOR)) {
\r
407 if ((count % 5 == 0) && (count > 0)) {
\r
408 // Decode every 5 codewords
\r
409 // Convert to Base 256
\r
410 char[] decodedData = new char[6];
\r
411 for (int j = 0; j < 6; ++j) {
\r
412 decodedData[5 - j] = (char) (value % 256);
\r
415 result.append(decodedData);
\r
423 * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
\r
425 * @param codewords The array of codewords (data + error)
\r
426 * @param codeIndex The current index into the codeword array.
\r
427 * @param result The decoded data is appended to the result.
\r
428 * @return The next index into the codeword array.
\r
430 private static int numericCompaction(int[] codewords, int codeIndex, StringBuffer result) {
\r
432 boolean end = false;
\r
434 int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];
\r
436 while ((codeIndex < codewords.length) && !end) {
\r
437 int code = codewords[codeIndex++];
\r
438 if (code < TEXT_COMPACTION_MODE_LATCH) {
\r
439 numericCodewords[count] = code;
\r
442 if ((code == TEXT_COMPACTION_MODE_LATCH) ||
\r
443 (code == BYTE_COMPACTION_MODE_LATCH) ||
\r
444 (code == BYTE_COMPACTION_MODE_LATCH_6) ||
\r
445 (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) ||
\r
446 (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) ||
\r
447 (code == MACRO_PDF417_TERMINATOR)) {
\r
452 if ((count % MAX_NUMERIC_CODEWORDS) == 0 ||
\r
453 code == NUMERIC_COMPACTION_MODE_LATCH) {
\r
454 // Re-invoking Numeric Compaction mode (by using codeword 902
\r
455 // while in Numeric Compaction mode) serves to terminate the
\r
456 // current Numeric Compaction mode grouping as described in 5.4.4.2,
\r
457 // and then to start a new one grouping.
\r
458 String s = decodeBase900toBase10(numericCodewords, count);
\r
467 * Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
\r
469 * @param codewords The array of codewords
\r
470 * @param count The number of codewords
\r
471 * @return The decoded string representing the Numeric data.
\r
475 Encode the fifteen digit numeric string 000213298174000
\r
476 Prefix the numeric string with a 1 and set the initial value of
\r
477 t = 1 000 213 298 174 000
\r
478 Calculate codeword 0
\r
479 d0 = 1 000 213 298 174 000 mod 900 = 200
\r
481 t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
\r
482 Calculate codeword 1
\r
483 d1 = 1 111 348 109 082 mod 900 = 282
\r
485 t = 1 111 348 109 082 div 900 = 1 234 831 232
\r
486 Calculate codeword 2
\r
487 d2 = 1 234 831 232 mod 900 = 632
\r
489 t = 1 234 831 232 div 900 = 1 372 034
\r
490 Calculate codeword 3
\r
491 d3 = 1 372 034 mod 900 = 434
\r
493 t = 1 372 034 div 900 = 1 524
\r
494 Calculate codeword 4
\r
495 d4 = 1 524 mod 900 = 624
\r
497 t = 1 524 div 900 = 1
\r
498 Calculate codeword 5
\r
501 Codeword sequence is: 1, 624, 434, 632, 282, 200
\r
503 Decode the above codewords involves
\r
504 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
\r
505 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
\r
507 Remove leading 1 => Result is 000213298174000
\r
509 As there are huge numbers involved here we must use fake out the maths using string
\r
510 tokens for the numbers.
\r
511 BigDecimal is not supported by J2ME.
\r
513 private static String decodeBase900toBase10(int[] codewords, int count) {
\r
514 StringBuffer accum = null;
\r
515 for (int i = 0; i < count; i++) {
\r
516 StringBuffer value = multiply(EXP900[count - i - 1], codewords[i]);
\r
517 if (accum == null) {
\r
518 // First time in accum=0
\r
521 accum = add(accum.toString(), value.toString());
\r
524 String result = null;
\r
525 // Remove leading '1' which was inserted to preserve
\r
527 for (int i = 0; i < accum.length(); i++) {
\r
528 if (accum.charAt(i) == '1') {
\r
529 //result = accum.substring(i + 1);
\r
530 result = accum.toString().substring(i + 1);
\r
534 if (result == null) {
\r
535 // No leading 1 => just write the converted number.
\r
536 result = accum.toString();
\r
542 * Multiplies two String numbers
\r
544 * @param value1 Any number represented as a string.
\r
545 * @param value2 A number <= 999.
\r
546 * @return the result of value1 * value2.
\r
548 private static StringBuffer multiply(String value1, int value2) {
\r
549 StringBuffer result = new StringBuffer(value1.length());
\r
550 for (int i = 0; i < value1.length(); i++) {
\r
551 // Put zeros into the result.
\r
552 result.append('0');
\r
554 int hundreds = value2 / 100;
\r
555 int tens = (value2 / 10) % 10;
\r
556 int ones = value2 % 10;
\r
557 // Multiply by ones
\r
558 for (int j = 0; j < ones; j++) {
\r
559 result = add(result.toString(), value1);
\r
561 // Multiply by tens
\r
562 for (int j = 0; j < tens; j++) {
\r
563 result = add(result.toString(), (value1 + '0').substring(1));
\r
565 // Multiply by hundreds
\r
566 for (int j = 0; j < hundreds; j++) {
\r
567 result = add(result.toString(), (value1 + "00").substring(2));
\r
573 * Add two numbers which are represented as strings.
\r
577 * @return the result of value1 + value2
\r
579 private static StringBuffer add(String value1, String value2) {
\r
580 StringBuffer temp1 = new StringBuffer(5);
\r
581 StringBuffer temp2 = new StringBuffer(5);
\r
582 StringBuffer result = new StringBuffer(value1.length());
\r
583 for (int i = 0; i < value1.length(); i++) {
\r
584 // Put zeros into the result.
\r
585 result.append('0');
\r
588 for (int i = value1.length() - 3; i > -1; i -= 3) {
\r
590 temp1.setLength(0);
\r
591 temp1.append(value1.charAt(i));
\r
592 temp1.append(value1.charAt(i + 1));
\r
593 temp1.append(value1.charAt(i + 2));
\r
595 temp2.setLength(0);
\r
596 temp2.append(value2.charAt(i));
\r
597 temp2.append(value2.charAt(i + 1));
\r
598 temp2.append(value2.charAt(i + 2));
\r
600 int intValue1 = Integer.parseInt(temp1.toString());
\r
601 int intValue2 = Integer.parseInt(temp2.toString());
\r
603 int sumval = (intValue1 + intValue2 + carry) % 1000;
\r
604 carry = (intValue1 + intValue2 + carry) / 1000;
\r
606 result.setCharAt(i + 2, (char) ((sumval % 10) + '0'));
\r
607 result.setCharAt(i + 1, (char) (((sumval / 10) % 10) + '0'));
\r
608 result.setCharAt(i, (char) ((sumval / 100) + '0'));
\r
614 private static String decodeBase900toBase10(int codewords[], int count) {
\r
615 BigInteger accum = BigInteger.valueOf(0);
\r
616 BigInteger value = null;
\r
617 for (int i = 0; i < count; i++) {
\r
618 value = BigInteger.valueOf(900).pow(count - i - 1);
\r
619 value = value.multiply(BigInteger.valueOf(codewords[i]));
\r
620 accum = accum.add(value);
\r
622 if (debug) System.out.println("Big Integer " + accum);
\r
623 String result = accum.toString().substring(1);
\r