partially passing encoder

This commit is contained in:
Henry Schimke
2022-09-25 16:52:12 -05:00
parent fb08ee0e34
commit b2a460a226
10 changed files with 769 additions and 512 deletions

View File

@@ -34,6 +34,8 @@
// import java.util.Random; // import java.util.Random;
// import java.util.TreeSet; // import java.util.TreeSet;
use rand::Rng;
use crate::{aztec::decoder, common::BitMatrix, exceptions::Exceptions}; use crate::{aztec::decoder, common::BitMatrix, exceptions::Exceptions};
use super::{ use super::{
@@ -69,7 +71,7 @@ fn testErrorInParameterLocatorNotCompact() {
fn testErrorInParameterLocator(data: &str) { fn testErrorInParameterLocator(data: &str) {
let aztec = encoder::encoder::encode(data, 25, encoder::encoder::DEFAULT_AZTEC_LAYERS) let aztec = encoder::encoder::encode(data, 25, encoder::encoder::DEFAULT_AZTEC_LAYERS)
.expect("encode should create"); .expect("encode should create");
let random = rand::thread_rng(); //Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic let mut random = rand::thread_rng(); //Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
let layers = aztec.getLayers(); let layers = aztec.getLayers();
let compact = aztec.isCompact(); let compact = aztec.isCompact();
let orientationPoints = getOrientationPoints(&aztec); let orientationPoints = getOrientationPoints(&aztec);
@@ -78,24 +80,24 @@ fn testErrorInParameterLocator(data: &str) {
for matrix in getRotations(aztec.getMatrix()) { for matrix in getRotations(aztec.getMatrix()) {
// for (BitMatrix matrix : getRotations(aztec.getMatrix())) { // for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
// Systematically try every possible 1- and 2-bit error. // Systematically try every possible 1- and 2-bit error.
for error1 in 0..orientationPoints.size() { for error1 in 0..orientationPoints.len() {
// for (int error1 = 0; error1 < orientationPoints.size(); error1++) { // for (int error1 = 0; error1 < orientationPoints.size(); error1++) {
for error2 in error1..orientationPoints.size() { for error2 in error1..orientationPoints.len() {
// for (int error2 = error1; error2 < orientationPoints.size(); error2++) { // for (int error2 = error1; error2 < orientationPoints.size(); error2++) {
let copy = if isMirror { let mut copy = if isMirror {
transpose(&matrix) transpose(&matrix)
} else { } else {
clone(&matrix) clone(&matrix)
}; };
copy.flip( copy.flip_coords(
orientationPoints.get(error1).getX(), orientationPoints.get(error1).unwrap().getX() as u32,
orientationPoints.get(error1).getY(), orientationPoints.get(error1).unwrap().getY() as u32,
); );
if error2 > error1 { if error2 > error1 {
// if error2 == error1, we only test a single error // if error2 == error1, we only test a single error
copy.flip( copy.flip_coords(
orientationPoints.get(error2).getX(), orientationPoints.get(error2).unwrap().getX() as u32,
orientationPoints.get(error2).getY(), orientationPoints.get(error2).unwrap().getY() as u32,
); );
} }
// The detector doesn't seem to work when matrix bits are only 1x1. So magnify. // The detector doesn't seem to work when matrix bits are only 1x1. So magnify.
@@ -111,17 +113,17 @@ fn testErrorInParameterLocator(data: &str) {
// Try a few random three-bit errors; // Try a few random three-bit errors;
for i in 0..5 { for i in 0..5 {
// for (int i = 0; i < 5; i++) { // for (int i = 0; i < 5; i++) {
let copy = clone(&matrix); let mut copy = clone(&matrix);
let errors = Vec::new(); let mut errors = Vec::new();
while errors.size() < 3 { while errors.len() < 3 {
// Quick and dirty way of getting three distinct integers between 1 and n. // Quick and dirty way of getting three distinct integers between 1 and n.
errors.push(random.nextInt(orientationPoints.size())); errors.push(random.gen_range(0..=orientationPoints.len()));
} }
for error in errors { for error in errors {
// for (int error : errors) { // for (int error : errors) {
copy.flip( copy.flip_coords(
orientationPoints.get(error).getX(), orientationPoints.get(error).unwrap().getX() as u32,
orientationPoints.get(error).getY(), orientationPoints.get(error).unwrap().getY() as u32,
); );
} }
// try { // try {
@@ -147,7 +149,7 @@ fn testErrorInParameterLocator(data: &str) {
// Zooms a bit matrix so that each bit is factor x factor // Zooms a bit matrix so that each bit is factor x factor
fn makeLarger(input: &BitMatrix, factor: u32) -> BitMatrix { fn makeLarger(input: &BitMatrix, factor: u32) -> BitMatrix {
let width = input.getWidth(); let width = input.getWidth();
let output = BitMatrix::with_single_dimension(width * factor); let mut output = BitMatrix::with_single_dimension(width * factor);
for inputY in 0..width { for inputY in 0..width {
// for (int inputY = 0; inputY < width; inputY++) { // for (int inputY = 0; inputY < width; inputY++) {
for inputX in 0..width { for inputX in 0..width {
@@ -165,13 +167,13 @@ fn getRotations(matrix0: &BitMatrix) -> Vec<BitMatrix> {
let matrix90 = rotateRight(matrix0); let matrix90 = rotateRight(matrix0);
let matrix180 = rotateRight(&matrix90); let matrix180 = rotateRight(&matrix90);
let matrix270 = rotateRight(&matrix180); let matrix270 = rotateRight(&matrix180);
vec![*matrix0, matrix90, matrix180, matrix270] vec![matrix0.clone(), matrix90, matrix180, matrix270]
} }
// Rotates a square BitMatrix to the right by 90 degrees // Rotates a square BitMatrix to the right by 90 degrees
fn rotateRight(input: &BitMatrix) -> BitMatrix { fn rotateRight(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth(); let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width); let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width { for x in 0..width {
// for (int x = 0; x < width; x++) { // for (int x = 0; x < width; x++) {
for y in 0..width { for y in 0..width {
@@ -188,7 +190,7 @@ fn rotateRight(input: &BitMatrix) -> BitMatrix {
// matrix to the right, and then flipping it left-to-right // matrix to the right, and then flipping it left-to-right
fn transpose(input: &BitMatrix) -> BitMatrix { fn transpose(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth(); let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width); let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width { for x in 0..width {
// for (int x = 0; x < width; x++) { // for (int x = 0; x < width; x++) {
for y in 0..width { for y in 0..width {
@@ -203,7 +205,7 @@ fn transpose(input: &BitMatrix) -> BitMatrix {
fn clone(input: &BitMatrix) -> BitMatrix { fn clone(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth(); let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width); let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width { for x in 0..width {
// for (int x = 0; x < width; x++) { // for (int x = 0; x < width; x++) {
for y in 0..width { for y in 0..width {
@@ -217,21 +219,21 @@ fn clone(input: &BitMatrix) -> BitMatrix {
} }
fn getOrientationPoints(code: &AztecCode) -> Vec<Point> { fn getOrientationPoints(code: &AztecCode) -> Vec<Point> {
let center = code.getMatrix().getWidth() / 2; let center = code.getMatrix().getWidth() as i32 / 2;
let offset = if code.isCompact() { 5 } else { 7 }; let offset = if code.isCompact() { 5 } else { 7 };
let result = Vec::new(); let mut result = Vec::new();
let mut xSign = -1; let mut xSign: i32 = -1;
while xSign <= 1 { while xSign <= 1 {
// for (int xSign = -1; xSign <= 1; xSign += 2) { // for (int xSign = -1; xSign <= 1; xSign += 2) {
let mut ySign = -1; let mut ySign: i32 = -1;
while ySign <= 1 { while ySign <= 1 {
// for (int ySign = -1; ySign <= 1; ySign += 2) { // for (int ySign = -1; ySign <= 1; ySign += 2) {
result.add(Point::new(center + xSign * offset, center + ySign * offset)); result.push(Point::new(center + xSign * offset, center + ySign * offset));
result.add(Point::new( result.push(Point::new(
center + xSign * (offset - 1), center + xSign * (offset - 1),
center + ySign * offset, center + ySign * offset,
)); ));
result.add(Point::new( result.push(Point::new(
center + xSign * offset, center + xSign * offset,
center + ySign * (offset - 1), center + ySign * (offset - 1),
)); ));

View File

@@ -40,12 +40,25 @@ use std::collections::HashMap;
use encoding::EncodingRef; use encoding::EncodingRef;
use crate::{common::{BitArray, BitMatrix}, RXingResultPoint, BarcodeFormat, aztec::{encoder::HighLevelEncoder, decoder, shared_test_methods::{toBooleanArray, stripSpace, toBitArray}, AztecDetectorResult::AztecDetectorRXingResult}, EncodeHintType,EncodeHintValue}; use crate::{
aztec::{
decoder,
encoder::HighLevelEncoder,
shared_test_methods::{stripSpace, toBitArray, toBooleanArray},
AztecDetectorResult::AztecDetectorRXingResult,
},
common::{BitArray, BitMatrix},
BarcodeFormat, EncodeHintType, EncodeHintValue, RXingResultPoint,
};
use super::{AztecWriter, encoder::encoder}; use super::{encoder::encoder, AztecWriter};
use crate::Writer; use crate::Writer;
use rand::Rng;
use encoding::Encoding;
/** /**
* Aztec 2D generator unit tests. * Aztec 2D generator unit tests.
* *
@@ -53,33 +66,35 @@ use crate::Writer;
* @author Frank Yellin * @author Frank Yellin
*/ */
const ISO_8859_1:EncodingRef = encoding::all::ISO_8859_1;//StandardCharsets.ISO_8859_1; const ISO_8859_1: EncodingRef = encoding::all::ISO_8859_1; //StandardCharsets.ISO_8859_1;
const UTF_8 :EncodingRef= encoding::all::UTF_8; //StandardCharsets.UTF_8; const UTF_8: EncodingRef = encoding::all::UTF_8; //StandardCharsets.UTF_8;
const SHIFT_JIS:EncodingRef = encoding::label::encoding_from_whatwg_label("Shift_JIS").expect("must exist");//Charset.forName("Shift_JIS"); const ISO_8859_15: EncodingRef = encoding::all::ISO_8859_15; //Charset.forName("ISO-8859-15");
const ISO_8859_15:EncodingRef = encoding::all::ISO_8859_15;//Charset.forName("ISO-8859-15"); const WINDOWS_1252: EncodingRef = encoding::all::WINDOWS_1252; //Charset.forName("Windows-1252");
const WINDOWS_1252 :EncodingRef= encoding::all::WINDOWS_1252;//Charset.forName("Windows-1252");
const DOTX : &str = "[^.X]"; const DOTX: &str = "[^.X]";
const SPACES :&str= "\\s+"; const SPACES: &str = "\\s+";
const NO_POINTS:Vec<RXingResultPoint> = Vec::new(); const NO_POINTS: Vec<RXingResultPoint> = Vec::new();
// real life tests // real life tests
#[test] #[test]
fn testEncode1() { fn testEncode1() {
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3, testEncode(
"This is an example Aztec symbol for Wikipedia.",
true,
3,
r"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 X X X X X X
X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X
@@ -90,15 +105,18 @@ use crate::Writer;
X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X
X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X
"); " );
} }
#[test] #[test]
fn testEncode2() { fn testEncode2() {
testEncode(r"Aztec Code is a public domain 2D matrix barcode symbology testEncode(
r"Aztec Code is a public domain 2D matrix barcode symbology
of nominally square symbols built on a square grid with a of nominally square symbols built on a square grid with a
distinctive square bullseye pattern at their center.", false, 6, distinctive square bullseye pattern at their center.",
false,
6,
r" X 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 X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
@@ -140,11 +158,14 @@ distinctive square bullseye pattern at their center.", false, 6,
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X X X X
"); ",
} );
}
#[test]
fn testAztecWriter() { fn testAztecWriter() {
let shift_jis: EncodingRef =
encoding::label::encoding_from_whatwg_label("Shift_JIS").expect("must exist");
testWriter("Espa\u{00F1}ol", None, 25, true, 1); // Without ECI (implicit ISO-8859-1) testWriter("Espa\u{00F1}ol", None, 25, true, 1); // Without ECI (implicit ISO-8859-1)
testWriter("Espa\u{00F1}ol", Some(ISO_8859_1), 25, true, 1); // Explicit ISO-8859-1 testWriter("Espa\u{00F1}ol", Some(ISO_8859_1), 25, true, 1); // Explicit ISO-8859-1
testWriter("\u{20AC} 1 sample data.", Some(WINDOWS_1252), 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can testWriter("\u{20AC} 1 sample data.", Some(WINDOWS_1252), 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
@@ -153,58 +174,81 @@ distinctive square bullseye pattern at their center.", false, 6,
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 100, true, 3); testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 100, true, 3);
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 300, true, 4); testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 300, true, 4);
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 500, false, 5); testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 500, false, 5);
testWriter("The capital of Japan is named \u{6771}\u{4EAC}.", Some(SHIFT_JIS), 25, true, 3); testWriter(
"The capital of Japan is named \u{6771}\u{4EAC}.",
Some(shift_jis),
25,
true,
3,
);
// Test AztecWriter defaults // Test AztecWriter defaults
let data = "In ut magna vel mauris malesuada"; let data = "In ut magna vel mauris malesuada";
// let writer = AztecWriter{}; // let writer = AztecWriter{};
let matrix = AztecWriter::encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist"); let matrix = AztecWriter::encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist");
let aztec = encoder::encode(data, let aztec = encoder::encode(
encoder::DEFAULT_EC_PERCENT, encoder::DEFAULT_AZTEC_LAYERS).expect("encode should succeed"); data,
encoder::DEFAULT_EC_PERCENT,
encoder::DEFAULT_AZTEC_LAYERS,
)
.expect("encode should succeed");
let expectedMatrix = aztec.getMatrix(); let expectedMatrix = aztec.getMatrix();
assert_eq!(&matrix, expectedMatrix); assert_eq!(&matrix, expectedMatrix);
} }
// synthetic tests (encode-decode round-trip) // synthetic tests (encode-decode round-trip)
#[test] #[test]
fn testEncodeDecode1() { fn testEncodeDecode1() {
testEncodeDecode("Abc123!", true, 1); testEncodeDecode("Abc123!", true, 1);
} }
#[test] #[test]
fn testEncodeDecode2() { fn testEncodeDecode2() {
testEncodeDecode("Lorem ipsum. http://test/", true, 2); testEncodeDecode("Lorem ipsum. http://test/", true, 2);
} }
#[test] #[test]
fn testEncodeDecode3() { fn testEncodeDecode3() {
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3); testEncodeDecode(
} "AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN",
true,
3,
);
}
#[test] #[test]
fn testEncodeDecode4() { fn testEncodeDecode4() {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4); testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
} }
#[test] #[test]
fn testEncodeDecode5() { fn testEncodeDecode5() {
testEncodeDecode(r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc testEncodeDecode(
Four score and seven our forefathers brought forth"#, false, 5); r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc
} Four score and seven our forefathers brought forth"#,
false,
5,
);
}
#[test] #[test]
fn testEncodeDecode10() { fn testEncodeDecode10() {
testEncodeDecode(r"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam testEncodeDecode(
r"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id
elementum sapien dolor et diam.", false, 10); elementum sapien dolor et diam.",
} false,
10,
);
}
#[test] #[test]
fn testEncodeDecode23() { fn testEncodeDecode23() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam testEncodeDecode(
"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
@@ -225,12 +269,16 @@ Four score and seven our forefathers brought forth"#, false, 5);
sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet. sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.
Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit
felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo
erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23); erat pulvinar nisi, id elementum sapien dolor et diam.",
} false,
23,
);
}
#[test] #[test]
fn testEncodeDecode31() { fn testEncodeDecode31() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam testEncodeDecode(
"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
@@ -266,201 +314,271 @@ Four score and seven our forefathers brought forth"#, false, 5);
Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum
sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet. sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.
Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget
hendrerit felis turpis nec lorem.", false, 31); hendrerit felis turpis nec lorem.",
} false,
31,
);
}
#[test] #[test]
fn testGenerateModeMessage() { fn testGenerateModeMessage() {
testModeMessageComplex(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X"); testModeMessageComplex(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
testModeMessageComplex(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX.."); testModeMessageComplex(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
testModeMessageComplex(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX"); testModeMessageComplex(
testModeMessageComplex(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX"); false,
} 21,
660,
"X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX",
);
testModeMessageComplex(
false,
32,
4096,
"XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX",
);
}
#[test] #[test]
fn testStuffBitsTest() { fn testStuffBitsTest() {
testStuffBits(5, ".X.X. X.X.X .X.X.", testStuffBits(5, ".X.X. X.X.X .X.X.", ".X.X. X.X.X .X.X.");
".X.X. X.X.X .X.X."); testStuffBits(5, ".X.X. ..... .X.X", ".X.X. ....X ..X.X");
testStuffBits(5, ".X.X. ..... .X.X", testStuffBits(
".X.X. ....X ..X.X"); 3,
testStuffBits(3, "XX. ... ... ..X XXX .X. ..", "XX. ... ... ..X XXX .X. ..",
"XX. ..X ..X ..X ..X .XX XX. .X. ..X"); "XX. ..X ..X ..X ..X .XX XX. .X. ..X",
testStuffBits(6, ".X.X.. ...... ..X.XX", );
".X.X.. .....X. ..X.XX XXXX."); testStuffBits(6, ".X.X.. ...... ..X.XX", ".X.X.. .....X. ..X.XX XXXX.");
testStuffBits(6, ".X.X.. ...... ...... ..X.X.", testStuffBits(
".X.X.. .....X .....X ....X. X.XXXX"); 6,
testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX", ".X.X.. ...... ...... ..X.X.",
".X.X.. XXXXX. X..... ...X.X XXXXX."); ".X.X.. .....X .....X ....X. X.XXXX",
);
testStuffBits(
6,
".X.X.. XXXXXX ...... ..X.XX",
".X.X.. XXXXX. X..... ...X.X XXXXX.",
);
testStuffBits(6, testStuffBits(6,
"...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X", "...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X",
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX"); ".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
} }
#[test] #[test] // Adding a binary shift character that shouldn't be there.
fn testHighLevelEncode() { fn testHighLevelEncode() {
testHighLevelEncodeString("A. b.", testHighLevelEncodeString(
"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",
testHighLevelEncodeString("Lorem ipsum.", );
testHighLevelEncodeString(
"Lorem ipsum.",
// 'L' L/L 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' D/L '.' // 'L' L/L 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' D/L '.'
".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X"); ".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X",
);
testHighLevelEncodeString("Lo. Test 123.", testHighLevelEncodeString("Lo. Test 123.",
// 'L' L/L 'o' P/S '. ' U/S 'T' 'e' 's' 't' D/L ' ' '1' '2' '3' '.' // 'L' L/L 'o' P/S '. ' U/S 'T' 'e' 's' 't' D/L ' ' '1' '2' '3' '.'
".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X XXXX. ...X ..XX .X.. .X.X XX.X"); ".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X XXXX. ...X ..XX .X.. .X.X XX.X");
testHighLevelEncodeString("Lo...x", testHighLevelEncodeString(
"Lo...x",
// 'L' L/L 'o' D/L '.' '.' '.' U/L L/L 'x' // 'L' L/L 'o' D/L '.' '.' '.' U/L L/L 'x'
".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X"); ".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X",
);
testHighLevelEncodeString(". x://abc/.", testHighLevelEncodeString(". x://abc/.",
//P/S '. ' L/L 'x' P/S ':' P/S '/' P/S '/' 'a' 'b' 'c' P/S '/' D/L '.' //P/S '. ' L/L 'x' P/S ':' P/S '/' P/S '/' 'a' 'b' 'c' P/S '/' D/L '.'
"..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X"); "..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X");
// Uses Binary/Shift rather than Lower/Shift to save two bits. // Uses Binary/Shift rather than Lower/Shift to save two bits.
testHighLevelEncodeString("ABCdEFG", testHighLevelEncodeString(
"ABCdEFG",
//'A' 'B' 'C' B/S =1 'd' 'E' 'F' 'G' //'A' 'B' 'C' B/S =1 'd' 'E' 'F' 'G'
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X..."); "...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...",
);
testHighLevelEncodeStringCount( testHighLevelEncodeStringCount(
// Found on an airline boarding pass. Several stretches of Binary shift are // Found on an airline boarding pass. Several stretches of Binary shift are
// necessary to keep the bitcount so low. // necessary to keep the bitcount so low.
"09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEiYgh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=", "09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEiYgh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=",
823); 823);
} }
#[test] #[test]
fn testHighLevelEncodeBinary() { fn testHighLevelEncodeBinary() {
// binary short form single byte // binary short form single byte
testHighLevelEncodeString("N\0N", testHighLevelEncodeString(
"N\0N",
// 'N' B/S =1 '\0' N // 'N' B/S =1 '\0' N
".XXXX XXXXX ....X ........ .XXXX"); // Encode "N" in UPPER ".XXXX XXXXX ....X ........ .XXXX",
); // Encode "N" in UPPER
testHighLevelEncodeString("N\0n", testHighLevelEncodeString(
"N\0n",
// 'N' B/S =2 '\0' 'n' // 'N' B/S =2 '\0' 'n'
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY ".XXXX XXXXX ...X. ........ .XX.XXX.",
); // Encode "n" in BINARY
// binary short form consecutive bytes // binary short form consecutive bytes
testHighLevelEncodeString("N\0\u{0080} A", testHighLevelEncodeString(
"N\0\u{0080} A",
// 'N' B/S =2 '\0' \u0080 ' ' 'A' // 'N' B/S =2 '\0' \u0080 ' ' 'A'
".XXXX XXXXX ...X. ........ X....... ....X ...X."); ".XXXX XXXXX ...X. ........ X....... ....X ...X.",
);
// binary skipping over single character // binary skipping over single character
testHighLevelEncodeString("\0a\u{00FF}\u{0080} A", testHighLevelEncodeString(
"\0a\u{00FF}\u{0080} A",
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A' // B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X."); "XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.",
);
// getting into binary mode from digit mode // getting into binary mode from digit mode
testHighLevelEncodeString("1234\0", testHighLevelEncodeString(
"1234\0",
//D/L '1' '2' '3' '4' U/L B/S =1 \0 //D/L '1' '2' '3' '4' U/L B/S =1 \0
"XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........" "XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........",
); );
// Create a string in which every character requires binary // Create a string in which every character requires binary
let sb = String::new(); let mut sb = String::new();
for i in 0..3000 { for i in 0..3000 {
// for (int i = 0; i <= 3000; i++) { // for (int i = 0; i <= 3000; i++) {
sb.push(char::from_u32(128 + (i % 30)).unwrap()); sb.push(char::from_u32(128 + (i % 30)).unwrap());
} }
// Test the output generated by Binary/Switch, particularly near the // Test the output generated by Binary/Switch, particularly near the
// places where the encoding changes: 31, 62, and 2047+31=2078 // places where the encoding changes: 31, 62, and 2047+31=2078
for i in [1, 2, 3, 10, 29, 30, 31, 32, 33, for i in [
60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100]{ 1, 2, 3, 10, 29, 30, 31, 32, 33, 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100,
] {
// for (int i : new int[] { 1, 2, 3, 10, 29, 30, 31, 32, 33, // for (int i : new int[] { 1, 2, 3, 10, 29, 30, 31, 32, 33,
// 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100 }) { // 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100 }) {
// This is the expected length of a binary string of length "i" // This is the expected length of a binary string of length "i"
let expectedLength = (8 * i) + let expected_length = (8 * i)
if i <= 31 { 10 } else { if i <= 62 {20} else{if i <= 2078 {21} else {31}} }; + if i <= 31 {
10
} else {
if i <= 62 {
20
} else {
if i <= 2078 {
21
} else {
31
}
}
};
// ( (i <= 31) ? 10 : (i <= 62) ? 20 : (i <= 2078) ? 21 : 31); // ( (i <= 31) ? 10 : (i <= 62) ? 20 : (i <= 2078) ? 21 : 31);
// Verify that we are correct about the length. // Verify that we are correct about the length.
testHighLevelEncodeStringCount(&sb[..i], expectedLength as u32); let substring_for_test : String = sb.chars().take(i).collect();
testHighLevelEncodeStringCount(&substring_for_test, expected_length as u32);
if i != 1 && i != 32 && i != 2079 { if i != 1 && i != 32 && i != 2079 {
// The addition of an 'a' at the beginning or end gets merged into the binary code // The addition of an 'a' at the beginning or end gets merged into the binary code
// in those cases where adding another binary character only adds 8 or 9 bits to the result. // in those cases where adding another binary character only adds 8 or 9 bits to the result.
// So we exclude the border cases i=1,32,2079 // So we exclude the border cases i=1,32,2079
// A lower case letter at the beginning will be merged into binary mode // A lower case letter at the beginning will be merged into binary mode
testHighLevelEncodeStringCount(&format!("a{}" , &sb[.. i - 1]), expectedLength as u32); let substring_for_sub_test : String = sb.chars().take(i-1).collect();
testHighLevelEncodeStringCount(&format!("a{}", &substring_for_sub_test), expected_length as u32);
// A lower case letter at the end will also be merged into binary mode // A lower case letter at the end will also be merged into binary mode
testHighLevelEncodeStringCount(&format!("{}a",&sb[..i - 1]), expectedLength as u32); testHighLevelEncodeStringCount(&format!("{}a", &substring_for_sub_test), expected_length as u32);
} }
// A lower case letter at both ends will enough to latch us into LOWER. // A lower case letter at both ends will enough to latch us into LOWER.
testHighLevelEncodeStringCount(&format!("a{}b",&sb[..i] ), expectedLength as u32+ 15); testHighLevelEncodeStringCount(&format!("a{}b", &substring_for_test), expected_length as u32 + 15);
} }
sb.clear(); sb.clear();
for i in 0..32 {
sb.push('A');
for _i in 0..31 {
// for (int i = 0; i < 32; i++) { // for (int i = 0; i < 32; i++) {
sb.push('§'); // § forces binary encoding sb.push('§'); // § forces binary encoding
} }
sb.replace_range(1..2, "A"); // sb.replace_range(sb.char_indices().nth(1).map(|(pos, ch)| pos..pos+ch.len_utf8()).unwrap(), "A");
// sb.setCharAt(1, 'A'); // sb.setCharAt(1, 'A');
// expect B/S(1) A B/S(30) // expect B/S(1) A B/S(30)
testHighLevelEncodeStringCount(&sb, 5 + 20 + 31 * 8); testHighLevelEncodeStringCount(&sb, 5 + 20 + 31 * 8);
sb.clear(); sb.clear();
for i in 0..31 {
sb.push('A');
for _i in 0..30 {
// for (int i = 0; i < 31; i++) { // for (int i = 0; i < 31; i++) {
sb.push('§'); sb.push('§');
} }
sb.replace_range(1..2, "A"); // sb.replace_range(1..2, "A");
// sb.setCharAt(1, 'A'); // sb.setCharAt(1, 'A');
// expect B/S(31) // expect B/S(31)
testHighLevelEncodeStringCount(&sb, 10 + 31 * 8); testHighLevelEncodeStringCount(&sb, 10 + 31 * 8);
sb.clear(); sb.clear();
for i in 0..34 {
sb.push('A');
for _i in 0..33 {
// for (int i = 0; i < 34; i++) { // for (int i = 0; i < 34; i++) {
sb.push('§'); sb.push('§');
} }
sb.replace_range(1..2, "A"); //sb.replace_range(1..2, "A");
// sb.setCharAt(1, 'A'); // sb.setCharAt(1, 'A');
// expect B/S(31) B/S(3) // expect B/S(31) B/S(3)
testHighLevelEncodeStringCount(&sb, 20 + 34 * 8); testHighLevelEncodeStringCount(&sb, 20 + 34 * 8);
sb.clear(); sb.clear();
for i in 0..64 { for _i in 0..30 {
// for (int i = 0; i < 64; i++) { // for (int i = 0; i < 64; i++) {
sb.push('§'); sb.push('§');
} }
sb.replace_range(30..31, "A"); sb.push('A');
for _i in 31..64 {
// for (int i = 0; i < 64; i++) {
sb.push('§');
}
//sb.replace_range(30..31, "A");
// sb.setCharAt(30, 'A'); // sb.setCharAt(30, 'A');
// expect B/S(64) // expect B/S(64)
testHighLevelEncodeStringCount(&sb, 21 + 64 * 8); testHighLevelEncodeStringCount(&sb, 21 + 64 * 8);
} }
#[test] #[test]
fn testHighLevelEncodePairs() { fn testHighLevelEncodePairs() {
// Typical usage // Typical usage
testHighLevelEncodeString("ABC. DEF\r\n", testHighLevelEncodeString(
"ABC. DEF\r\n",
// A B C P/S .<sp> D E F P/S \r\n // A B C P/S .<sp> D E F P/S \r\n
"...X. ...XX ..X.. ..... ...XX ..X.X ..XX. ..XXX ..... ...X."); "...X. ...XX ..X.. ..... ...XX ..X.X ..XX. ..XXX ..... ...X.",
);
// We should latch to PUNCT mode, rather than shift. Also check all pairs // We should latch to PUNCT mode, rather than shift. Also check all pairs
testHighLevelEncodeString("A. : , \r\n", testHighLevelEncodeString(
"A. : , \r\n",
// 'A' M/L P/L ". " ": " ", " "\r\n" // 'A' M/L P/L ". " ": " ", " "\r\n"
"...X. XXX.X XXXX. ...XX ..X.X ..X.. ...X."); "...X. XXX.X XXXX. ...XX ..X.X ..X.. ...X.",
);
// Latch to DIGIT rather than shift to PUNCT // Latch to DIGIT rather than shift to PUNCT
testHighLevelEncodeString("A. 1234", testHighLevelEncodeString(
"A. 1234",
// 'A' D/L '.' ' ' '1' '2' '3' '4' // 'A' D/L '.' ' ' '1' '2' '3' '4'
"...X. XXXX. XX.X ...X ..XX .X.. .X.X .X X."); "...X. XXXX. XX.X ...X ..XX .X.. .X.X .X X.",
);
// Don't bother leaving Binary Shift. // Don't bother leaving Binary Shift.
testHighLevelEncodeString("A\u{200}. \u{200}", testHighLevelEncodeString(
"A\u{80}. \u{80}",
// 'A' B/S =2 \200 "." " " \200 // 'A' B/S =2 \200 "." " " \200
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X......."); "...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......",
} );
}
#[test] #[test]
#[should_panic] #[should_panic]
fn testUserSpecifiedLayers() { fn testUserSpecifiedLayers() {
doTestUserSpecifiedLayers(33); doTestUserSpecifiedLayers(33);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn testUserSpecifiedLayers2() { fn testUserSpecifiedLayers2() {
doTestUserSpecifiedLayers(1); doTestUserSpecifiedLayers(1);
} }
fn doTestUserSpecifiedLayers( userSpecifiedLayers:usize) { fn doTestUserSpecifiedLayers(userSpecifiedLayers: usize) {
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let aztec = encoder::encode(alphabet, 25, 2).expect("should encode"); let mut aztec = encoder::encode(alphabet, 25, 2).expect("should encode");
assert_eq!(2, aztec.getLayers()); assert_eq!(2, aztec.getLayers());
assert!(aztec.isCompact()); assert!(aztec.isCompact());
@@ -468,147 +586,250 @@ Four score and seven our forefathers brought forth"#, false, 5);
assert_eq!(32, aztec.getLayers()); assert_eq!(32, aztec.getLayers());
assert!(!aztec.isCompact()); assert!(!aztec.isCompact());
encoder::encode(alphabet, 25, userSpecifiedLayers as u32); encoder::encode(alphabet, 25, userSpecifiedLayers as u32).expect("encode");
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn testBorderCompact4CaseFailed() { fn testBorderCompact4CaseFailed() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must // Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction // be error correction
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// encodes as 26 * 5 * 4 = 520 bits of data // encodes as 26 * 5 * 4 = 520 bits of data
let alphabet4 = format!("{}{}{}{}",alphabet , alphabet, alphabet , alphabet); let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
encoder::encode(&alphabet4, 0, 4); encoder::encode(&alphabet4, 0, 4).expect("encode");
} }
#[test] #[test]
fn testBorderCompact4Case() { fn testBorderCompact4Case() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must // Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction // be error correction
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// encodes as 26 * 5 * 4 = 520 bits of data // encodes as 26 * 5 * 4 = 520 bits of data
let alphabet4 = format!("{}{}{}{}",alphabet , alphabet, alphabet , alphabet); let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
// If we just try to encode it normally, it will go to a non-compact 4 layer // If we just try to encode it normally, it will go to a non-compact 4 layer
let aztecCode = encoder::encode(&alphabet4, 0, encoder::DEFAULT_AZTEC_LAYERS).expect("Should encode"); let mut aztecCode =
encoder::encode(&alphabet4, 0, encoder::DEFAULT_AZTEC_LAYERS).expect("Should encode");
assert!(!aztecCode.isCompact()); assert!(!aztecCode.isCompact());
assert_eq!(4, aztecCode.getLayers()); assert_eq!(4, aztecCode.getLayers());
// But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we // But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we
// include more error checking. // include more error checking.
aztecCode = encoder::encode(&alphabet4[..100], 10, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode"); aztecCode = encoder::encode(&alphabet4[..100], 10, encoder::DEFAULT_AZTEC_LAYERS)
.expect("should encode");
assert!(aztecCode.isCompact()); assert!(aztecCode.isCompact());
assert_eq!(4, aztecCode.getLayers()); assert_eq!(4, aztecCode.getLayers());
} }
// Helper routines // Helper routines
fn testEncode( data:&str, compact:bool, layers:u32, expected:&str) { fn testEncode(data: &str, compact: bool, layers: u32, expected: &str) {
let aztec = encoder::encode(data, 33, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode"); let aztec = encoder::encode(data, 33, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)"); assert_eq!(
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers"); compact,
aztec.isCompact(),
"Unexpected symbol format (compact)"
);
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let matrix = aztec.getMatrix(); let matrix = aztec.getMatrix();
assert_eq!( expected, matrix.to_string(),"encode() failed"); assert_eq!(expected, matrix.to_string(), "encode({}) failed", data);
let z: BitMatrix; }
}
fn testEncodeDecode( data:&str, compact:bool, layers:u32) { fn testEncodeDecode(data: &str, compact: bool, layers: u32) {
let aztec = encoder::encode(data, 25, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode"); let aztec = encoder::encode(data, 25, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)"); assert_eq!(
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers"); compact,
let mut matrix = aztec.getMatrix(); aztec.isCompact(),
let r = "Unexpected symbol format (compact)"
AztecDetectorRXingResult::new(matrix.clone(), NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers()); );
let res = decoder::decode(&r).expect("decode ok"); assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let mut matrix = aztec.getMatrix().clone();
let mut r = AztecDetectorRXingResult::new(
matrix.clone(),
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
let mut res = decoder::decode(&r).expect("decode ok");
assert_eq!(data, res.getText()); assert_eq!(data, res.getText());
// Check error correction by introducing a few minor errors // Check error correction by introducing a few minor errors
let random = getPseudoRandom(); let mut random = getPseudoRandom();
matrix.flip(random.nextInt(matrix.getWidth()), random.nextInt(2)); matrix.flip_coords(
matrix.flip(random.nextInt(matrix.getWidth()), matrix.getHeight() - 2 + random.nextInt(2)); random.gen_range(0..matrix.getWidth()),
matrix.flip(random.nextInt(2), random.nextInt(matrix.getHeight())); random.gen_range(0..=2),
matrix.flip(matrix.getWidth() - 2 + random.nextInt(2), random.nextInt(matrix.getHeight())); );
r = AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers()); matrix.flip_coords(
res = decoder::decode(r); random.gen_range(0..matrix.getWidth()),
matrix.getHeight() - 2 + random.gen_range(0..2),
);
matrix.flip_coords(
random.gen_range(0..=2),
random.gen_range(0..matrix.getHeight()),
);
matrix.flip_coords(
matrix.getWidth() - 2 + random.gen_range(0..2),
random.gen_range(0..matrix.getHeight()),
);
r = AztecDetectorRXingResult::new(
matrix,
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
res = decoder::decode(&r).expect("decode should work");
assert_eq!(data, res.getText()); assert_eq!(data, res.getText());
} }
fn testWriter( data:&str, fn testWriter(
charset:Option<EncodingRef>, data: &str,
eccPercent:u32, charset: Option<EncodingRef>,
compact:bool, eccPercent: u32,
layers:u32) { compact: bool,
layers: u32,
) {
// Perform an encode-decode round-trip because it can be lossy. // Perform an encode-decode round-trip because it can be lossy.
let hints = HashMap::new(); let mut hints = HashMap::new();
if charset.is_some() { if charset.is_some() {
hints.insert(EncodingHintType::CHARACTER_SET, EncodingHintValue::CharacterSet(charset.unwrap().name())); hints.insert(
EncodeHintType::CHARACTER_SET,
EncodeHintValue::CharacterSet(charset.unwrap().name().to_owned()),
);
} }
// if (null != charset) { // if (null != charset) {
// hints.put(EncodeHintType.CHARACTER_SET, charset.name()); // hints.put(EncodeHintType.CHARACTER_SET, charset.name());
// } // }
hints.insert(EncodeHintType::ERROR_CORRECTION, eccPercent); hints.insert(
let writer = AztecWriter{}; EncodeHintType::ERROR_CORRECTION,
let matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints).expect("encoder created"); EncodeHintValue::ErrorCorrection(eccPercent.to_string()),
let aztec = encoder::encode_with_charset(data, eccPercent, );
encoder::DEFAULT_AZTEC_LAYERS, charset.unwrap()).expect("encode should encode"); let writer = AztecWriter {};
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)"); let mut matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints)
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers"); .expect("encoder created");
let aztec = encoder::encode_with_charset(
data,
eccPercent,
encoder::DEFAULT_AZTEC_LAYERS,
charset.unwrap(),
)
.expect("encode should encode");
assert_eq!(
compact,
aztec.isCompact(),
"Unexpected symbol format (compact)"
);
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let matrix2 = aztec.getMatrix(); let matrix2 = aztec.getMatrix();
assert_eq!(&matrix, matrix2); assert_eq!(&matrix, matrix2);
let r = let mut r = AztecDetectorRXingResult::new(
AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers()); matrix.clone(),
let res = decoder::decode(&r); NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
let mut res = decoder::decode(&r).expect("should decode");
assert_eq!(data, res.getText()); assert_eq!(data, res.getText());
// Check error correction by introducing up to eccPercent/2 errors // Check error correction by introducing up to eccPercent/2 errors
let ecWords = aztec.getCodeWords() * eccPercent / 100 / 2; let ecWords = aztec.getCodeWords() * eccPercent / 100 / 2;
let random = getPseudoRandom(); let mut random = getPseudoRandom();
for i in 0 ..ecWords { for _i in 0..ecWords {
// for (int i = 0; i < ecWords; i++) { // for (int i = 0; i < ecWords; i++) {
// don't touch the core // don't touch the core
let x = if random.nextBoolean() let x = if random.gen_bool(50.0) {
{random.nextInt(aztec.getLayers() * 2)} random.gen_range(0..=aztec.getLayers() * 2)
else {matrix.getWidth() - 1 - random.nextInt(aztec.getLayers() * 2)}; } else {
let y = if random.nextBoolean() matrix.getWidth() - 1 - random.gen_range(0..=aztec.getLayers() * 2)
{random.nextInt(aztec.getLayers() * 2)} };
else {matrix.getHeight() - 1 - random.nextInt(aztec.getLayers() * 2)}; let y = if random.gen_bool(50.0) {
matrix.flip(x, y); random.gen_range(0..=aztec.getLayers() * 2)
} else {
matrix.getHeight() - 1 - random.gen_range(0..=aztec.getLayers() * 2)
};
matrix.flip_coords(x, y);
} }
r = AztecDetectorRXingResult::nwq(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers()); r = AztecDetectorRXingResult::new(
res = decoder::decode(r); matrix,
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
res = decoder::decode(&r).expect("must decode");
assert_eq!(data, res.getText()); assert_eq!(data, res.getText());
} }
fn getPseudoRandom() -> rand::rngs::ThreadRng{ fn getPseudoRandom() -> rand::rngs::ThreadRng {
rand::thread_rng() rand::thread_rng()
} }
fn testModeMessageComplex( compact:bool, layers:u32, words:usize, expected:&str) { fn testModeMessageComplex(compact: bool, layers: u32, words: u32, expected: &str) {
let indata = encoder::generateModeMessage(compact, layers, words); let indata = encoder::generateModeMessage(compact, layers, words);
assert_eq!( stripSpace(expected), stripSpace(indata.toString()),"generateModeMessage() failed"); assert_eq!(
} stripSpace(expected),
stripSpace(&indata.to_string()),
"generateModeMessage() failed"
);
}
fn testStuffBits( wordSize:usize, bits:&str, expected:&str) { fn testStuffBits(wordSize: usize, bits: &str, expected: &str) {
let indata = toBitArray(bits); let indata = toBitArray(bits);
let stuffed = encoder::stuffBits(&indata, wordSize); let stuffed = encoder::stuffBits(&indata, wordSize);
assert_eq!( assert_eq!(
stripSpace(expected), stripSpace(stuffed.toString()), stripSpace(expected),
"stuffBits() failed for input string: {}" , bits); stripSpace(&stuffed.to_string()),
} "stuffBits() failed for input string: {}",
bits
);
}
fn testHighLevelEncodeString(s: &str, expectedBits: &str) {
let bits = HighLevelEncoder::new(
fn testHighLevelEncodeString( s:&str, expectedBits:&str) { encoding::all::ISO_8859_1
let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode(); .encode(s, encoding::EncoderTrap::Strict)
let receivedBits = stripSpace(bits.toString()); .expect("should encode to bytes"),
assert_eq!( stripSpace(expectedBits), receivedBits,"highLevelEncode() failed for input string: {}" , s); )
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits))); .encode()
} .expect("high level ok");
// let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
fn testHighLevelEncodeStringCount( s:&str, expectedReceivedBits:u32) { let receivedBits = stripSpace(&bits.to_string());
let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode().unwrap();
let receivedBitCount = stripSpace(bits.toString()).len();
assert_eq!( assert_eq!(
stripSpace(expectedBits),
receivedBits,
"highLevelEncode() failed for input string: {}",
s
);
assert_eq!(
s,
decoder::highLevelDecode(&toBooleanArray(&bits)).expect("must decode")
);
}
fn testHighLevelEncodeStringCount(s: &str, expectedReceivedBits: u32) {
let bits = HighLevelEncoder::new(
encoding::all::ISO_8859_1
.encode(s, encoding::EncoderTrap::Strict)
.expect("should encode to bytes"),
)
.encode()
.expect("high level ok");
//let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode().unwrap();
let receivedBitCount = stripSpace(&bits.to_string()).len();
assert_eq!(
s,
decoder::highLevelDecode(&toBooleanArray(&bits)).expect("should decode")
);
assert!(
expectedReceivedBits as usize >= receivedBitCount,
"encode size too high ({} >= {}) failed for input string: {}",
expectedReceivedBits, receivedBitCount, expectedReceivedBits, receivedBitCount,
"highLevelEncode() failed for input string: {}" , s); s
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits))); );
} // assert_eq!(
// expectedReceivedBits as usize, receivedBitCount,
// "highLevelEncode() failed for input string: {}",
// s
// );
}

View File

@@ -20,37 +20,37 @@ use crate::common::BitArray;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct BinaryShiftToken { pub struct BinaryShiftToken {
binaryShiftStart: u32, binary_shift_start: u32,
binaryShiftByteCount: u32, binary_shift_byte_count: u32,
} }
impl BinaryShiftToken { impl BinaryShiftToken {
pub fn new(binaryShiftStart: u32, binaryShiftByteCount: u32) -> Self { pub fn new(binary_shift_start: u32, binary_shift_byte_count: u32) -> Self {
Self { Self {
binaryShiftStart, binary_shift_start,
binaryShiftByteCount, binary_shift_byte_count,
} }
} }
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) { pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
let bsbc = self.binaryShiftByteCount as usize; let bsbc = self.binary_shift_byte_count as usize;
for i in 0..bsbc { for i in 0..bsbc {
// for (int i = 0; i < bsbc; i++) { // for (int i = 0; i < bsbc; i++) {
if (i == 0 || (i == 31 && bsbc <= 62)) { if i == 0 || (i == 31 && bsbc <= 62) {
// We need a header before the first character, and before // We need a header before the first character, and before
// character 31 when the total byte code is <= 62 // character 31 when the total byte code is <= 62
bitArray.appendBits(31, 5); // BINARY_SHIFT bit_array.appendBits(31, 5).unwrap(); // BINARY_SHIFT
if (bsbc > 62) { if bsbc > 62 {
bitArray.appendBits(bsbc as u32 - 31, 16); bit_array.appendBits(bsbc as u32 - 31, 16).unwrap();
} else if (i == 0) { } else if i == 0 {
// 1 <= binaryShiftByteCode <= 62 // 1 <= binaryShiftByteCode <= 62
bitArray.appendBits(bsbc.min(31) as u32, 5); bit_array.appendBits(bsbc.min(31) as u32, 5).unwrap();
} else { } else {
// 32 <= binaryShiftCount <= 62 and i == 31 // 32 <= binaryShiftCount <= 62 and i == 31
bitArray.appendBits(bsbc as u32 - 31, 5); bit_array.appendBits(bsbc as u32 - 31, 5).unwrap();
} }
} }
bitArray.appendBits(text[self.binaryShiftStart as usize + i].into(), 8); bit_array.appendBits(text[self.binary_shift_start as usize + i].into(), 8).expect("should never fail to append");
} }
} }
@@ -65,8 +65,8 @@ impl fmt::Display for BinaryShiftToken {
write!( write!(
f, f,
"<{}::{}>", "<{}::{}>",
self.binaryShiftStart, self.binary_shift_start,
(self.binaryShiftStart + self.binaryShiftByteCount - 1) (self.binary_shift_start + self.binary_shift_byte_count - 1)
) )
} }
} }

View File

@@ -72,8 +72,8 @@ pub fn encode(
userSpecifiedLayers: u32, userSpecifiedLayers: u32,
) -> Result<AztecCode, Exceptions> { ) -> Result<AztecCode, Exceptions> {
let bytes = encoding::all::ISO_8859_1 let bytes = encoding::all::ISO_8859_1
.encode(data, encoding::EncoderTrap::Replace) .encode(data, encoding::EncoderTrap::Strict)
.unwrap(); .expect("must encode cleanly in ISO_8859_1");
encode_bytes(&bytes, minECCPercent, userSpecifiedLayers) encode_bytes(&bytes, minECCPercent, userSpecifiedLayers)
} }
@@ -209,6 +209,7 @@ pub fn encode_bytes_with_charset(
layers = if compact { i + 1 } else { i }; layers = if compact { i + 1 } else { i };
totalBitsInLayerVar = totalBitsInLayer(layers, compact); totalBitsInLayerVar = totalBitsInLayer(layers, compact);
if totalSizeBits > totalBitsInLayerVar as u32 { if totalSizeBits > totalBitsInLayerVar as u32 {
i += 1;
continue; continue;
} }
// [Re]stuff the bits if this is the first opportunity, or if the // [Re]stuff the bits if this is the first opportunity, or if the
@@ -220,6 +221,7 @@ pub fn encode_bytes_with_charset(
let usableBitsInLayers = totalBitsInLayerVar - (totalBitsInLayerVar % wordSize); let usableBitsInLayers = totalBitsInLayerVar - (totalBitsInLayerVar % wordSize);
if compact && stuffedBits.getSize() as u32 > wordSize * 64 { if compact && stuffedBits.getSize() as u32 > wordSize * 64 {
// Compact format only allows 64 data words, though C4 can hold more words than that // Compact format only allows 64 data words, though C4 can hold more words than that
i += 1;
continue; continue;
} }
if stuffedBits.getSize()as u32 + eccBits<= usableBitsInLayers { if stuffedBits.getSize()as u32 + eccBits<= usableBitsInLayers {
@@ -487,32 +489,32 @@ fn getGF(wordSize: usize) -> Result<GenericGF, Exceptions> {
// } // }
} }
pub fn stuffBits(bits: &BitArray, wordSize: usize) -> BitArray { pub fn stuffBits(bits: &BitArray, word_size: usize) -> BitArray {
let mut out = BitArray::new(); let mut out = BitArray::new();
let n = bits.getSize(); let n = bits.getSize() as isize;
let mask = (1 << wordSize) - 2; let mask = (1 << word_size) - 2;
let mut i = 0; let mut i:isize = 0;
while i < n { while i < n {
// for (int i = 0; i < n; i += wordSize) { // for (int i = 0; i < n; i += wordSize) {
let mut word = 0; let mut word = 0;
for j in 0..wordSize { for j in 0..word_size as isize {
// for (int j = 0; j < wordSize; j++) { // for (int j = 0; j < wordSize; j++) {
if i + j >= n || bits.get(i + j) { if i + j >= n || bits.get((i + j) as usize) {
word |= 1 << (wordSize - 1 - j); word |= 1 << (word_size as isize - 1 - j);
} }
} }
if (word & mask) == mask { if (word & mask) == mask {
out.appendBits(word & mask, wordSize); out.appendBits(word & mask, word_size).unwrap();
i -= 1; i -= 1;
} else if (word & mask) == 0 { } else if (word & mask) == 0 {
out.appendBits(word | 1, wordSize); out.appendBits(word | 1, word_size).unwrap();
i -= 1; i -= 1;
} else { } else {
out.appendBits(word, wordSize); out.appendBits(word, word_size).unwrap();
} }
i += wordSize; i += word_size as isize;
} }
return out; return out;
} }

View File

@@ -125,27 +125,28 @@ impl HighLevelEncoder {
// } // }
char_map[Self::MODE_DIGIT][b',' as usize] = 12; char_map[Self::MODE_DIGIT][b',' as usize] = 12;
char_map[Self::MODE_DIGIT][b'.' as usize] = 13; char_map[Self::MODE_DIGIT][b'.' as usize] = 13;
let mixedTable = [ let mixed_table = [
'\0', ' ', '\u{1}', '\u{2}', '\u{3}', '\u{4}', '\u{5}', '\u{6}', '\u{7}', '\u{8}', '\0', ' ', '\u{1}', '\u{2}', '\u{3}', '\u{4}', '\u{5}', '\u{6}', '\u{7}', '\u{8}',
'\t', '\n', '\u{13}', '\u{f}', '\r', '\u{33}', '\u{34}', '\u{35}', '\u{36}', '\u{37}', '\t', '\n', '\u{13}', '\u{f}', '\r', '\u{33}', '\u{34}', '\u{35}', '\u{36}', '\u{37}',
'@', '\\', '^', '_', '`', '|', '~', '\u{177}', '@', '\\', '^', '_', '`', '|', '~', '\u{177}',
]; ];
let mut i = 0; let mut i = 0;
while i < mixedTable.len() { while i < mixed_table.len() {
char_map[Self::MODE_MIXED][mixedTable[i] as u8 as usize] = i as u8; char_map[Self::MODE_MIXED][mixed_table[i] as u8 as usize] = i as u8;
i += 1; i += 1;
} }
// for (int i = 0; i < mixedTable.length; i++) { // for (int i = 0; i < mixedTable.length; i++) {
// CHAR_MAP[MODE_MIXED][mixedTable[i]] = i; // CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
// } // }
let punctTable = [ let punctTable = [
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', b'\0', b'\r', b'\0', b'\0', b'\0', b'\0', b'!', b'\'', b'#', b'$', b'%', b'&', b'\'',
'+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}', b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?',
b'[', b']', b'{', b'}',
]; ];
let mut i = 0; let mut i = 0;
while i < punctTable.len() { while i < punctTable.len() {
if punctTable[i] as u8 > 0u8 { if punctTable[i] > 0u8 {
char_map[Self::MODE_PUNCT][punctTable[i] as u8 as usize] = i as u8; char_map[Self::MODE_PUNCT][punctTable[i] as usize] = i as u8;
} }
i += 1; i += 1;
} }
@@ -230,7 +231,7 @@ impl HighLevelEncoder {
pub fn new(text: Vec<u8>) -> Self { pub fn new(text: Vec<u8>) -> Self {
Self { Self {
text, text,
charset: encoding::all::UTF_8, charset: encoding::all::ISO_8859_1,
} }
} }
@@ -242,9 +243,11 @@ impl HighLevelEncoder {
* @return text represented by this encoder encoded as a {@link BitArray} * @return text represented by this encoder encoded as a {@link BitArray}
*/ */
pub fn encode(&self) -> Result<BitArray, Exceptions> { pub fn encode(&self) -> Result<BitArray, Exceptions> {
let mut initialState = State::new(Token::new(), Self::MODE_UPPER as u32, 0, 0); let mut initial_state = State::new(Token::new(), Self::MODE_UPPER as u32, 0, 0);
if let Some(eci) = CharacterSetECI::getCharacterSetECI(self.charset) { if let Some(eci) = CharacterSetECI::getCharacterSetECI(self.charset) {
initialState = initialState.appendFLGn(CharacterSetECI::getValue(&eci))?; if eci != CharacterSetECI::ISO8859_1 {
initial_state = initial_state.appendFLGn(CharacterSetECI::getValue(&eci))?;
}
} else { } else {
return Err(Exceptions::IllegalArgumentException( return Err(Exceptions::IllegalArgumentException(
"No ECI code for character set".to_owned(), "No ECI code for character set".to_owned(),
@@ -257,22 +260,22 @@ impl HighLevelEncoder {
// } // }
// initialState = initialState.appendFLGn(eci.getValue()); // initialState = initialState.appendFLGn(eci.getValue());
// } // }
let mut states = vec![initialState]; let mut states = vec![initial_state];
let mut index = 0; let mut index = 0;
while index < self.text.len() { while index < self.text.len() {
// for index in 0..self.text.len() { // for index in 0..self.text.len() {
// for (int index = 0; index < text.length; index++) { // for (int index = 0; index < text.length; index++) {
let pairCode; let pair_code;
let nextChar = if index + 1 < self.text.len() { let next_char = if index + 1 < self.text.len() {
self.text[index + 1] self.text[index + 1]
} else { } else {
0 0
}; };
pairCode = match self.text[index] { pair_code = match self.text[index] {
b'\r' if nextChar == b'\n' => 2, b'\r' if next_char == b'\n' => 2,
b'.' if nextChar == b' ' => 3, b'.' if next_char == b' ' => 3,
b',' if nextChar == b' ' => 4, b',' if next_char == b' ' => 4,
b':' if nextChar == b' ' => 5, b':' if next_char == b' ' => 5,
_ => 0, _ => 0,
}; };
// switch (text[index]) { // switch (text[index]) {
@@ -291,19 +294,24 @@ impl HighLevelEncoder {
// default: // default:
// pairCode = 0; // pairCode = 0;
// } // }
if pairCode > 0 { if pair_code > 0 {
// We have one of the four special PUNCT pairs. Treat them specially. // We have one of the four special PUNCT pairs. Treat them specially.
// Get a new set of states for the two new characters. // Get a new set of states for the two new characters.
states = Self::updateStateListForPair(states, index as u32, pairCode); states = Self::update_state_list_for_pair(states, index as u32, pair_code);
index += 1; index += 1;
} else { } else {
// Get a new set of states for the new character. // Get a new set of states for the new character.
states = self.updateStateListForChar(states, index as u32); states = self.update_state_list_for_char(states, index as u32);
} }
index += 1; index += 1;
} }
// for state in &states {
// dbg!(state.clone().toBitArray(&self.text).to_string());
// }
// We are left with a set of states. Find the shortest one. // We are left with a set of states. Find the shortest one.
let minState = states let min_state = states
.into_iter() .into_iter()
.min_by(|a, b| { .min_by(|a, b| {
let diff: i64 = a.getBitCount() as i64 - b.getBitCount() as i64; let diff: i64 = a.getBitCount() as i64 - b.getBitCount() as i64;
@@ -324,58 +332,61 @@ impl HighLevelEncoder {
// } // }
// }); // });
// Convert it to a bit array, and return. // Convert it to a bit array, and return.
Ok(minState.toBitArray(&self.text)) Ok(min_state.toBitArray(&self.text))
} }
// We update a set of states for a new character by updating each state // We update a set of states for a new character by updating each state
// for the new character, merging the results, and then removing the // for the new character, merging the results, and then removing the
// non-optimal states. // non-optimal states.
fn updateStateListForChar(&self, states: Vec<State>, index: u32) -> Vec<State> { fn update_state_list_for_char(&self, states: Vec<State>, index: u32) -> Vec<State> {
let mut result = Vec::new(); let mut result = Vec::new();
for state in states { for state in states {
// for (State state : states) { // for (State state : states) {
self.updateStateForChar(state, index, &mut result); self.update_state_for_char(state, index, &mut result);
} }
Self::simplifyStates(result) Self::simplify_states(result)
} }
// Return a set of states that represent the possible ways of updating this // Return a set of states that represent the possible ways of updating this
// state for the next character. The resulting set of states are added to // state for the next character. The resulting set of states are added to
// the "result" list. // the "result" list.
fn updateStateForChar(&self, state: State, index: u32, result: &mut Vec<State>) { fn update_state_for_char(&self, state: State, index: u32, result: &mut Vec<State>) {
let ch = self.text[index as usize]; let ch = self.text[index as usize];
let charInCurrentTable = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0; let char_in_current_table = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0;
let mut stateNoBinary = None; let mut state_no_binary = None;
for mode in 0..Self::MODE_PUNCT { for mode in 0..=Self::MODE_PUNCT {
// for (int mode = 0; mode <= MODE_PUNCT; mode++) { // for (int mode = 0; mode <= MODE_PUNCT; mode++) {
let charInMode = Self::CHAR_MAP[mode as usize][ch as usize]; let char_in_mode = Self::CHAR_MAP[mode as usize][ch as usize];
if charInMode > 0 { if char_in_mode > 0 {
if stateNoBinary.is_none() { if state_no_binary.is_none() {
// Only create stateNoBinary the first time it's required. // Only create stateNoBinary the first time it's required.
stateNoBinary = Some(state.clone().endBinaryShift(index)); state_no_binary = Some(state.clone().endBinaryShift(index));
} }
// Try generating the character by latching to its mode // Try generating the character by latching to its mode
if !charInCurrentTable || mode as u32 == state.getMode() || mode == Self::MODE_DIGIT if !char_in_current_table
|| mode as u32 == state.getMode()
|| mode == Self::MODE_DIGIT
{ {
// If the character is in the current table, we don't want to latch to // If the character is in the current table, we don't want to latch to
// any other mode except possibly digit (which uses only 4 bits). Any // any other mode except possibly digit (which uses only 4 bits). Any
// other latch would be equally successful *after* this character, and // other latch would be equally successful *after* this character, and
// so wouldn't save any bits. // so wouldn't save any bits.
let latchState = stateNoBinary let latch_state = state_no_binary
.clone() .clone()
.unwrap() .unwrap()
.latchAndAppend(mode as u32, charInMode as u32); .latchAndAppend(mode as u32, char_in_mode as u32);
result.push(latchState); result.push(latch_state);
} }
// Try generating the character by switching to its mode. // Try generating the character by switching to its mode.
if !charInCurrentTable && Self::SHIFT_TABLE[state.getMode() as usize][mode] >= 0 { if !char_in_current_table && Self::SHIFT_TABLE[state.getMode() as usize][mode] >= 0
{
// It never makes sense to temporarily shift to another mode if the // It never makes sense to temporarily shift to another mode if the
// character exists in the current mode. That can never save bits. // character exists in the current mode. That can never save bits.
let shiftState = stateNoBinary let shift_state = state_no_binary
.clone() .clone()
.unwrap() .unwrap()
.shiftAndAppend(mode as u32, charInMode as u32); .shiftAndAppend(mode as u32, char_in_mode as u32);
result.push(shiftState); result.push(shift_state);
} }
} }
} }
@@ -385,56 +396,56 @@ impl HighLevelEncoder {
// It's never worthwhile to go into binary shift mode if you're not already // It's never worthwhile to go into binary shift mode if you're not already
// in binary shift mode, and the character exists in your current mode. // in binary shift mode, and the character exists in your current mode.
// That can never save bits over just outputting the char in the current mode. // That can never save bits over just outputting the char in the current mode.
let binaryState = state.addBinaryShiftChar(index); let binary_state = state.addBinaryShiftChar(index);
result.push(binaryState); result.push(binary_state);
} }
} }
fn updateStateListForPair(states: Vec<State>, index: u32, pairCode: u32) -> Vec<State> { fn update_state_list_for_pair(states: Vec<State>, index: u32, pairCode: u32) -> Vec<State> {
let mut result = Vec::new(); let mut result = Vec::new();
for state in states { for state in states {
// for (State state : states) { // for (State state : states) {
Self::updateStateForPair(state, index, pairCode, &mut result); Self::update_state_for_pair(state, index, pairCode, &mut result);
} }
Self::simplifyStates(result) Self::simplify_states(result)
} }
fn updateStateForPair(state: State, index: u32, pairCode: u32, result: &mut Vec<State>) { fn update_state_for_pair(state: State, index: u32, pair_code: u32, result: &mut Vec<State>) {
let stateNoBinary = state.clone().endBinaryShift(index); let state_no_binary = state.clone().endBinaryShift(index);
// Possibility 1. Latch to MODE_PUNCT, and then append this code // Possibility 1. Latch to MODE_PUNCT, and then append this code
result.push( result.push(
stateNoBinary state_no_binary
.clone() .clone()
.latchAndAppend(Self::MODE_PUNCT as u32, pairCode), .latchAndAppend(Self::MODE_PUNCT as u32, pair_code),
); );
if state.getMode() != Self::MODE_PUNCT as u32 { if state.getMode() != Self::MODE_PUNCT as u32 {
// Possibility 2. Shift to MODE_PUNCT, and then append this code. // Possibility 2. Shift to MODE_PUNCT, and then append this code.
// Every state except MODE_PUNCT (handled above) can shift // Every state except MODE_PUNCT (handled above) can shift
result.push( result.push(
stateNoBinary state_no_binary
.clone() .clone()
.shiftAndAppend(Self::MODE_PUNCT as u32, pairCode), .shiftAndAppend(Self::MODE_PUNCT as u32, pair_code),
); );
} }
if pairCode == 3 || pairCode == 4 { if pair_code == 3 || pair_code == 4 {
// both characters are in DIGITS. Sometimes better to just add two digits // both characters are in DIGITS. Sometimes better to just add two digits
let digitState = stateNoBinary let digit_state = state_no_binary
.latchAndAppend(Self::MODE_DIGIT as u32, 16 - pairCode) // period or comma in DIGIT .latchAndAppend(Self::MODE_DIGIT as u32, 16 - pair_code) // period or comma in DIGIT
.latchAndAppend(Self::MODE_DIGIT as u32, 1); // space in DIGIT .latchAndAppend(Self::MODE_DIGIT as u32, 1); // space in DIGIT
result.push(digitState); result.push(digit_state);
} }
if state.getBinaryShiftByteCount() > 0 { if state.getBinaryShiftByteCount() > 0 {
// It only makes sense to do the characters as binary if we're already // It only makes sense to do the characters as binary if we're already
// in binary mode. // in binary mode.
let binaryState = state let binary_state = state
.addBinaryShiftChar(index) .addBinaryShiftChar(index)
.addBinaryShiftChar(index + 1); .addBinaryShiftChar(index + 1);
result.push(binaryState); result.push(binary_state);
} }
} }
fn simplifyStates(states: Vec<State>) -> Vec<State> { fn simplify_states(states: Vec<State>) -> Vec<State> {
let mut result: Vec<State> = Vec::new(); let mut result: Vec<State> = Vec::new();
for newState in states { for newState in states {
// for (State newState : states) { // for (State newState : states) {
@@ -442,7 +453,7 @@ impl HighLevelEncoder {
for i in 0..result.len() { for i in 0..result.len() {
// for st in result { // for st in result {
// for (Iterator<State> iterator = result.iterator(); iterator.hasNext();) { // for (Iterator<State> iterator = result.iterator(); iterator.hasNext();) {
let oldState = result.get(i).unwrap(); if let Some(oldState) = result.get(i) {
if oldState.isBetterThanOrEqualTo(&newState) { if oldState.isBetterThanOrEqualTo(&newState) {
add = false; add = false;
break; break;
@@ -451,6 +462,7 @@ impl HighLevelEncoder {
result.remove(i); result.remove(i);
} }
} }
}
if add { if add {
result.push(newState); result.push(newState);
} }

View File

@@ -22,20 +22,20 @@ use crate::common::BitArray;
pub struct SimpleToken { pub struct SimpleToken {
// For normal words, indicates value and bitCount // For normal words, indicates value and bitCount
value: u16, value: u16,
bitCount: u16, bit_count: u16,
} }
impl SimpleToken { impl SimpleToken {
pub fn new(value: i32, bitCount: u32) -> Self { pub fn new(value: i32, bitCount: u32) -> Self {
Self { Self {
value: value as u16, value: value as u16,
bitCount: bitCount as u16, bit_count: bitCount as u16,
} }
} }
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) { pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
bitArray bit_array
.appendBits(self.value as u32, self.bitCount as usize) .appendBits(self.value as u32, self.bit_count as usize)
.expect("append should never fail"); .expect("append should never fail");
} }
@@ -49,8 +49,8 @@ impl SimpleToken {
impl fmt::Display for SimpleToken { impl fmt::Display for SimpleToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut value = self.value & ((1 << self.bitCount) - 1); let mut value = self.value & ((1 << self.bit_count) - 1);
value |= 1 << self.bitCount; value |= 1 << self.bit_count;
write!(f, "<{:#016b}>", value | (1 << self.bitCount)) write!(f, "<{:#016b}>", value | (1 << self.bit_count))
} }
} }

View File

@@ -38,19 +38,19 @@ pub struct State {
token: Token, token: Token,
// If non-zero, the number of most recent bytes that should be output // If non-zero, the number of most recent bytes that should be output
// in Binary Shift mode. // in Binary Shift mode.
binaryShiftByteCount: u32, binary_shift_byte_count: u32,
// The total number of bits generated (including Binary Shift). // The total number of bits generated (including Binary Shift).
bitCount: u32, bit_count: u32,
binaryShiftCost: u32, binary_shift_cost: u32,
} }
impl State { impl State {
pub fn new(token: Token, mode: u32, binaryBytes: u32, bitCount: u32) -> Self { pub fn new(token: Token, mode: u32, binary_bytes: u32, bit_count: u32) -> Self {
Self { Self {
mode, mode,
token, token,
binaryShiftByteCount: binaryBytes, binary_shift_byte_count: binary_bytes,
bitCount, bit_count,
binaryShiftCost: Self::calculateBinaryShiftCost(binaryBytes), binary_shift_cost: Self::calculate_binary_shift_cost(binary_bytes),
} }
} }
@@ -63,19 +63,19 @@ impl State {
} }
pub fn getBinaryShiftByteCount(&self) -> u32 { pub fn getBinaryShiftByteCount(&self) -> u32 {
self.binaryShiftByteCount self.binary_shift_byte_count
} }
pub fn getBitCount(&self) -> u32 { pub fn getBitCount(&self) -> u32 {
self.bitCount self.bit_count
} }
pub fn appendFLGn(self, eci: u32) -> Result<Self, Exceptions> { pub fn appendFLGn(self, eci: u32) -> Result<Self, Exceptions> {
let bit_count = self.bitCount; let bit_count = self.bit_count;
let mode = self.mode; let mode = self.mode;
let result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT as u32, 0); // 0: FLG(n) let result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT as u32, 0); // 0: FLG(n)
let mut token = result.token; let mut token = result.token;
let mut bitsAdded = 3; let mut bits_added = 3;
if eci < 0 { if eci < 0 {
token.add(0, 3); // 0: FNC1 token.add(0, 3); // 0: FNC1
} else if eci > 999999 { } else if eci > 999999 {
@@ -84,25 +84,25 @@ impl State {
)); ));
// throw new IllegalArgumentException("ECI code must be between 0 and 999999"); // throw new IllegalArgumentException("ECI code must be between 0 and 999999");
} else { } else {
let eciDigits = encoding::all::ISO_8859_1 let eci_digits = encoding::all::ISO_8859_1
.encode(&format!("{}", eci), encoding::EncoderTrap::Replace) .encode(&format!("{}", eci), encoding::EncoderTrap::Replace)
.unwrap(); .unwrap();
// let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1); // let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
token.add(eciDigits.len() as i32, 3); // 1-6: number of ECI digits token.add(eci_digits.len() as i32, 3); // 1-6: number of ECI digits
for eciDigit in &eciDigits { for eci_digit in &eci_digits {
// for (byte eciDigit : eciDigits) { // for (byte eciDigit : eciDigits) {
token.add((eciDigit - b'0' + 2) as i32, 4); token.add((eci_digit - b'0' + 2) as i32, 4);
} }
bitsAdded += eciDigits.len() * 4; bits_added += eci_digits.len() * 4;
} }
Ok(State::new(token, mode, 0, bit_count + bitsAdded as u32)) Ok(State::new(token, mode, 0, bit_count + bits_added as u32))
// return new State(token, mode, 0, bitCount + bitsAdded); // return new State(token, mode, 0, bitCount + bitsAdded);
} }
// Create a new state representing this state with a latch to a (not // Create a new state representing this state with a latch to a (not
// necessary different) mode, and then a code. // necessary different) mode, and then a code.
pub fn latchAndAppend(self, mode: u32, value: u32) -> State { pub fn latchAndAppend(self, mode: u32, value: u32) -> State {
let mut bitCount = self.bitCount; let mut bitCount = self.bit_count;
let mut token = self.token; let mut token = self.token;
if mode != self.mode { if mode != self.mode {
let latch = HighLevelEncoder::LATCH_TABLE[self.mode as usize][mode as usize]; let latch = HighLevelEncoder::LATCH_TABLE[self.mode as usize][mode as usize];
@@ -134,7 +134,7 @@ impl State {
thisModeBitCount, thisModeBitCount,
); );
token.add(value as i32, 5); token.add(value as i32, 5);
State::new(token, self.mode, 0, self.bitCount + thisModeBitCount + 5) State::new(token, self.mode, 0, self.bit_count + thisModeBitCount + 5)
} }
// Create a new state representing this state, but an additional character // Create a new state representing this state, but an additional character
@@ -142,7 +142,7 @@ impl State {
pub fn addBinaryShiftChar(self, index: u32) -> State { pub fn addBinaryShiftChar(self, index: u32) -> State {
let mut token = self.token; let mut token = self.token;
let mut mode = self.mode; let mut mode = self.mode;
let mut bitCount = self.bitCount; let mut bitCount = self.bit_count;
if self.mode == HighLevelEncoder::MODE_PUNCT as u32 if self.mode == HighLevelEncoder::MODE_PUNCT as u32
|| self.mode == HighLevelEncoder::MODE_DIGIT as u32 || self.mode == HighLevelEncoder::MODE_DIGIT as u32
{ {
@@ -151,10 +151,10 @@ impl State {
bitCount += latch >> 16; bitCount += latch >> 16;
mode = HighLevelEncoder::MODE_UPPER as u32; mode = HighLevelEncoder::MODE_UPPER as u32;
} }
let deltaBitCount = if self.binaryShiftByteCount == 0 || self.binaryShiftByteCount == 31 { let deltaBitCount = if self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31 {
18 18
} else { } else {
if self.binaryShiftByteCount == 62 { if self.binary_shift_byte_count == 62 {
9 9
} else { } else {
8 8
@@ -163,10 +163,10 @@ impl State {
let mut result = State::new( let mut result = State::new(
token, token,
mode, mode,
self.binaryShiftByteCount + 1, self.binary_shift_byte_count + 1,
bitCount + deltaBitCount, bitCount + deltaBitCount,
); );
if result.binaryShiftByteCount == 2047 + 31 { if result.binary_shift_byte_count == 2047 + 31 {
// The string is as long as it's allowed to be. We should end it. // The string is as long as it's allowed to be. We should end it.
result = result.endBinaryShift(index + 1); result = result.endBinaryShift(index + 1);
} }
@@ -176,30 +176,30 @@ impl State {
// Create the state identical to this one, but we are no longer in // Create the state identical to this one, but we are no longer in
// Binary Shift mode. // Binary Shift mode.
pub fn endBinaryShift(self, index: u32) -> State { pub fn endBinaryShift(self, index: u32) -> State {
if self.binaryShiftByteCount == 0 { if self.binary_shift_byte_count == 0 {
return self; return self;
} }
let mut token = self.token; let mut token = self.token;
token.addBinaryShift(index - self.binaryShiftByteCount, self.binaryShiftByteCount); token.addBinaryShift(index - self.binary_shift_byte_count, self.binary_shift_byte_count);
State::new(token, self.mode, 0, self.bitCount) State::new(token, self.mode, 0, self.bit_count)
} }
// Returns true if "this" state is better (or equal) to be in than "that" // Returns true if "this" state is better (or equal) to be in than "that"
// state under all possible circumstances. // state under all possible circumstances.
pub fn isBetterThanOrEqualTo(&self, other: &State) -> bool { pub fn isBetterThanOrEqualTo(&self, other: &State) -> bool {
let mut newModeBitCount = self.bitCount let mut new_mode_bit_count = self.bit_count
+ (HighLevelEncoder::LATCH_TABLE[self.mode as usize][other.mode as usize] >> 16); + (HighLevelEncoder::LATCH_TABLE[self.mode as usize][other.mode as usize] >> 16);
if self.binaryShiftByteCount < other.binaryShiftByteCount { if self.binary_shift_byte_count < other.binary_shift_byte_count {
// add additional B/S encoding cost of other, if any // add additional B/S encoding cost of other, if any
newModeBitCount += other.binaryShiftCost - self.binaryShiftCost; new_mode_bit_count += other.binary_shift_cost - self.binary_shift_cost;
} else if self.binaryShiftByteCount > other.binaryShiftByteCount } else if self.binary_shift_byte_count > other.binary_shift_byte_count
&& other.binaryShiftByteCount > 0 && other.binary_shift_byte_count > 0
{ {
// maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it) // maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
newModeBitCount += 10; new_mode_bit_count += 10;
} }
newModeBitCount <= other.bitCount new_mode_bit_count <= other.bit_count
} }
pub fn toBitArray(self, text: &[u8]) -> BitArray { pub fn toBitArray(self, text: &[u8]) -> BitArray {
@@ -215,28 +215,24 @@ impl State {
// symbols.push(tkn); // symbols.push(tkn);
// tkn = tok.getPrevious(); // tkn = tok.getPrevious();
// } // }
let mut bitArray = BitArray::new(); let mut bit_array = BitArray::new();
// Add each token to the result in forward order // Add each token to the result in forward order
for i in (0..symbols.len() - 1).rev() { for symbol in symbols.into_iter().rev() {
// for i in (0..symbols.len()).rev() {
// for (int i = symbols.size() - 1; i >= 0; i--) { // for (int i = symbols.size() - 1; i >= 0; i--) {
symbols.get(i).unwrap().appendTo(&mut bitArray, text); symbol.appendTo(&mut bit_array, text);
} }
bitArray bit_array
} }
// @Override fn calculate_binary_shift_cost(binary_shift_byte_count: u32) -> u32 {
// public String toString() { if binary_shift_byte_count > 62 {
// return String.format("%s bits=%d bytes=%d", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
// }
fn calculateBinaryShiftCost(binaryShiftByteCount: u32) -> u32 {
if binaryShiftByteCount > 62 {
return 21; // B/S with extended length return 21; // B/S with extended length
} }
if binaryShiftByteCount > 31 { if binary_shift_byte_count > 31 {
return 20; // two B/S return 20; // two B/S
} }
if binaryShiftByteCount > 0 { if binary_shift_byte_count > 0 {
return 10; // one B/S return 10; // one B/S
} }
return 0; return 0;
@@ -249,8 +245,8 @@ impl fmt::Display for State {
f, f,
"{} bits={} bytes={}", "{} bits={} bytes={}",
HighLevelEncoder::MODE_NAMES[self.mode as usize], HighLevelEncoder::MODE_NAMES[self.mode as usize],
self.bitCount, self.bit_count,
self.binaryShiftByteCount self.binary_shift_byte_count
) )
} }
} }

View File

@@ -9,9 +9,9 @@ pub fn toBitArray( bits:&str) -> BitArray{
let mut ba_in = BitArray::new(); let mut ba_in = BitArray::new();
let replacer_regex = Regex::new(DOTX).unwrap(); let replacer_regex = Regex::new(DOTX).unwrap();
let str = replacer_regex.replace_all(bits, ""); let str = replacer_regex.replace_all(bits, "");
for aStr in str.chars() { for a_str in str.chars() {
// for (char aStr : str) { // for (char aStr : str) {
ba_in.appendBit(aStr == 'X'); ba_in.appendBit(a_str == 'X');
} }
ba_in ba_in

View File

@@ -148,6 +148,21 @@ use rand::Rng;
} }
} }
#[test]
fn test_append_bit(){
let mut array = BitArray::new();
array.appendBits(0x000001E, 6);
let mut array_2 = BitArray::new();
array_2.appendBit(false);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(false);
assert_eq!(array, array_2)
}
#[test] #[test]
fn test_set_range() { fn test_set_range() {
let mut array = BitArray::with_size(64); let mut array = BitArray::with_size(64);

View File

@@ -552,14 +552,19 @@ impl BitArray {
* @param numBits bits from value to append * @param numBits bits from value to append
*/ */
pub fn appendBits(&mut self, value: u32, numBits: usize) -> Result<(), Exceptions> { pub fn appendBits(&mut self, value: u32, numBits: usize) -> Result<(), Exceptions> {
if numBits < 0 || numBits > 32 { if numBits > 32 {
return Err(Exceptions::IllegalArgumentException( return Err(Exceptions::IllegalArgumentException(
"Num bits must be between 0 and 32".to_owned(), "Num bits must be between 0 and 32".to_owned(),
)); ));
} }
if numBits == 0 {
return Ok(());
}
let mut nextSize = self.size; let mut nextSize = self.size;
self.ensureCapacity(nextSize + numBits); self.ensureCapacity(nextSize + numBits);
for numBitsLeft in (0..(numBits - 1)).rev() { for numBitsLeft in (0..(numBits)).rev() {
//for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) { //for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) {
if (value & (1 << numBitsLeft)) != 0 { if (value & (1 << numBitsLeft)) != 0 {
self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F); self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F);
@@ -720,7 +725,6 @@ impl fmt::Display for BitArray {
* @author Sean Owen * @author Sean Owen
*/ */
pub trait DetectorRXingResult { pub trait DetectorRXingResult {
fn getBits(&self) -> &BitMatrix; fn getBits(&self) -> &BitMatrix;
fn getPoints(&self) -> &Vec<RXingResultPoint>; fn getPoints(&self) -> &Vec<RXingResultPoint>;
@@ -841,25 +845,25 @@ impl BitMatrix {
} }
pub fn parse_strings( pub fn parse_strings(
stringRepresentation: &str, string_representation: &str,
setString: &str, set_string: &str,
unsetString: &str, unset_string: &str,
) -> Result<Self, Exceptions> { ) -> Result<Self, Exceptions> {
// cannot pass nulls in rust // cannot pass nulls in rust
// if (stringRepresentation == null) { // if (stringRepresentation == null) {
// throw new IllegalArgumentException(); // throw new IllegalArgumentException();
// } // }
let mut bits = vec![false; stringRepresentation.len()]; let mut bits = vec![false; string_representation.len()];
let mut bitsPos = 0; let mut bitsPos = 0;
let mut rowStartPos = 0; let mut rowStartPos = 0;
let mut rowLength = 0; //-1; let mut rowLength = 0; //-1;
let mut first_run = true; let mut first_run = true;
let mut nRows = 0; let mut nRows = 0;
let mut pos = 0; let mut pos = 0;
while pos < stringRepresentation.len() { while pos < string_representation.len() {
if stringRepresentation.chars().nth(pos).unwrap() == '\n' if string_representation.chars().nth(pos).unwrap() == '\n'
|| stringRepresentation.chars().nth(pos).unwrap() == '\r' || string_representation.chars().nth(pos).unwrap() == '\r'
{ {
if bitsPos > rowStartPos { if bitsPos > rowStartPos {
//if rowLength == -1 { //if rowLength == -1 {
@@ -875,18 +879,18 @@ impl BitMatrix {
nRows += 1; nRows += 1;
} }
pos += 1; pos += 1;
} else if stringRepresentation[pos..].starts_with(setString) { } else if string_representation[pos..].starts_with(set_string) {
pos += setString.len(); pos += set_string.len();
bits[bitsPos] = true; bits[bitsPos] = true;
bitsPos += 1; bitsPos += 1;
} else if stringRepresentation[pos..].starts_with(unsetString) { } else if string_representation[pos..].starts_with(unset_string) {
pos += unsetString.len(); pos += unset_string.len();
bits[bitsPos] = false; bits[bitsPos] = false;
bitsPos += 1; bitsPos += 1;
} else { } else {
return Err(Exceptions::IllegalArgumentException(format!( return Err(Exceptions::IllegalArgumentException(format!(
"illegal character encountered: {}", "illegal character encountered: {}",
stringRepresentation[pos..].to_owned() string_representation[pos..].to_owned()
))); )));
} }
} }
@@ -975,7 +979,8 @@ impl BitMatrix {
* @param mask XOR mask * @param mask XOR mask
*/ */
pub fn xor(&mut self, mask: &BitMatrix) -> Result<(), Exceptions> { pub fn xor(&mut self, mask: &BitMatrix) -> Result<(), Exceptions> {
if self.width != mask.width || self.height != mask.height || self.row_size != mask.row_size { if self.width != mask.width || self.height != mask.height || self.row_size != mask.row_size
{
return Err(Exceptions::IllegalArgumentException( return Err(Exceptions::IllegalArgumentException(
"input matrix dimensions do not match".to_owned(), "input matrix dimensions do not match".to_owned(),
)); ));
@@ -2398,6 +2403,7 @@ impl GridSampler for DefaultGridSampler {
* *
* @author Sean Owen * @author Sean Owen
*/ */
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CharacterSetECI { pub enum CharacterSetECI {
// Enum name is a Java encoding valid for java.lang and java.io // Enum name is a Java encoding valid for java.lang and java.io
Cp437, //(new int[]{0,2}), Cp437, //(new int[]{0,2}),
@@ -2531,34 +2537,34 @@ impl CharacterSetECI {
* but unsupported * but unsupported
*/ */
pub fn getCharacterSetECI(charset: &'static dyn Encoding) -> Option<CharacterSetECI> { pub fn getCharacterSetECI(charset: &'static dyn Encoding) -> Option<CharacterSetECI> {
match charset.whatwg_name().unwrap() { match charset.name() {
"CP437" => Some(CharacterSetECI::Cp437), "CP437" => Some(CharacterSetECI::Cp437),
"ISO-8859-1" => Some(CharacterSetECI::ISO8859_1), "iso-8859-1" => Some(CharacterSetECI::ISO8859_1),
"ISO-8859-2" => Some(CharacterSetECI::ISO8859_2), "iso-8859-2" => Some(CharacterSetECI::ISO8859_2),
"ISO-8859-3" => Some(CharacterSetECI::ISO8859_3), "iso-8859-3" => Some(CharacterSetECI::ISO8859_3),
"ISO-8859-4" => Some(CharacterSetECI::ISO8859_4), "iso-8859-4" => Some(CharacterSetECI::ISO8859_4),
"ISO-8859-5" => Some(CharacterSetECI::ISO8859_5), "iso-8859-5" => Some(CharacterSetECI::ISO8859_5),
"ISO-8859-6" => Some(CharacterSetECI::ISO8859_6), "iso-8859-6" => Some(CharacterSetECI::ISO8859_6),
"ISO-8859-7" => Some(CharacterSetECI::ISO8859_7), "iso-8859-7" => Some(CharacterSetECI::ISO8859_7),
"ISO-8859-8" => Some(CharacterSetECI::ISO8859_8), "iso-8859-8" => Some(CharacterSetECI::ISO8859_8),
"ISO-8859-9" => Some(CharacterSetECI::ISO8859_9), "iso-8859-9" => Some(CharacterSetECI::ISO8859_9),
"ISO-8859-10" => Some(CharacterSetECI::ISO8859_10), "iso-8859-10" => Some(CharacterSetECI::ISO8859_10),
"ISO-8859-11" => Some(CharacterSetECI::ISO8859_11), "iso-8859-11" => Some(CharacterSetECI::ISO8859_11),
"ISO-8859-13" => Some(CharacterSetECI::ISO8859_13), "iso-8859-13" => Some(CharacterSetECI::ISO8859_13),
"ISO-8859-14" => Some(CharacterSetECI::ISO8859_14), "iso-8859-14" => Some(CharacterSetECI::ISO8859_14),
"ISO-8859-15" => Some(CharacterSetECI::ISO8859_15), "iso-8859-15" => Some(CharacterSetECI::ISO8859_15),
"ISO-8859-16" => Some(CharacterSetECI::ISO8859_16), "iso-8859-16" => Some(CharacterSetECI::ISO8859_16),
"Shift_JIS" => Some(CharacterSetECI::SJIS), "shift_jis" => Some(CharacterSetECI::SJIS),
"windows-1250" => Some(CharacterSetECI::Cp1250), "windows-1250" => Some(CharacterSetECI::Cp1250),
"windows-1251" => Some(CharacterSetECI::Cp1251), "windows-1251" => Some(CharacterSetECI::Cp1251),
"windows-1252" => Some(CharacterSetECI::Cp1252), "windows-1252" => Some(CharacterSetECI::Cp1252),
"windows-1256" => Some(CharacterSetECI::Cp1256), "windows-1256" => Some(CharacterSetECI::Cp1256),
"UTF-16BE" => Some(CharacterSetECI::UnicodeBigUnmarked), "utf-16be" => Some(CharacterSetECI::UnicodeBigUnmarked),
"UTF-8" => Some(CharacterSetECI::UTF8), "utf-8" => Some(CharacterSetECI::UTF8),
"US-ASCII" => Some(CharacterSetECI::ASCII), "us-ascii" => Some(CharacterSetECI::ASCII),
"Big5" => Some(CharacterSetECI::Big5), "big5" => Some(CharacterSetECI::Big5),
"GB2312" => Some(CharacterSetECI::GB18030), "gb2312" => Some(CharacterSetECI::GB18030),
"EUC-KR" => Some(CharacterSetECI::EUC_KR), "euc-kr" => Some(CharacterSetECI::EUC_KR),
_ => None, _ => None,
} }
} }
@@ -4052,6 +4058,9 @@ impl HybridBinarizer {
blackPoints[y as usize][x as usize] = average; blackPoints[y as usize][x as usize] = average;
} }
} }
return blackPoints.into_iter().map(|x| x.iter().map(|y| *y as u32).collect()).collect(); return blackPoints
.into_iter()
.map(|x| x.iter().map(|y| *y as u32).collect())
.collect();
} }
} }