mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-28 05:12:34 +00:00
partially passing encoder
This commit is contained in:
@@ -34,6 +34,8 @@
|
||||
// import java.util.Random;
|
||||
// import java.util.TreeSet;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{aztec::decoder, common::BitMatrix, exceptions::Exceptions};
|
||||
|
||||
use super::{
|
||||
@@ -69,7 +71,7 @@ fn testErrorInParameterLocatorNotCompact() {
|
||||
fn testErrorInParameterLocator(data: &str) {
|
||||
let aztec = encoder::encoder::encode(data, 25, encoder::encoder::DEFAULT_AZTEC_LAYERS)
|
||||
.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 compact = aztec.isCompact();
|
||||
let orientationPoints = getOrientationPoints(&aztec);
|
||||
@@ -78,24 +80,24 @@ fn testErrorInParameterLocator(data: &str) {
|
||||
for matrix in getRotations(aztec.getMatrix()) {
|
||||
// for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
|
||||
// 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 error2 in error1..orientationPoints.size() {
|
||||
for error2 in error1..orientationPoints.len() {
|
||||
// for (int error2 = error1; error2 < orientationPoints.size(); error2++) {
|
||||
let copy = if isMirror {
|
||||
let mut copy = if isMirror {
|
||||
transpose(&matrix)
|
||||
} else {
|
||||
clone(&matrix)
|
||||
};
|
||||
copy.flip(
|
||||
orientationPoints.get(error1).getX(),
|
||||
orientationPoints.get(error1).getY(),
|
||||
copy.flip_coords(
|
||||
orientationPoints.get(error1).unwrap().getX() as u32,
|
||||
orientationPoints.get(error1).unwrap().getY() as u32,
|
||||
);
|
||||
if error2 > error1 {
|
||||
// if error2 == error1, we only test a single error
|
||||
copy.flip(
|
||||
orientationPoints.get(error2).getX(),
|
||||
orientationPoints.get(error2).getY(),
|
||||
copy.flip_coords(
|
||||
orientationPoints.get(error2).unwrap().getX() as u32,
|
||||
orientationPoints.get(error2).unwrap().getY() as u32,
|
||||
);
|
||||
}
|
||||
// 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;
|
||||
for i in 0..5 {
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
let copy = clone(&matrix);
|
||||
let errors = Vec::new();
|
||||
while errors.size() < 3 {
|
||||
let mut copy = clone(&matrix);
|
||||
let mut errors = Vec::new();
|
||||
while errors.len() < 3 {
|
||||
// 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 (int error : errors) {
|
||||
copy.flip(
|
||||
orientationPoints.get(error).getX(),
|
||||
orientationPoints.get(error).getY(),
|
||||
copy.flip_coords(
|
||||
orientationPoints.get(error).unwrap().getX() as u32,
|
||||
orientationPoints.get(error).unwrap().getY() as u32,
|
||||
);
|
||||
}
|
||||
// try {
|
||||
@@ -147,7 +149,7 @@ fn testErrorInParameterLocator(data: &str) {
|
||||
// Zooms a bit matrix so that each bit is factor x factor
|
||||
fn makeLarger(input: &BitMatrix, factor: u32) -> BitMatrix {
|
||||
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 (int inputY = 0; inputY < width; inputY++) {
|
||||
for inputX in 0..width {
|
||||
@@ -165,13 +167,13 @@ fn getRotations(matrix0: &BitMatrix) -> Vec<BitMatrix> {
|
||||
let matrix90 = rotateRight(matrix0);
|
||||
let matrix180 = rotateRight(&matrix90);
|
||||
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
|
||||
fn rotateRight(input: &BitMatrix) -> BitMatrix {
|
||||
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 (int x = 0; x < width; x++) {
|
||||
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
|
||||
fn transpose(input: &BitMatrix) -> BitMatrix {
|
||||
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 (int x = 0; x < width; x++) {
|
||||
for y in 0..width {
|
||||
@@ -203,7 +205,7 @@ fn transpose(input: &BitMatrix) -> BitMatrix {
|
||||
|
||||
fn clone(input: &BitMatrix) -> BitMatrix {
|
||||
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 (int x = 0; x < width; x++) {
|
||||
for y in 0..width {
|
||||
@@ -217,21 +219,21 @@ fn clone(input: &BitMatrix) -> BitMatrix {
|
||||
}
|
||||
|
||||
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 result = Vec::new();
|
||||
let mut xSign = -1;
|
||||
let mut result = Vec::new();
|
||||
let mut xSign: i32 = -1;
|
||||
while xSign <= 1 {
|
||||
// for (int xSign = -1; xSign <= 1; xSign += 2) {
|
||||
let mut ySign = -1;
|
||||
let mut ySign: i32 = -1;
|
||||
while ySign <= 1 {
|
||||
// for (int ySign = -1; ySign <= 1; ySign += 2) {
|
||||
result.add(Point::new(center + xSign * offset, center + ySign * offset));
|
||||
result.add(Point::new(
|
||||
result.push(Point::new(center + xSign * offset, center + ySign * offset));
|
||||
result.push(Point::new(
|
||||
center + xSign * (offset - 1),
|
||||
center + ySign * offset,
|
||||
));
|
||||
result.add(Point::new(
|
||||
result.push(Point::new(
|
||||
center + xSign * offset,
|
||||
center + ySign * (offset - 1),
|
||||
));
|
||||
|
||||
@@ -40,12 +40,25 @@ use std::collections::HashMap;
|
||||
|
||||
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 rand::Rng;
|
||||
|
||||
use encoding::Encoding;
|
||||
|
||||
/**
|
||||
* Aztec 2D generator unit tests.
|
||||
*
|
||||
@@ -55,7 +68,6 @@ use crate::Writer;
|
||||
|
||||
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 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 WINDOWS_1252: EncodingRef = encoding::all::WINDOWS_1252; //Charset.forName("Windows-1252");
|
||||
|
||||
@@ -67,7 +79,10 @@ use crate::Writer;
|
||||
|
||||
#[test]
|
||||
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
|
||||
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
|
||||
" );
|
||||
}
|
||||
|
||||
#[test]
|
||||
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
|
||||
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
|
||||
X X X X X X X X X X 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
|
||||
");
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
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", 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
|
||||
@@ -153,13 +174,23 @@ 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), 300, true, 4);
|
||||
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
|
||||
let data = "In ut magna vel mauris malesuada";
|
||||
// let writer = AztecWriter{};
|
||||
let matrix = AztecWriter::encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist");
|
||||
let aztec = encoder::encode(data,
|
||||
encoder::DEFAULT_EC_PERCENT, encoder::DEFAULT_AZTEC_LAYERS).expect("encode should succeed");
|
||||
let aztec = encoder::encode(
|
||||
data,
|
||||
encoder::DEFAULT_EC_PERCENT,
|
||||
encoder::DEFAULT_AZTEC_LAYERS,
|
||||
)
|
||||
.expect("encode should succeed");
|
||||
let expectedMatrix = aztec.getMatrix();
|
||||
assert_eq!(&matrix, expectedMatrix);
|
||||
}
|
||||
@@ -178,7 +209,11 @@ distinctive square bullseye pattern at their center.", false, 6,
|
||||
|
||||
#[test]
|
||||
fn testEncodeDecode3() {
|
||||
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
|
||||
testEncodeDecode(
|
||||
"AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN",
|
||||
true,
|
||||
3,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -188,23 +223,32 @@ distinctive square bullseye pattern at their center.", false, 6,
|
||||
|
||||
#[test]
|
||||
fn testEncodeDecode5() {
|
||||
testEncodeDecode(r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc
|
||||
Four score and seven our forefathers brought forth"#, false, 5);
|
||||
testEncodeDecode(
|
||||
r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc
|
||||
Four score and seven our forefathers brought forth"#,
|
||||
false,
|
||||
5,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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
|
||||
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
|
||||
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
|
||||
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]
|
||||
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
|
||||
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
|
||||
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.
|
||||
Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit
|
||||
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]
|
||||
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
|
||||
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
|
||||
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
|
||||
@@ -266,57 +314,84 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum
|
||||
sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.
|
||||
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]
|
||||
fn testGenerateModeMessage() {
|
||||
testModeMessageComplex(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
|
||||
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(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
|
||||
testModeMessageComplex(
|
||||
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]
|
||||
fn testStuffBitsTest() {
|
||||
testStuffBits(5, ".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(3, "XX. ... ... ..X XXX .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.X.",
|
||||
".X.X.. .....X .....X ....X. X.XXXX");
|
||||
testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX",
|
||||
".X.X.. XXXXX. X..... ...X.X XXXXX.");
|
||||
testStuffBits(5, ".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(
|
||||
3,
|
||||
"XX. ... ... ..X XXX .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.X.",
|
||||
".X.X.. .....X .....X ....X. X.XXXX",
|
||||
);
|
||||
testStuffBits(
|
||||
6,
|
||||
".X.X.. XXXXXX ...... ..X.XX",
|
||||
".X.X.. XXXXX. X..... ...X.X XXXXX.",
|
||||
);
|
||||
testStuffBits(6,
|
||||
"...... ..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");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test] // Adding a binary shift character that shouldn't be there.
|
||||
fn testHighLevelEncode() {
|
||||
testHighLevelEncodeString("A. b.",
|
||||
testHighLevelEncodeString(
|
||||
"A. b.",
|
||||
// 'A' P/S '. ' L/L b D/L '.'
|
||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
||||
testHighLevelEncodeString("Lorem ipsum.",
|
||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X",
|
||||
);
|
||||
testHighLevelEncodeString(
|
||||
"Lorem ipsum.",
|
||||
// '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.",
|
||||
// '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");
|
||||
testHighLevelEncodeString("Lo...x",
|
||||
testHighLevelEncodeString(
|
||||
"Lo...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/.",
|
||||
//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");
|
||||
// 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'
|
||||
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...");
|
||||
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...",
|
||||
);
|
||||
|
||||
testHighLevelEncodeStringCount(
|
||||
// Found on an airline boarding pass. Several stretches of Binary shift are
|
||||
@@ -328,97 +403,132 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
#[test]
|
||||
fn testHighLevelEncodeBinary() {
|
||||
// binary short form single byte
|
||||
testHighLevelEncodeString("N\0N",
|
||||
testHighLevelEncodeString(
|
||||
"N\0N",
|
||||
// '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'
|
||||
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
|
||||
".XXXX XXXXX ...X. ........ .XX.XXX.",
|
||||
); // Encode "n" in BINARY
|
||||
|
||||
// binary short form consecutive bytes
|
||||
testHighLevelEncodeString("N\0\u{0080} A",
|
||||
testHighLevelEncodeString(
|
||||
"N\0\u{0080} 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
|
||||
testHighLevelEncodeString("\0a\u{00FF}\u{0080} A",
|
||||
testHighLevelEncodeString(
|
||||
"\0a\u{00FF}\u{0080} 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
|
||||
testHighLevelEncodeString("1234\0",
|
||||
testHighLevelEncodeString(
|
||||
"1234\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
|
||||
let sb = String::new();
|
||||
let mut sb = String::new();
|
||||
for i in 0..3000 {
|
||||
// for (int i = 0; i <= 3000; i++) {
|
||||
sb.push(char::from_u32(128 + (i % 30)).unwrap());
|
||||
}
|
||||
// Test the output generated by Binary/Switch, particularly near the
|
||||
// places where the encoding changes: 31, 62, and 2047+31=2078
|
||||
for i in [1, 2, 3, 10, 29, 30, 31, 32, 33,
|
||||
60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100]{
|
||||
for i in [
|
||||
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,
|
||||
// 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100 }) {
|
||||
// This is the expected length of a binary string of length "i"
|
||||
let expectedLength = (8 * i) +
|
||||
if i <= 31 { 10 } else { if i <= 62 {20} else{if i <= 2078 {21} else {31}} };
|
||||
let expected_length = (8 * i)
|
||||
+ 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);
|
||||
// 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 {
|
||||
// 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.
|
||||
// So we exclude the border cases i=1,32,2079
|
||||
// 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
|
||||
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.
|
||||
testHighLevelEncodeStringCount(&format!("a{}b",&sb[..i] ), expectedLength as u32+ 15);
|
||||
testHighLevelEncodeStringCount(&format!("a{}b", &substring_for_test), expected_length as u32 + 15);
|
||||
}
|
||||
|
||||
sb.clear();
|
||||
for i in 0..32 {
|
||||
|
||||
sb.push('A');
|
||||
for _i in 0..31 {
|
||||
// for (int i = 0; i < 32; i++) {
|
||||
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');
|
||||
// expect B/S(1) A B/S(30)
|
||||
testHighLevelEncodeStringCount(&sb, 5 + 20 + 31 * 8);
|
||||
|
||||
sb.clear();
|
||||
for i in 0..31 {
|
||||
|
||||
sb.push('A');
|
||||
for _i in 0..30 {
|
||||
// for (int i = 0; i < 31; i++) {
|
||||
sb.push('§');
|
||||
}
|
||||
sb.replace_range(1..2, "A");
|
||||
// sb.replace_range(1..2, "A");
|
||||
// sb.setCharAt(1, 'A');
|
||||
// expect B/S(31)
|
||||
testHighLevelEncodeStringCount(&sb, 10 + 31 * 8);
|
||||
|
||||
sb.clear();
|
||||
for i in 0..34 {
|
||||
|
||||
sb.push('A');
|
||||
for _i in 0..33 {
|
||||
// for (int i = 0; i < 34; i++) {
|
||||
sb.push('§');
|
||||
}
|
||||
sb.replace_range(1..2, "A");
|
||||
//sb.replace_range(1..2, "A");
|
||||
// sb.setCharAt(1, 'A');
|
||||
// expect B/S(31) B/S(3)
|
||||
testHighLevelEncodeStringCount(&sb, 20 + 34 * 8);
|
||||
|
||||
sb.clear();
|
||||
for i in 0..64 {
|
||||
for _i in 0..30 {
|
||||
// for (int i = 0; i < 64; i++) {
|
||||
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');
|
||||
// expect B/S(64)
|
||||
testHighLevelEncodeStringCount(&sb, 21 + 64 * 8);
|
||||
@@ -427,23 +537,31 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
#[test]
|
||||
fn testHighLevelEncodePairs() {
|
||||
// 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
|
||||
"...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
|
||||
testHighLevelEncodeString("A. : , \r\n",
|
||||
testHighLevelEncodeString(
|
||||
"A. : , \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
|
||||
testHighLevelEncodeString("A. 1234",
|
||||
testHighLevelEncodeString(
|
||||
"A. 1234",
|
||||
// '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.
|
||||
testHighLevelEncodeString("A\u{200}. \u{200}",
|
||||
testHighLevelEncodeString(
|
||||
"A\u{80}. \u{80}",
|
||||
// 'A' B/S =2 \200 "." " " \200
|
||||
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
|
||||
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -460,7 +578,7 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
|
||||
fn doTestUserSpecifiedLayers(userSpecifiedLayers: usize) {
|
||||
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!(aztec.isCompact());
|
||||
|
||||
@@ -468,7 +586,7 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
assert_eq!(32, aztec.getLayers());
|
||||
assert!(!aztec.isCompact());
|
||||
|
||||
encoder::encode(alphabet, 25, userSpecifiedLayers as u32);
|
||||
encoder::encode(alphabet, 25, userSpecifiedLayers as u32).expect("encode");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -479,7 +597,7 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
// encodes as 26 * 5 * 4 = 520 bits of data
|
||||
let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
|
||||
encoder::encode(&alphabet4, 0, 4);
|
||||
encoder::encode(&alphabet4, 0, 4).expect("encode");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -491,13 +609,15 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
|
||||
|
||||
// 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_eq!(4, aztecCode.getLayers());
|
||||
|
||||
// But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we
|
||||
// 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_eq!(4, aztecCode.getLayers());
|
||||
}
|
||||
@@ -506,75 +626,138 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
|
||||
fn testEncode(data: &str, compact: bool, layers: u32, expected: &str) {
|
||||
let aztec = encoder::encode(data, 33, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
|
||||
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)");
|
||||
assert_eq!(
|
||||
compact,
|
||||
aztec.isCompact(),
|
||||
"Unexpected symbol format (compact)"
|
||||
);
|
||||
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
|
||||
let matrix = aztec.getMatrix();
|
||||
assert_eq!( expected, matrix.to_string(),"encode() failed");
|
||||
let z: BitMatrix;
|
||||
assert_eq!(expected, matrix.to_string(), "encode({}) failed", data);
|
||||
}
|
||||
|
||||
fn testEncodeDecode(data: &str, compact: bool, layers: u32) {
|
||||
let aztec = encoder::encode(data, 25, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
|
||||
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)");
|
||||
assert_eq!(
|
||||
compact,
|
||||
aztec.isCompact(),
|
||||
"Unexpected symbol format (compact)"
|
||||
);
|
||||
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
|
||||
let mut matrix = aztec.getMatrix();
|
||||
let r =
|
||||
AztecDetectorRXingResult::new(matrix.clone(), NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
let res = decoder::decode(&r).expect("decode ok");
|
||||
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());
|
||||
// Check error correction by introducing a few minor errors
|
||||
let random = getPseudoRandom();
|
||||
matrix.flip(random.nextInt(matrix.getWidth()), random.nextInt(2));
|
||||
matrix.flip(random.nextInt(matrix.getWidth()), matrix.getHeight() - 2 + random.nextInt(2));
|
||||
matrix.flip(random.nextInt(2), random.nextInt(matrix.getHeight()));
|
||||
matrix.flip(matrix.getWidth() - 2 + random.nextInt(2), random.nextInt(matrix.getHeight()));
|
||||
r = AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
res = decoder::decode(r);
|
||||
let mut random = getPseudoRandom();
|
||||
matrix.flip_coords(
|
||||
random.gen_range(0..matrix.getWidth()),
|
||||
random.gen_range(0..=2),
|
||||
);
|
||||
matrix.flip_coords(
|
||||
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());
|
||||
}
|
||||
|
||||
fn testWriter( data:&str,
|
||||
fn testWriter(
|
||||
data: &str,
|
||||
charset: Option<EncodingRef>,
|
||||
eccPercent: u32,
|
||||
compact: bool,
|
||||
layers:u32) {
|
||||
layers: u32,
|
||||
) {
|
||||
// Perform an encode-decode round-trip because it can be lossy.
|
||||
let hints = HashMap::new();
|
||||
let mut hints = HashMap::new();
|
||||
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) {
|
||||
// hints.put(EncodeHintType.CHARACTER_SET, charset.name());
|
||||
// }
|
||||
hints.insert(EncodeHintType::ERROR_CORRECTION, eccPercent);
|
||||
hints.insert(
|
||||
EncodeHintType::ERROR_CORRECTION,
|
||||
EncodeHintValue::ErrorCorrection(eccPercent.to_string()),
|
||||
);
|
||||
let writer = AztecWriter {};
|
||||
let matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints).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)");
|
||||
let mut matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints)
|
||||
.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();
|
||||
assert_eq!(&matrix, matrix2);
|
||||
let r =
|
||||
AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
let res = decoder::decode(&r);
|
||||
let mut r = AztecDetectorRXingResult::new(
|
||||
matrix.clone(),
|
||||
NO_POINTS,
|
||||
aztec.isCompact(),
|
||||
aztec.getCodeWords(),
|
||||
aztec.getLayers(),
|
||||
);
|
||||
let mut res = decoder::decode(&r).expect("should decode");
|
||||
assert_eq!(data, res.getText());
|
||||
// Check error correction by introducing up to eccPercent/2 errors
|
||||
let ecWords = aztec.getCodeWords() * eccPercent / 100 / 2;
|
||||
let random = getPseudoRandom();
|
||||
for i in 0 ..ecWords {
|
||||
let mut random = getPseudoRandom();
|
||||
for _i in 0..ecWords {
|
||||
// for (int i = 0; i < ecWords; i++) {
|
||||
// don't touch the core
|
||||
let x = if random.nextBoolean()
|
||||
{random.nextInt(aztec.getLayers() * 2)}
|
||||
else {matrix.getWidth() - 1 - random.nextInt(aztec.getLayers() * 2)};
|
||||
let y = if random.nextBoolean()
|
||||
{random.nextInt(aztec.getLayers() * 2)}
|
||||
else {matrix.getHeight() - 1 - random.nextInt(aztec.getLayers() * 2)};
|
||||
matrix.flip(x, y);
|
||||
let x = if random.gen_bool(50.0) {
|
||||
random.gen_range(0..=aztec.getLayers() * 2)
|
||||
} else {
|
||||
matrix.getWidth() - 1 - random.gen_range(0..=aztec.getLayers() * 2)
|
||||
};
|
||||
let y = if random.gen_bool(50.0) {
|
||||
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());
|
||||
res = decoder::decode(r);
|
||||
r = AztecDetectorRXingResult::new(
|
||||
matrix,
|
||||
NO_POINTS,
|
||||
aztec.isCompact(),
|
||||
aztec.getCodeWords(),
|
||||
aztec.getLayers(),
|
||||
);
|
||||
res = decoder::decode(&r).expect("must decode");
|
||||
assert_eq!(data, res.getText());
|
||||
}
|
||||
|
||||
@@ -582,33 +765,71 @@ Four score and seven our forefathers brought forth"#, false, 5);
|
||||
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);
|
||||
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) {
|
||||
let indata = toBitArray(bits);
|
||||
let stuffed = encoder::stuffBits(&indata, wordSize);
|
||||
assert_eq!(
|
||||
stripSpace(expected), stripSpace(stuffed.toString()),
|
||||
"stuffBits() failed for input string: {}" , bits);
|
||||
stripSpace(expected),
|
||||
stripSpace(&stuffed.to_string()),
|
||||
"stuffBits() failed for input string: {}",
|
||||
bits
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn testHighLevelEncodeString(s: &str, expectedBits: &str) {
|
||||
let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
||||
let receivedBits = stripSpace(bits.toString());
|
||||
assert_eq!( stripSpace(expectedBits), receivedBits,"highLevelEncode() failed for input string: {}" , s);
|
||||
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits)));
|
||||
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();
|
||||
let receivedBits = stripSpace(&bits.to_string());
|
||||
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(s.getBytes(StandardCharsets.ISO_8859_1)).encode().unwrap();
|
||||
let receivedBitCount = stripSpace(bits.toString()).len();
|
||||
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,
|
||||
"highLevelEncode() failed for input string: {}" , s);
|
||||
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits)));
|
||||
s
|
||||
);
|
||||
// assert_eq!(
|
||||
// expectedReceivedBits as usize, receivedBitCount,
|
||||
// "highLevelEncode() failed for input string: {}",
|
||||
// s
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -20,37 +20,37 @@ use crate::common::BitArray;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct BinaryShiftToken {
|
||||
binaryShiftStart: u32,
|
||||
binaryShiftByteCount: u32,
|
||||
binary_shift_start: u32,
|
||||
binary_shift_byte_count: u32,
|
||||
}
|
||||
|
||||
impl BinaryShiftToken {
|
||||
pub fn new(binaryShiftStart: u32, binaryShiftByteCount: u32) -> Self {
|
||||
pub fn new(binary_shift_start: u32, binary_shift_byte_count: u32) -> Self {
|
||||
Self {
|
||||
binaryShiftStart,
|
||||
binaryShiftByteCount,
|
||||
binary_shift_start,
|
||||
binary_shift_byte_count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
|
||||
let bsbc = self.binaryShiftByteCount as usize;
|
||||
pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
|
||||
let bsbc = self.binary_shift_byte_count as usize;
|
||||
for i in 0..bsbc {
|
||||
// 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
|
||||
// character 31 when the total byte code is <= 62
|
||||
bitArray.appendBits(31, 5); // BINARY_SHIFT
|
||||
if (bsbc > 62) {
|
||||
bitArray.appendBits(bsbc as u32 - 31, 16);
|
||||
} else if (i == 0) {
|
||||
bit_array.appendBits(31, 5).unwrap(); // BINARY_SHIFT
|
||||
if bsbc > 62 {
|
||||
bit_array.appendBits(bsbc as u32 - 31, 16).unwrap();
|
||||
} else if i == 0 {
|
||||
// 1 <= binaryShiftByteCode <= 62
|
||||
bitArray.appendBits(bsbc.min(31) as u32, 5);
|
||||
bit_array.appendBits(bsbc.min(31) as u32, 5).unwrap();
|
||||
} else {
|
||||
// 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!(
|
||||
f,
|
||||
"<{}::{}>",
|
||||
self.binaryShiftStart,
|
||||
(self.binaryShiftStart + self.binaryShiftByteCount - 1)
|
||||
self.binary_shift_start,
|
||||
(self.binary_shift_start + self.binary_shift_byte_count - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ pub fn encode(
|
||||
userSpecifiedLayers: u32,
|
||||
) -> Result<AztecCode, Exceptions> {
|
||||
let bytes = encoding::all::ISO_8859_1
|
||||
.encode(data, encoding::EncoderTrap::Replace)
|
||||
.unwrap();
|
||||
.encode(data, encoding::EncoderTrap::Strict)
|
||||
.expect("must encode cleanly in ISO_8859_1");
|
||||
encode_bytes(&bytes, minECCPercent, userSpecifiedLayers)
|
||||
}
|
||||
|
||||
@@ -209,6 +209,7 @@ pub fn encode_bytes_with_charset(
|
||||
layers = if compact { i + 1 } else { i };
|
||||
totalBitsInLayerVar = totalBitsInLayer(layers, compact);
|
||||
if totalSizeBits > totalBitsInLayerVar as u32 {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
// [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);
|
||||
if compact && stuffedBits.getSize() as u32 > wordSize * 64 {
|
||||
// Compact format only allows 64 data words, though C4 can hold more words than that
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
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 n = bits.getSize();
|
||||
let mask = (1 << wordSize) - 2;
|
||||
let mut i = 0;
|
||||
let n = bits.getSize() as isize;
|
||||
let mask = (1 << word_size) - 2;
|
||||
let mut i:isize = 0;
|
||||
while i < n {
|
||||
// for (int i = 0; i < n; i += wordSize) {
|
||||
let mut word = 0;
|
||||
for j in 0..wordSize {
|
||||
for j in 0..word_size as isize {
|
||||
// for (int j = 0; j < wordSize; j++) {
|
||||
if i + j >= n || bits.get(i + j) {
|
||||
word |= 1 << (wordSize - 1 - j);
|
||||
if i + j >= n || bits.get((i + j) as usize) {
|
||||
word |= 1 << (word_size as isize - 1 - j);
|
||||
}
|
||||
}
|
||||
if (word & mask) == mask {
|
||||
out.appendBits(word & mask, wordSize);
|
||||
out.appendBits(word & mask, word_size).unwrap();
|
||||
i -= 1;
|
||||
} else if (word & mask) == 0 {
|
||||
out.appendBits(word | 1, wordSize);
|
||||
out.appendBits(word | 1, word_size).unwrap();
|
||||
i -= 1;
|
||||
} else {
|
||||
out.appendBits(word, wordSize);
|
||||
out.appendBits(word, word_size).unwrap();
|
||||
}
|
||||
|
||||
i += wordSize;
|
||||
i += word_size as isize;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -125,27 +125,28 @@ impl HighLevelEncoder {
|
||||
// }
|
||||
char_map[Self::MODE_DIGIT][b',' as usize] = 12;
|
||||
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}',
|
||||
'\t', '\n', '\u{13}', '\u{f}', '\r', '\u{33}', '\u{34}', '\u{35}', '\u{36}', '\u{37}',
|
||||
'@', '\\', '^', '_', '`', '|', '~', '\u{177}',
|
||||
];
|
||||
let mut i = 0;
|
||||
while i < mixedTable.len() {
|
||||
char_map[Self::MODE_MIXED][mixedTable[i] as u8 as usize] = i as u8;
|
||||
while i < mixed_table.len() {
|
||||
char_map[Self::MODE_MIXED][mixed_table[i] as u8 as usize] = i as u8;
|
||||
i += 1;
|
||||
}
|
||||
// for (int i = 0; i < mixedTable.length; i++) {
|
||||
// CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
|
||||
// }
|
||||
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;
|
||||
while i < punctTable.len() {
|
||||
if punctTable[i] as u8 > 0u8 {
|
||||
char_map[Self::MODE_PUNCT][punctTable[i] as u8 as usize] = i as u8;
|
||||
if punctTable[i] > 0u8 {
|
||||
char_map[Self::MODE_PUNCT][punctTable[i] as usize] = i as u8;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
@@ -230,7 +231,7 @@ impl HighLevelEncoder {
|
||||
pub fn new(text: Vec<u8>) -> Self {
|
||||
Self {
|
||||
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}
|
||||
*/
|
||||
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) {
|
||||
initialState = initialState.appendFLGn(CharacterSetECI::getValue(&eci))?;
|
||||
if eci != CharacterSetECI::ISO8859_1 {
|
||||
initial_state = initial_state.appendFLGn(CharacterSetECI::getValue(&eci))?;
|
||||
}
|
||||
} else {
|
||||
return Err(Exceptions::IllegalArgumentException(
|
||||
"No ECI code for character set".to_owned(),
|
||||
@@ -257,22 +260,22 @@ impl HighLevelEncoder {
|
||||
// }
|
||||
// initialState = initialState.appendFLGn(eci.getValue());
|
||||
// }
|
||||
let mut states = vec![initialState];
|
||||
let mut states = vec![initial_state];
|
||||
let mut index = 0;
|
||||
while index < self.text.len() {
|
||||
// for index in 0..self.text.len() {
|
||||
// for (int index = 0; index < text.length; index++) {
|
||||
let pairCode;
|
||||
let nextChar = if index + 1 < self.text.len() {
|
||||
let pair_code;
|
||||
let next_char = if index + 1 < self.text.len() {
|
||||
self.text[index + 1]
|
||||
} else {
|
||||
0
|
||||
};
|
||||
pairCode = match self.text[index] {
|
||||
b'\r' if nextChar == b'\n' => 2,
|
||||
b'.' if nextChar == b' ' => 3,
|
||||
b',' if nextChar == b' ' => 4,
|
||||
b':' if nextChar == b' ' => 5,
|
||||
pair_code = match self.text[index] {
|
||||
b'\r' if next_char == b'\n' => 2,
|
||||
b'.' if next_char == b' ' => 3,
|
||||
b',' if next_char == b' ' => 4,
|
||||
b':' if next_char == b' ' => 5,
|
||||
_ => 0,
|
||||
};
|
||||
// switch (text[index]) {
|
||||
@@ -291,19 +294,24 @@ impl HighLevelEncoder {
|
||||
// default:
|
||||
// pairCode = 0;
|
||||
// }
|
||||
if pairCode > 0 {
|
||||
if pair_code > 0 {
|
||||
// We have one of the four special PUNCT pairs. Treat them specially.
|
||||
// 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;
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// for state in &states {
|
||||
// dbg!(state.clone().toBitArray(&self.text).to_string());
|
||||
// }
|
||||
|
||||
// We are left with a set of states. Find the shortest one.
|
||||
let minState = states
|
||||
let min_state = states
|
||||
.into_iter()
|
||||
.min_by(|a, b| {
|
||||
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.
|
||||
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
|
||||
// for the new character, merging the results, and then removing the
|
||||
// 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();
|
||||
for state in 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
|
||||
// state for the next character. The resulting set of states are added to
|
||||
// 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 charInCurrentTable = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0;
|
||||
let mut stateNoBinary = None;
|
||||
for mode in 0..Self::MODE_PUNCT {
|
||||
let char_in_current_table = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0;
|
||||
let mut state_no_binary = None;
|
||||
for mode in 0..=Self::MODE_PUNCT {
|
||||
// for (int mode = 0; mode <= MODE_PUNCT; mode++) {
|
||||
let charInMode = Self::CHAR_MAP[mode as usize][ch as usize];
|
||||
if charInMode > 0 {
|
||||
if stateNoBinary.is_none() {
|
||||
let char_in_mode = Self::CHAR_MAP[mode as usize][ch as usize];
|
||||
if char_in_mode > 0 {
|
||||
if state_no_binary.is_none() {
|
||||
// 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
|
||||
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
|
||||
// any other mode except possibly digit (which uses only 4 bits). Any
|
||||
// other latch would be equally successful *after* this character, and
|
||||
// so wouldn't save any bits.
|
||||
let latchState = stateNoBinary
|
||||
let latch_state = state_no_binary
|
||||
.clone()
|
||||
.unwrap()
|
||||
.latchAndAppend(mode as u32, charInMode as u32);
|
||||
result.push(latchState);
|
||||
.latchAndAppend(mode as u32, char_in_mode as u32);
|
||||
result.push(latch_state);
|
||||
}
|
||||
// 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
|
||||
// character exists in the current mode. That can never save bits.
|
||||
let shiftState = stateNoBinary
|
||||
let shift_state = state_no_binary
|
||||
.clone()
|
||||
.unwrap()
|
||||
.shiftAndAppend(mode as u32, charInMode as u32);
|
||||
result.push(shiftState);
|
||||
.shiftAndAppend(mode as u32, char_in_mode as u32);
|
||||
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
|
||||
// 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.
|
||||
let binaryState = state.addBinaryShiftChar(index);
|
||||
result.push(binaryState);
|
||||
let binary_state = state.addBinaryShiftChar(index);
|
||||
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();
|
||||
for state in 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>) {
|
||||
let stateNoBinary = state.clone().endBinaryShift(index);
|
||||
fn update_state_for_pair(state: State, index: u32, pair_code: u32, result: &mut Vec<State>) {
|
||||
let state_no_binary = state.clone().endBinaryShift(index);
|
||||
// Possibility 1. Latch to MODE_PUNCT, and then append this code
|
||||
result.push(
|
||||
stateNoBinary
|
||||
state_no_binary
|
||||
.clone()
|
||||
.latchAndAppend(Self::MODE_PUNCT as u32, pairCode),
|
||||
.latchAndAppend(Self::MODE_PUNCT as u32, pair_code),
|
||||
);
|
||||
if state.getMode() != Self::MODE_PUNCT as u32 {
|
||||
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
|
||||
// Every state except MODE_PUNCT (handled above) can shift
|
||||
result.push(
|
||||
stateNoBinary
|
||||
state_no_binary
|
||||
.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
|
||||
let digitState = stateNoBinary
|
||||
.latchAndAppend(Self::MODE_DIGIT as u32, 16 - pairCode) // period or comma in DIGIT
|
||||
let digit_state = state_no_binary
|
||||
.latchAndAppend(Self::MODE_DIGIT as u32, 16 - pair_code) // period or comma in DIGIT
|
||||
.latchAndAppend(Self::MODE_DIGIT as u32, 1); // space in DIGIT
|
||||
result.push(digitState);
|
||||
result.push(digit_state);
|
||||
}
|
||||
if state.getBinaryShiftByteCount() > 0 {
|
||||
// It only makes sense to do the characters as binary if we're already
|
||||
// in binary mode.
|
||||
let binaryState = state
|
||||
let binary_state = state
|
||||
.addBinaryShiftChar(index)
|
||||
.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();
|
||||
for newState in states {
|
||||
// for (State newState : states) {
|
||||
@@ -442,7 +453,7 @@ impl HighLevelEncoder {
|
||||
for i in 0..result.len() {
|
||||
// for st in result {
|
||||
// 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) {
|
||||
add = false;
|
||||
break;
|
||||
@@ -451,6 +462,7 @@ impl HighLevelEncoder {
|
||||
result.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if add {
|
||||
result.push(newState);
|
||||
}
|
||||
|
||||
@@ -22,20 +22,20 @@ use crate::common::BitArray;
|
||||
pub struct SimpleToken {
|
||||
// For normal words, indicates value and bitCount
|
||||
value: u16,
|
||||
bitCount: u16,
|
||||
bit_count: u16,
|
||||
}
|
||||
|
||||
impl SimpleToken {
|
||||
pub fn new(value: i32, bitCount: u32) -> Self {
|
||||
Self {
|
||||
value: value as u16,
|
||||
bitCount: bitCount as u16,
|
||||
bit_count: bitCount as u16,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
|
||||
bitArray
|
||||
.appendBits(self.value as u32, self.bitCount as usize)
|
||||
pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
|
||||
bit_array
|
||||
.appendBits(self.value as u32, self.bit_count as usize)
|
||||
.expect("append should never fail");
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ impl SimpleToken {
|
||||
|
||||
impl fmt::Display for SimpleToken {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut value = self.value & ((1 << self.bitCount) - 1);
|
||||
value |= 1 << self.bitCount;
|
||||
write!(f, "<{:#016b}>", value | (1 << self.bitCount))
|
||||
let mut value = self.value & ((1 << self.bit_count) - 1);
|
||||
value |= 1 << self.bit_count;
|
||||
write!(f, "<{:#016b}>", value | (1 << self.bit_count))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,19 +38,19 @@ pub struct State {
|
||||
token: Token,
|
||||
// If non-zero, the number of most recent bytes that should be output
|
||||
// in Binary Shift mode.
|
||||
binaryShiftByteCount: u32,
|
||||
binary_shift_byte_count: u32,
|
||||
// The total number of bits generated (including Binary Shift).
|
||||
bitCount: u32,
|
||||
binaryShiftCost: u32,
|
||||
bit_count: u32,
|
||||
binary_shift_cost: u32,
|
||||
}
|
||||
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 {
|
||||
mode,
|
||||
token,
|
||||
binaryShiftByteCount: binaryBytes,
|
||||
bitCount,
|
||||
binaryShiftCost: Self::calculateBinaryShiftCost(binaryBytes),
|
||||
binary_shift_byte_count: binary_bytes,
|
||||
bit_count,
|
||||
binary_shift_cost: Self::calculate_binary_shift_cost(binary_bytes),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,19 +63,19 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn getBinaryShiftByteCount(&self) -> u32 {
|
||||
self.binaryShiftByteCount
|
||||
self.binary_shift_byte_count
|
||||
}
|
||||
|
||||
pub fn getBitCount(&self) -> u32 {
|
||||
self.bitCount
|
||||
self.bit_count
|
||||
}
|
||||
|
||||
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 result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT as u32, 0); // 0: FLG(n)
|
||||
let mut token = result.token;
|
||||
let mut bitsAdded = 3;
|
||||
let mut bits_added = 3;
|
||||
if eci < 0 {
|
||||
token.add(0, 3); // 0: FNC1
|
||||
} else if eci > 999999 {
|
||||
@@ -84,25 +84,25 @@ impl State {
|
||||
));
|
||||
// throw new IllegalArgumentException("ECI code must be between 0 and 999999");
|
||||
} else {
|
||||
let eciDigits = encoding::all::ISO_8859_1
|
||||
let eci_digits = encoding::all::ISO_8859_1
|
||||
.encode(&format!("{}", eci), encoding::EncoderTrap::Replace)
|
||||
.unwrap();
|
||||
// let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
|
||||
token.add(eciDigits.len() as i32, 3); // 1-6: number of ECI digits
|
||||
for eciDigit in &eciDigits {
|
||||
token.add(eci_digits.len() as i32, 3); // 1-6: number of ECI digits
|
||||
for eci_digit in &eci_digits {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Create a new state representing this state with a latch to a (not
|
||||
// necessary different) mode, and then a code.
|
||||
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;
|
||||
if mode != self.mode {
|
||||
let latch = HighLevelEncoder::LATCH_TABLE[self.mode as usize][mode as usize];
|
||||
@@ -134,7 +134,7 @@ impl State {
|
||||
thisModeBitCount,
|
||||
);
|
||||
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
|
||||
@@ -142,7 +142,7 @@ impl State {
|
||||
pub fn addBinaryShiftChar(self, index: u32) -> State {
|
||||
let mut token = self.token;
|
||||
let mut mode = self.mode;
|
||||
let mut bitCount = self.bitCount;
|
||||
let mut bitCount = self.bit_count;
|
||||
if self.mode == HighLevelEncoder::MODE_PUNCT as u32
|
||||
|| self.mode == HighLevelEncoder::MODE_DIGIT as u32
|
||||
{
|
||||
@@ -151,10 +151,10 @@ impl State {
|
||||
bitCount += latch >> 16;
|
||||
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
|
||||
} else {
|
||||
if self.binaryShiftByteCount == 62 {
|
||||
if self.binary_shift_byte_count == 62 {
|
||||
9
|
||||
} else {
|
||||
8
|
||||
@@ -163,10 +163,10 @@ impl State {
|
||||
let mut result = State::new(
|
||||
token,
|
||||
mode,
|
||||
self.binaryShiftByteCount + 1,
|
||||
self.binary_shift_byte_count + 1,
|
||||
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.
|
||||
result = result.endBinaryShift(index + 1);
|
||||
}
|
||||
@@ -176,30 +176,30 @@ impl State {
|
||||
// Create the state identical to this one, but we are no longer in
|
||||
// Binary Shift mode.
|
||||
pub fn endBinaryShift(self, index: u32) -> State {
|
||||
if self.binaryShiftByteCount == 0 {
|
||||
if self.binary_shift_byte_count == 0 {
|
||||
return self;
|
||||
}
|
||||
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"
|
||||
// state under all possible circumstances.
|
||||
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);
|
||||
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
|
||||
newModeBitCount += other.binaryShiftCost - self.binaryShiftCost;
|
||||
} else if self.binaryShiftByteCount > other.binaryShiftByteCount
|
||||
&& other.binaryShiftByteCount > 0
|
||||
new_mode_bit_count += other.binary_shift_cost - self.binary_shift_cost;
|
||||
} else if self.binary_shift_byte_count > other.binary_shift_byte_count
|
||||
&& 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)
|
||||
newModeBitCount += 10;
|
||||
new_mode_bit_count += 10;
|
||||
}
|
||||
newModeBitCount <= other.bitCount
|
||||
new_mode_bit_count <= other.bit_count
|
||||
}
|
||||
|
||||
pub fn toBitArray(self, text: &[u8]) -> BitArray {
|
||||
@@ -215,28 +215,24 @@ impl State {
|
||||
// symbols.push(tkn);
|
||||
// tkn = tok.getPrevious();
|
||||
// }
|
||||
let mut bitArray = BitArray::new();
|
||||
let mut bit_array = BitArray::new();
|
||||
// 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--) {
|
||||
symbols.get(i).unwrap().appendTo(&mut bitArray, text);
|
||||
symbol.appendTo(&mut bit_array, text);
|
||||
}
|
||||
bitArray
|
||||
bit_array
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return String.format("%s bits=%d bytes=%d", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
|
||||
// }
|
||||
|
||||
fn calculateBinaryShiftCost(binaryShiftByteCount: u32) -> u32 {
|
||||
if binaryShiftByteCount > 62 {
|
||||
fn calculate_binary_shift_cost(binary_shift_byte_count: u32) -> u32 {
|
||||
if binary_shift_byte_count > 62 {
|
||||
return 21; // B/S with extended length
|
||||
}
|
||||
if binaryShiftByteCount > 31 {
|
||||
if binary_shift_byte_count > 31 {
|
||||
return 20; // two B/S
|
||||
}
|
||||
if binaryShiftByteCount > 0 {
|
||||
if binary_shift_byte_count > 0 {
|
||||
return 10; // one B/S
|
||||
}
|
||||
return 0;
|
||||
@@ -249,8 +245,8 @@ impl fmt::Display for State {
|
||||
f,
|
||||
"{} bits={} bytes={}",
|
||||
HighLevelEncoder::MODE_NAMES[self.mode as usize],
|
||||
self.bitCount,
|
||||
self.binaryShiftByteCount
|
||||
self.bit_count,
|
||||
self.binary_shift_byte_count
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ pub fn toBitArray( bits:&str) -> BitArray{
|
||||
let mut ba_in = BitArray::new();
|
||||
let replacer_regex = Regex::new(DOTX).unwrap();
|
||||
let str = replacer_regex.replace_all(bits, "");
|
||||
for aStr in str.chars() {
|
||||
for a_str in str.chars() {
|
||||
// for (char aStr : str) {
|
||||
ba_in.appendBit(aStr == 'X');
|
||||
ba_in.appendBit(a_str == 'X');
|
||||
}
|
||||
|
||||
ba_in
|
||||
|
||||
@@ -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]
|
||||
fn test_set_range() {
|
||||
let mut array = BitArray::with_size(64);
|
||||
|
||||
@@ -552,14 +552,19 @@ impl BitArray {
|
||||
* @param numBits bits from value to append
|
||||
*/
|
||||
pub fn appendBits(&mut self, value: u32, numBits: usize) -> Result<(), Exceptions> {
|
||||
if numBits < 0 || numBits > 32 {
|
||||
if numBits > 32 {
|
||||
return Err(Exceptions::IllegalArgumentException(
|
||||
"Num bits must be between 0 and 32".to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
if numBits == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut nextSize = self.size;
|
||||
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--) {
|
||||
if (value & (1 << numBitsLeft)) != 0 {
|
||||
self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F);
|
||||
@@ -720,7 +725,6 @@ impl fmt::Display for BitArray {
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub trait DetectorRXingResult {
|
||||
|
||||
fn getBits(&self) -> &BitMatrix;
|
||||
|
||||
fn getPoints(&self) -> &Vec<RXingResultPoint>;
|
||||
@@ -841,25 +845,25 @@ impl BitMatrix {
|
||||
}
|
||||
|
||||
pub fn parse_strings(
|
||||
stringRepresentation: &str,
|
||||
setString: &str,
|
||||
unsetString: &str,
|
||||
string_representation: &str,
|
||||
set_string: &str,
|
||||
unset_string: &str,
|
||||
) -> Result<Self, Exceptions> {
|
||||
// cannot pass nulls in rust
|
||||
// if (stringRepresentation == null) {
|
||||
// throw new IllegalArgumentException();
|
||||
// }
|
||||
|
||||
let mut bits = vec![false; stringRepresentation.len()];
|
||||
let mut bits = vec![false; string_representation.len()];
|
||||
let mut bitsPos = 0;
|
||||
let mut rowStartPos = 0;
|
||||
let mut rowLength = 0; //-1;
|
||||
let mut first_run = true;
|
||||
let mut nRows = 0;
|
||||
let mut pos = 0;
|
||||
while pos < stringRepresentation.len() {
|
||||
if stringRepresentation.chars().nth(pos).unwrap() == '\n'
|
||||
|| stringRepresentation.chars().nth(pos).unwrap() == '\r'
|
||||
while pos < string_representation.len() {
|
||||
if string_representation.chars().nth(pos).unwrap() == '\n'
|
||||
|| string_representation.chars().nth(pos).unwrap() == '\r'
|
||||
{
|
||||
if bitsPos > rowStartPos {
|
||||
//if rowLength == -1 {
|
||||
@@ -875,18 +879,18 @@ impl BitMatrix {
|
||||
nRows += 1;
|
||||
}
|
||||
pos += 1;
|
||||
} else if stringRepresentation[pos..].starts_with(setString) {
|
||||
pos += setString.len();
|
||||
} else if string_representation[pos..].starts_with(set_string) {
|
||||
pos += set_string.len();
|
||||
bits[bitsPos] = true;
|
||||
bitsPos += 1;
|
||||
} else if stringRepresentation[pos..].starts_with(unsetString) {
|
||||
pos += unsetString.len();
|
||||
} else if string_representation[pos..].starts_with(unset_string) {
|
||||
pos += unset_string.len();
|
||||
bits[bitsPos] = false;
|
||||
bitsPos += 1;
|
||||
} else {
|
||||
return Err(Exceptions::IllegalArgumentException(format!(
|
||||
"illegal character encountered: {}",
|
||||
stringRepresentation[pos..].to_owned()
|
||||
string_representation[pos..].to_owned()
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -975,7 +979,8 @@ impl BitMatrix {
|
||||
* @param mask XOR mask
|
||||
*/
|
||||
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(
|
||||
"input matrix dimensions do not match".to_owned(),
|
||||
));
|
||||
@@ -2398,6 +2403,7 @@ impl GridSampler for DefaultGridSampler {
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum CharacterSetECI {
|
||||
// Enum name is a Java encoding valid for java.lang and java.io
|
||||
Cp437, //(new int[]{0,2}),
|
||||
@@ -2531,34 +2537,34 @@ impl CharacterSetECI {
|
||||
* but unsupported
|
||||
*/
|
||||
pub fn getCharacterSetECI(charset: &'static dyn Encoding) -> Option<CharacterSetECI> {
|
||||
match charset.whatwg_name().unwrap() {
|
||||
match charset.name() {
|
||||
"CP437" => Some(CharacterSetECI::Cp437),
|
||||
"ISO-8859-1" => Some(CharacterSetECI::ISO8859_1),
|
||||
"ISO-8859-2" => Some(CharacterSetECI::ISO8859_2),
|
||||
"ISO-8859-3" => Some(CharacterSetECI::ISO8859_3),
|
||||
"ISO-8859-4" => Some(CharacterSetECI::ISO8859_4),
|
||||
"ISO-8859-5" => Some(CharacterSetECI::ISO8859_5),
|
||||
"ISO-8859-6" => Some(CharacterSetECI::ISO8859_6),
|
||||
"ISO-8859-7" => Some(CharacterSetECI::ISO8859_7),
|
||||
"ISO-8859-8" => Some(CharacterSetECI::ISO8859_8),
|
||||
"ISO-8859-9" => Some(CharacterSetECI::ISO8859_9),
|
||||
"ISO-8859-10" => Some(CharacterSetECI::ISO8859_10),
|
||||
"ISO-8859-11" => Some(CharacterSetECI::ISO8859_11),
|
||||
"ISO-8859-13" => Some(CharacterSetECI::ISO8859_13),
|
||||
"ISO-8859-14" => Some(CharacterSetECI::ISO8859_14),
|
||||
"ISO-8859-15" => Some(CharacterSetECI::ISO8859_15),
|
||||
"ISO-8859-16" => Some(CharacterSetECI::ISO8859_16),
|
||||
"Shift_JIS" => Some(CharacterSetECI::SJIS),
|
||||
"iso-8859-1" => Some(CharacterSetECI::ISO8859_1),
|
||||
"iso-8859-2" => Some(CharacterSetECI::ISO8859_2),
|
||||
"iso-8859-3" => Some(CharacterSetECI::ISO8859_3),
|
||||
"iso-8859-4" => Some(CharacterSetECI::ISO8859_4),
|
||||
"iso-8859-5" => Some(CharacterSetECI::ISO8859_5),
|
||||
"iso-8859-6" => Some(CharacterSetECI::ISO8859_6),
|
||||
"iso-8859-7" => Some(CharacterSetECI::ISO8859_7),
|
||||
"iso-8859-8" => Some(CharacterSetECI::ISO8859_8),
|
||||
"iso-8859-9" => Some(CharacterSetECI::ISO8859_9),
|
||||
"iso-8859-10" => Some(CharacterSetECI::ISO8859_10),
|
||||
"iso-8859-11" => Some(CharacterSetECI::ISO8859_11),
|
||||
"iso-8859-13" => Some(CharacterSetECI::ISO8859_13),
|
||||
"iso-8859-14" => Some(CharacterSetECI::ISO8859_14),
|
||||
"iso-8859-15" => Some(CharacterSetECI::ISO8859_15),
|
||||
"iso-8859-16" => Some(CharacterSetECI::ISO8859_16),
|
||||
"shift_jis" => Some(CharacterSetECI::SJIS),
|
||||
"windows-1250" => Some(CharacterSetECI::Cp1250),
|
||||
"windows-1251" => Some(CharacterSetECI::Cp1251),
|
||||
"windows-1252" => Some(CharacterSetECI::Cp1252),
|
||||
"windows-1256" => Some(CharacterSetECI::Cp1256),
|
||||
"UTF-16BE" => Some(CharacterSetECI::UnicodeBigUnmarked),
|
||||
"UTF-8" => Some(CharacterSetECI::UTF8),
|
||||
"US-ASCII" => Some(CharacterSetECI::ASCII),
|
||||
"Big5" => Some(CharacterSetECI::Big5),
|
||||
"GB2312" => Some(CharacterSetECI::GB18030),
|
||||
"EUC-KR" => Some(CharacterSetECI::EUC_KR),
|
||||
"utf-16be" => Some(CharacterSetECI::UnicodeBigUnmarked),
|
||||
"utf-8" => Some(CharacterSetECI::UTF8),
|
||||
"us-ascii" => Some(CharacterSetECI::ASCII),
|
||||
"big5" => Some(CharacterSetECI::Big5),
|
||||
"gb2312" => Some(CharacterSetECI::GB18030),
|
||||
"euc-kr" => Some(CharacterSetECI::EUC_KR),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -4052,6 +4058,9 @@ impl HybridBinarizer {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user