aztec decoder passes

This commit is contained in:
Henry Schimke
2022-09-20 12:22:41 -05:00
parent 1b3535c0df
commit 1a0f04736c
2 changed files with 113 additions and 110 deletions

View File

@@ -41,16 +41,16 @@ use super::{decoder, AztecDetectorResult::AztecDetectorRXingResult};
const NO_POINTS: &[RXingResultPoint] = &[RXingResultPoint { x: 0.0, y: 0.0 }; 0]; const NO_POINTS: &[RXingResultPoint] = &[RXingResultPoint { x: 0.0, y: 0.0 }; 0];
#[test] #[test]
fn testHighLevelDecode() { fn test_high_level_decode() {
// no ECI codes // no ECI codes
testHighLevelDecodeString( test_high_level_decode_string(
"A. b.", "A. b.",
// 'A' P/S '. ' L/L b D/L '.' // 'A' P/S '. ' L/L b D/L '.'
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X", "...X. ..... ...XX XXX.. ...XX XXXX. XX.X",
); );
// initial ECI code 26 (switch to UTF-8) // initial ECI code 26 (switch to UTF-8)
testHighLevelDecodeString( test_high_level_decode_string(
"Ça", "Ça",
// P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a' // P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
"..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.", "..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
@@ -58,21 +58,21 @@ fn testHighLevelDecode() {
// initial character without ECI (must be interpreted as ISO_8859_1) // initial character without ECI (must be interpreted as ISO_8859_1)
// followed by ECI code 26 (= UTF-8) and UTF-8 text // followed by ECI code 26 (= UTF-8) and UTF-8 text
testHighLevelDecodeString( test_high_level_decode_string(
"±Ça", "±Ça",
// B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a' // B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
"XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.", "XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
); );
// GS1 data // GS1 data
testHighLevelDecodeString( test_high_level_decode_string(
"101233742", "101233742",
// P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2 // P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
"..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..", "..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..",
); );
} }
fn testHighLevelDecodeString(expectedString: &str, b: &str) { fn test_high_level_decode_string(expectedString: &str, b: &str) {
let bits = toBitArray(&stripSpace(b)); let bits = toBitArray(&stripSpace(b));
assert_eq!( assert_eq!(
expectedString, expectedString,
@@ -83,7 +83,7 @@ fn testHighLevelDecodeString(expectedString: &str, b: &str) {
} }
#[test] #[test]
fn testAztecRXingResult() { fn test_aztec_rxing_result() {
let matrix = BitMatrix::parse_strings( let matrix = BitMatrix::parse_strings(
r"X X X X X X X X X X X X X X r"X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
@@ -148,7 +148,7 @@ X X X X X X X X X X X X X X
} }
#[test] #[test]
fn testAztecRXingResultECI() { fn test_aztec_rxing_result_eci() {
let matrix = BitMatrix::parse_strings( let matrix = BitMatrix::parse_strings(
r" X X X X X X r" X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X
@@ -180,86 +180,86 @@ X X X X X X X X ",
#[test] #[test]
#[should_panic] #[should_panic]
fn testDecodeTooManyErrors() { fn test_decode_too_many_errors() {
let matrix = BitMatrix::parse_strings( let matrix = BitMatrix::parse_strings(
r" r"
X X . X . . . X X . . . X . . X X X . X . X X X X X . X X . X . . . X X . . . X . . X X X . X . X X X X X .
X X . . X X . . . . . X X . . . X X . . . X . X . . X X X . . X X . . . . . X X . . . X X . . . X . X . . X
X . . . X X . . X X X . X X . X X X X . X X . . X . . X . . . X X . . X X X . X X . X X X X . X X . . X . .
. . . . X . X X . . X X . X X . X . X X X X . X . . X . . . . X . X X . . X X . X X . X . X X X X . X . . X
X X X . . X X X X X . . . . . X X . . . X . X . X . X X X X . . X X X X X . . . . . X X . . . X . X . X . X
X X . . . . . . . . X . . . X . X X X . X . . X . . . X X . . . . . . . . X . . . X . X X X . X . . X . . .
X X . . X . . . . . X X . . . . . X . . . . X . . X X \ X X . . X . . . . . X X . . . . . X . . . . X . . X X
. . . X . X . X . . . . . X X X X X X . . . . . . X X . . . X . X . X . . . . . X X X X X X . . . . . . X X
X . . . X . X X X X X X . . X X X . X . X X X X X X . X . . . X . X X X X X X . . X X X . X . X X X X X X .
X . . X X X . X X X X X X X X X X X X X . . . X . X X X . . X X X . X X X X X X X X X X X X X . . . X . X X
. . . . X X . . . X . . . . . . . X X . . . X X . X . . . . . X X . . . X . . . . . . . X X . . . X X . X .
. . . X X X . . X X . X X X X X . X . . X . . . . . . . . . X X X . . X X . X X X X X . X . . X . . . . . .
X . . . . X . X . X . X . . . X . X . X X . X X . X X X . . . . X . X . X . X . . . X . X . X X . X X . X X
X . X . . X . X . X . X . X . X . X . . . . . X . X X X . X . . X . X . X . X . X . X . X . . . . . X . X X
X . X X X . . X . X . X . . . X . X . X X X . . . X X X . X X X . . X . X . X . . . X . X . X X X . . . X X
X X X X X X X X . X . X X X X X . X . X . X . X X X . X X X X X X X X . X . X X X X X . X . X . X . X X X .
. . . . . . . X . X . . . . . . . X X X X . . . X X X . . . . . . . X . X . . . . . . . X X X X . . . X X X
X X . . X . . X . X X X X X X X X X X X X X . . X . X X X . . X . . X . X X X X X X X X X X X X X . . X . X
X X X . X X X X . . X X X X . . X . . . . X . . X X X X X X . X X X X . . X X X X . . X . . . . X . . X X X
. . . . X . X X X . . . . X X X X . . X X X X . . . . . . . . X . X X X . . . . X X X X . . X X X X . . . .
. . X . . X . X . . . X . X X . X X . X . . . X . X . . . X . . X . X . . . X . X X . X X . X . . . X . X .
X X . . X . . X X X X X X X . . X . X X X X X X X . . X X . . X . . X X X X X X X . . X . X X X X X X X . .
X . X X . . X X . . . . . X . . . . . . X X . X X X . X . X X . . X X . . . . . X . . . . . . X X . X X X .
X . . X X . . X X . X . X . . . . X . X . . X . . X . X . . X X . . X X . X . X . . . . X . X . . X . . X .
X . X . X . . X . X X X X X X X X . X X X X . . X X . X . X . X . . X . X X X X X X X X . X X X X . . X X .
X X X X . . . X . . X X X . X X . . X . . . . X X X . X X X X . . . X . . X X X . X X . . X . . . . X X X .
X X . X . X . . . X . X . . . . X X . X . . X X . . . ", X X . X . X . . . X . X . . . . X X . X . . X X . . . ",
"X ", "X ",
". ", ". ",
) )
.expect("parse string success"); .expect("parse string failed");
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4); let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
decoder::decode(&r); assert!(decoder::decode(&r).is_ok());
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn testDecodeTooManyErrors2() { fn test_decode_too_many_errors2() {
let matrix = BitMatrix::parse_strings( let matrix = BitMatrix::parse_strings(
r" r"
. X X . . X . X X . . . X . . X X X . . . X X . X X . . X X . . X . X X . . . X . . X X X . . . X X . X X .
X X . X X . . X . . . X X . . . X X . X X X . X . X X X X . X X . . X . . . X X . . . X X . X X X . X . X X
. . . . X . . . X X X . X X . X X X X . X X . . X . . . . . . X . . . X X X . X X . X X X X . X X . . X . .
X . X X . . X . . . X X . X X . X . X X . . . . . X . X . X X . . X . . . X X . X X . X . X X . . . . . X .
X X . X . . X . X X . . . . . X X . . . . . X . . . X X X . X . . X . X X . . . . . X X . . . . . X . . . X
X . . X . . . . . . X . . . X . X X X X X X X . . . X X . . X . . . . . . X . . . X . X X X X X X X . . . X
X . . X X . . X . . X X . . . . . X . . . . . X X X . X . . X X . . X . . X X . . . . . X . . . . . X X X .
. . X X X X . X . . . . . X X X X X X . . . . . . X X . . X X X X . X . . . . . X X X X X X . . . . . . X X
X . . . X . X X X X X X . . X X X . X . X X X X X X . X . . . X . X X X X X X . . X X X . X . X X X X X X .
X . . X X X . X X X X X X X X X X X X X . . . X . X X X . . X X X . X X X X X X X X X X X X X . . . X . X X
. . . . X X . . . X . . . . . . . X X . . . X X . X . . . . . X X . . . X . . . . . . . X X . . . X X . X .
. . . X X X . . X X . X X X X X . X . . X . . . . . . . . . X X X . . X X . X X X X X . X . . X . . . . . .
X . . . . X . X . X . X . . . X . X . X X . X X . X X X . . . . X . X . X . X . . . X . X . X X . X X . X X
X . X . . X . X . X . X . X . X . X . . . . . X . X X X . X . . X . X . X . X . X . X . X . . . . . X . X X
X . X X X . . X . X . X . . . X . X . X X X . . . X X X . X X X . . X . X . X . . . X . X . X X X . . . X X
X X X X X X X X . X . X X X X X . X . X . X . X X X . X X X X X X X X . X . X X X X X . X . X . X . X X X .
. . . . . . . X . X . . . . . . . X X X X . . . X X X . . . . . . . X . X . . . . . . . X X X X . . . X X X
X X . . X . . X . X X X X X X X X X X X X X . . X . X X X . . X . . X . X X X X X X X X X X X X X . . X . X
X X X . X X X X . . X X X X . . X . . . . X . . X X X X X X . X X X X . . X X X X . . X . . . . X . . X X X
. . X X X X X . X . . . . X X X X . . X X X . X . X . . . X X X X X . X . . . . X X X X . . X X X . X . X .
. . X X . X . X . . . X . X X . X X . . . . X X . . . . . X X . X . X . . . X . X X . X X . . . . X X . . .
X . . . X . X . X X X X X X . . X . X X X X X . X . . X . . . X . X . X X X X X X . . X . X X X X X . X . .
. X . . . X X X . . . . . X . . . . . X X X X X . X . . X . . . X X X . . . . . X . . . . . X X X X X . X .
X . . X . X X X X . X . X . . . . X . X X . X . . X . X . . X . X X X X . X . X . . . . X . X X . X . . X .
X . . . X X . X . X X X X X X X X . X X X X . . X X . X . . . X X . X . X X X X X X X X . X X X X . . X X .
. X X X X . . X . . X X X . X X . . X . . . . X X X . . X X X X . . X . . X X X . X X . . X . . . . X X X .
X X . . . X X . . X . X . . . . X X . X . . X . X . X ", X X . . . X X . . X . X . . . . X X . X . . X . X . X ",
"X ", "X ",
". ", ". ",
) )
.expect("String Parse OK"); .expect("String Parse failed");
let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4); let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
decoder::decode(&r); assert!(decoder::decode(&r).is_ok());
} }
#[test] #[test]
fn testRawBytes() { fn test_raw_bytes() {
let bool0 = vec![false; 0]; let bool0 = vec![false; 0];
let bool1 = vec![true]; let bool1 = vec![true];
let bool7 = vec![true, false, true, false, true, false, true]; let bool7 = vec![true, false, true, false, true, false, true];

View File

@@ -123,33 +123,34 @@ pub fn highLevelDecode(correctedBits: &[bool]) -> Result<String, Exceptions> {
* *
* @return the decoded string * @return the decoded string
*/ */
fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> { fn getEncodedData(corrected_bits: &[bool]) -> Result<String, Exceptions> {
let endIndex = correctedBits.len(); let endIndex = corrected_bits.len();
let mut latchTable = Table::UPPER; // table most recently latched to let mut latch_table = Table::UPPER; // table most recently latched to
let mut shiftTable = Table::UPPER; // table to use for the next read let mut shift_table = Table::UPPER; // table to use for the next read
// Final decoded string result // Final decoded string result
// (correctedBits-5) / 4 is an upper bound on the size (all-digit result) // (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
let mut result = String::with_capacity((correctedBits.len() - 5) / 4); let mut result = String::with_capacity((corrected_bits.len() - 5) / 4);
// Intermediary buffer of decoded bytes, which is decoded into a string and flushed // Intermediary buffer of decoded bytes, which is decoded into a string and flushed
// when character encoding changes (ECI) or input ends. // when character encoding changes (ECI) or input ends.
let mut decodedBytes: Vec<u8> = Vec::new(); let mut decoded_bytes: Vec<u8> = Vec::new();
let mut encdr: &'static dyn encoding::Encoding = encoding::all::UTF_8; // let mut encdr: &'static dyn encoding::Encoding = encoding::all::UTF_8;
let mut encdr: &'static dyn encoding::Encoding = encoding::all::ISO_8859_1;
let mut index = 0; let mut index = 0;
while index < endIndex { while index < endIndex {
if shiftTable == Table::BINARY { if shift_table == Table::BINARY {
if endIndex - index < 5 { if endIndex - index < 5 {
break; break;
} }
let mut length = readCode(correctedBits, index, 5); let mut length = readCode(corrected_bits, index, 5);
index += 5; index += 5;
if length == 0 { if length == 0 {
if endIndex - index < 11 { if endIndex - index < 11 {
break; break;
} }
length = readCode(correctedBits, index, 11) + 31; length = readCode(corrected_bits, index, 11) + 31;
index += 11; index += 11;
} }
for _charCount in 0..length { for _charCount in 0..length {
@@ -158,34 +159,36 @@ fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> {
index = endIndex; // Force outer loop to exit index = endIndex; // Force outer loop to exit
break; break;
} }
let code = readCode(correctedBits, index, 8); let code = readCode(corrected_bits, index, 8);
decodedBytes.push(code as u8); decoded_bytes.push(code as u8);
index += 8; index += 8;
} }
// Go back to whatever mode we had been in // Go back to whatever mode we had been in
shiftTable = latchTable; shift_table = latch_table;
} else { } else {
let size = if shiftTable == Table::DIGIT { 4 } else { 5 }; let size = if shift_table == Table::DIGIT { 4 } else { 5 };
if endIndex - index < size { if endIndex - index < size {
break; break;
} }
let code = readCode(correctedBits, index, size); let code = readCode(corrected_bits, index, size);
index += size; index += size;
let str = getCharacter(shiftTable, code)?; let str = getCharacter(shift_table, code)?;
if "FLG(n)" == str { if "FLG(n)" == str {
if endIndex - index < 3 { if endIndex - index < 3 {
break; break;
} }
let mut n = readCode(correctedBits, index, 3); let mut n = readCode(corrected_bits, index, 3);
index += 3; index += 3;
// flush bytes, FLG changes state // flush bytes, FLG changes state
// try { // try {
result.push_str(&String::from_utf8(decodedBytes.clone()).unwrap()); result.push_str(&encdr.decode(&decoded_bytes, encoding::DecoderTrap::Strict).unwrap());
// result.push_str(&String::from_utf8(decoded_bytes.clone()).unwrap());
// result.append(decodedBytes.toString(encoding.name())); // result.append(decodedBytes.toString(encoding.name()));
// } catch (UnsupportedEncodingException uee) { // } catch (UnsupportedEncodingException uee) {
// throw new IllegalStateException(uee); // throw new IllegalStateException(uee);
// } // }
decodedBytes.clear(); decoded_bytes.clear();
match n { match n {
0 => result.push(29 as char), // translate FNC1 as ASCII 29 0 => result.push(29 as char), // translate FNC1 as ASCII 29
7 => { 7 => {
@@ -201,7 +204,7 @@ fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> {
} }
while n > 0 { while n > 0 {
//while (n-- > 0) { //while (n-- > 0) {
let nextDigit = readCode(correctedBits, index, 4); let nextDigit = readCode(corrected_bits, index, 4);
index += 4; index += 4;
if nextDigit < 2 || nextDigit > 11 { if nextDigit < 2 || nextDigit > 11 {
return Err(Exceptions::FormatException( return Err(Exceptions::FormatException(
@@ -248,16 +251,16 @@ fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> {
// encoding = charsetECI.getCharset(); // encoding = charsetECI.getCharset();
// } // }
// Go back to whatever mode we had been in // Go back to whatever mode we had been in
shiftTable = latchTable; shift_table = latch_table;
} else if str.starts_with("CTRL_") { } else if str.starts_with("CTRL_") {
// Table changes // Table changes
// ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
// That's including when that mode is a shift. // That's including when that mode is a shift.
// Our test case dlusbs.png for issue #642 exercises that. // Our test case dlusbs.png for issue #642 exercises that.
latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S latch_table = shift_table; // Latch the current mode, so as to return to Upper after U/S B/S
shiftTable = getTable(str.chars().nth(5).unwrap()); shift_table = getTable(str.chars().nth(5).unwrap());
if str.chars().nth(6).unwrap() == 'L' { if str.chars().nth(6).unwrap() == 'L' {
latchTable = shiftTable; latch_table = shift_table;
} }
} else { } else {
// Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*. // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
@@ -265,15 +268,15 @@ fn getEncodedData(correctedBits: &[bool]) -> Result<String, Exceptions> {
//let b = str.getBytes(StandardCharsets.US_ASCII); //let b = str.getBytes(StandardCharsets.US_ASCII);
//decodedBytes.write(b, 0, b.length); //decodedBytes.write(b, 0, b.length);
for bt in b { for bt in b {
decodedBytes.push(*bt); decoded_bytes.push(*bt);
} }
// Go back to whatever mode we had been in // Go back to whatever mode we had been in
shiftTable = latchTable; shift_table = latch_table;
} }
} }
} }
//try { //try {
if let Ok(str) = encdr.decode(&decodedBytes, encoding::DecoderTrap::Strict) { if let Ok(str) = encdr.decode(&decoded_bytes, encoding::DecoderTrap::Strict) {
result.push_str(&str); result.push_str(&str);
} else { } else {
return Err(Exceptions::IllegalStateException("bad encoding".to_owned())); return Err(Exceptions::IllegalStateException("bad encoding".to_owned()));
@@ -404,11 +407,11 @@ fn correctBits(
} }
//try { //try {
let rsDecoder = ReedSolomonDecoder::new(gf); let rs_decoder = ReedSolomonDecoder::new(gf);
rsDecoder.decode( rs_decoder.decode(
&mut dataWords, &mut dataWords,
(numCodewords - numDataCodewords as usize) as i32, (numCodewords - numDataCodewords as usize) as i32,
); )?;
//} catch (ReedSolomonException ex) { //} catch (ReedSolomonException ex) {
//throw FormatException.getFormatInstance(ex); //throw FormatException.getFormatInstance(ex);
//} //}
@@ -531,9 +534,9 @@ fn extractBits(ddata: &AztecDetectorRXingResult, matrix: &BitMatrix) -> Vec<bool
/** /**
* Reads a code of given length and at given index in an array of bits * Reads a code of given length and at given index in an array of bits
*/ */
fn readCode(rawbits: &[bool], startIndex: usize, length: usize) -> u32 { fn readCode(rawbits: &[bool], start_index: usize, length: usize) -> u32 {
let mut res = 0; let mut res = 0;
for i in startIndex..length { for i in start_index..start_index+length {
// for (int i = startIndex; i < startIndex + length; i++) { // for (int i = startIndex; i < startIndex + length; i++) {
res <<= 1; res <<= 1;
if rawbits[i] { if rawbits[i] {
@@ -546,24 +549,24 @@ fn readCode(rawbits: &[bool], startIndex: usize, length: usize) -> u32 {
/** /**
* Reads a code of length 8 in an array of bits, padding with zeros * Reads a code of length 8 in an array of bits, padding with zeros
*/ */
fn readByte(rawbits: &[bool], startIndex: usize) -> u8 { fn readByte(rawbits: &[bool], start_index: usize) -> u8 {
let n = rawbits.len() - startIndex; let n = rawbits.len() - start_index;
if n >= 8 { if n >= 8 {
return readCode(rawbits, startIndex, 8) as u8; return readCode(rawbits, start_index, 8) as u8;
} }
return (readCode(rawbits, startIndex, n) << (8 - n)) as u8; return (readCode(rawbits, start_index, n) << (8 - n)) as u8;
} }
/** /**
* Packs a bit array into bytes, most significant bit first * Packs a bit array into bytes, most significant bit first
*/ */
pub fn convertBoolArrayToByteArray(boolArr: &[bool]) -> Vec<u8> { pub fn convertBoolArrayToByteArray(bool_arr: &[bool]) -> Vec<u8> {
let mut byteArr = vec![0u8; (boolArr.len() + 7) / 8]; let mut byte_arr = vec![0u8; (bool_arr.len() + 7) / 8];
for i in 0..byteArr.len() { for i in 0..byte_arr.len() {
// for (int i = 0; i < byteArr.length; i++) { // for (int i = 0; i < byteArr.length; i++) {
byteArr[i] = readByte(boolArr, 8 * i); byte_arr[i] = readByte(bool_arr, 8 * i);
} }
return byteArr; return byte_arr;
} }
fn totalBitsInLayer(layers: usize, compact: bool) -> usize { fn totalBitsInLayer(layers: usize, compact: bool) -> usize {