From ac907832afb52d7545c9d30576264be9c83ce3c9 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sat, 27 Aug 2022 17:59:34 -0500 Subject: [PATCH] consider removing inverted --- src/common/mod.rs | 219 ++++++++++-------- .../reedsolomon/GenericGFPolyTestCase.rs | 22 +- src/common/reedsolomon/ReedSolomonTestCase.rs | 65 +++--- src/common/reedsolomon/mod.rs | 133 ++++++----- src/lib.rs | 194 +++++++--------- 5 files changed, 344 insertions(+), 289 deletions(-) diff --git a/src/common/mod.rs b/src/common/mod.rs index cbf12f2..b682cfa 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,7 @@ pub mod detector; pub mod reedsolomon; +use core::num; use std::cmp; use std::collections::HashMap; use std::fmt; @@ -52,12 +53,12 @@ pub struct StringUtils { // public static final String GB2312 = "GB2312"; } -const PLATFORM_DEFAULT_ENCODING: &dyn Encoding = encoding::all::UTF_8; -const SHIFT_JIS_CHARSET: &dyn Encoding = - encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); -const GB2312_CHARSET: &dyn Encoding = - encoding::label::encoding_from_whatwg_label("GB2312").unwrap(); -const EUC_JP: &dyn Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP").unwrap(); +// const PLATFORM_DEFAULT_ENCODING: &dyn Encoding = encoding::all::UTF_8; +// const SHIFT_JIS_CHARSET: &dyn Encoding = +// encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); +// const GB2312_CHARSET: &dyn Encoding = +// encoding::label::encoding_from_whatwg_label("GB2312").unwrap(); +// const EUC_JP: &dyn Encoding = encoding::label::encoding_from_whatwg_label("EUC_JP").unwrap(); const ASSUME_SHIFT_JIS: bool = false; static SHIFT_JIS: &'static str = "SJIS"; static GB2312: &'static str = "GB2312"; @@ -76,7 +77,11 @@ impl StringUtils { */ pub fn guessEncoding(bytes: &[u8], hints: HashMap) -> String { let c = StringUtils::guessCharset(bytes, hints); - if c.name() == SHIFT_JIS_CHARSET.name() { + if c.name() + == encoding::label::encoding_from_whatwg_label("SJIS") + .unwrap() + .name() + { return "SJIS".to_owned(); } else if c.name() == encoding::all::UTF_8.name() { return "UTF8".to_owned(); @@ -119,20 +124,20 @@ impl StringUtils { // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, // which should be by far the most common encodings. let length = bytes.len(); - let canBeISO88591 = true; - let canBeShiftJIS = true; - let canBeUTF8 = true; - let utf8BytesLeft = 0; - let utf2BytesChars = 0; - let utf3BytesChars = 0; - let utf4BytesChars = 0; - let sjisBytesLeft = 0; - let sjisKatakanaChars = 0; - let sjisCurKatakanaWordLength = 0; - let sjisCurDoubleBytesWordLength = 0; - let sjisMaxKatakanaWordLength = 0; - let sjisMaxDoubleBytesWordLength = 0; - let isoHighOther = 0; + let mut canBeISO88591 = true; + let mut canBeShiftJIS = true; + let mut canBeUTF8 = true; + let mut utf8BytesLeft = 0; + let mut utf2BytesChars = 0; + let mut utf3BytesChars = 0; + let mut utf4BytesChars = 0; + let mut sjisBytesLeft = 0; + let mut sjisKatakanaChars = 0; + let mut sjisCurKatakanaWordLength = 0; + let mut sjisCurDoubleBytesWordLength = 0; + let mut sjisMaxKatakanaWordLength = 0; + let mut sjisMaxDoubleBytesWordLength = 0; + let mut isoHighOther = 0; let utf8bom = bytes.len() > 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF; @@ -237,7 +242,7 @@ impl StringUtils { || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3) { - return SHIFT_JIS_CHARSET; + return encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); } // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short words. The crude heuristic is: // - If we saw @@ -248,7 +253,7 @@ impl StringUtils { return if (sjisMaxKatakanaWordLength == 2 && sjisKatakanaChars == 2) || isoHighOther * 10 >= length { - SHIFT_JIS_CHARSET + encoding::label::encoding_from_whatwg_label("SJIS").unwrap() } else { encoding::all::ISO_8859_1 }; @@ -259,13 +264,13 @@ impl StringUtils { return encoding::all::ISO_8859_1; } if canBeShiftJIS { - return SHIFT_JIS_CHARSET; + return encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); } if canBeUTF8 { return encoding::all::UTF_8; } // Otherwise, we take a wild guess with platform encoding - return PLATFORM_DEFAULT_ENCODING; + return encoding::all::UTF_8; } } @@ -334,9 +339,9 @@ impl BitArray { return (self.size + 7) / 8; } - fn ensureCapacity(&self, newSize: usize) { + fn ensureCapacity(&mut self, newSize: usize) { if newSize > self.bits.len() * 32 { - let newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil() as usize); + let mut newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil() as usize); //System.arraycopy(bits, 0, newBits, 0, bits.length); newBits[0..self.bits.len()].clone_from_slice(&self.bits[0..self.bits.len()]); self.bits = newBits; @@ -356,7 +361,7 @@ impl BitArray { * * @param i bit to set */ - pub fn set(&self, i: usize) { + pub fn set(&mut self, i: usize) { self.bits[i / 32] |= 1 << (i & 0x1F); } @@ -365,7 +370,7 @@ impl BitArray { * * @param i bit to set */ - pub fn flip(&self, i: usize) { + pub fn flip(&mut self, i: usize) { self.bits[i / 32] ^= 1 << (i & 0x1F); } @@ -379,7 +384,7 @@ impl BitArray { if from >= self.size { return self.size; } - let bitsOffset = from / 32; + let mut bitsOffset = from / 32; let mut currentBits = self.bits[bitsOffset] as i32; // mask off lesser bits first currentBits &= -(1 << (from & 0x1F)); @@ -403,10 +408,10 @@ impl BitArray { if from >= self.size { return self.size; } - let bitsOffset = from / 32; - let currentBits = !self.bits[bitsOffset] as i32; + let mut bitsOffset = from / 32; + let mut currentBits = !self.bits[bitsOffset] as i32; // mask off lesser bits first - currentBits &= -(1 << (from & 0x1F)) ; + currentBits &= -(1 << (from & 0x1F)); while currentBits == 0 { bitsOffset += 1; if bitsOffset == self.bits.len() { @@ -425,7 +430,7 @@ impl BitArray { * @param newBits the new value of the next 32 bits. Note again that the least-significant bit * corresponds to bit i, the next-least-significant to i+1, and so on. */ - pub fn setBulk(&self, i: usize, newBits: u32) { + pub fn setBulk(&mut self, i: usize, newBits: u32) { self.bits[i / 32] = newBits; } @@ -435,7 +440,8 @@ impl BitArray { * @param start start of range, inclusive. * @param end end of range, exclusive */ - pub fn setRange(&self, start: usize, end: usize) -> Result<(), IllegalArgumentException> { + pub fn setRange(&mut self, start: usize, end: usize) -> Result<(), IllegalArgumentException> { + let mut end = end; if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new( "end < start || start < 0 || end > self.size", @@ -461,7 +467,7 @@ impl BitArray { /** * Clears all bits (sets to false). */ - pub fn clear(&self) { + pub fn clear(&mut self) { let max = self.bits.len(); for i in 0..max { //for (int i = 0; i < max; i++) { @@ -484,6 +490,7 @@ impl BitArray { end: usize, value: bool, ) -> Result { + let mut end = end; if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new( "end < start || start < 0 || end > self.size", @@ -511,7 +518,7 @@ impl BitArray { return Ok(true); } - pub fn appendBit(&self, bit: bool) { + pub fn appendBit(&mut self, bit: bool) { self.ensureCapacity(self.size + 1); if bit { self.bits[self.size / 32] |= 1 << (self.size & 0x1F); @@ -527,13 +534,17 @@ impl BitArray { * @param value {@code int} containing bits to append * @param numBits bits from value to append */ - pub fn appendBits(&self, value: u32, numBits: usize) -> Result<(), IllegalArgumentException> { + pub fn appendBits( + &mut self, + value: u32, + numBits: usize, + ) -> Result<(), IllegalArgumentException> { if numBits < 0 || numBits > 32 { return Err(IllegalArgumentException::new( "Num bits must be between 0 and 32", )); } - let nextSize = self.size; + let mut nextSize = self.size; self.ensureCapacity(nextSize + numBits); for numBitsLeft in (0..(numBits - 1)).rev() { //for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) { @@ -546,7 +557,7 @@ impl BitArray { Ok(()) } - pub fn appendBitArray(&self, other: BitArray) { + pub fn appendBitArray(&mut self, other: BitArray) { let otherSize = other.size; self.ensureCapacity(self.size + otherSize); for i in 0..otherSize { @@ -555,7 +566,7 @@ impl BitArray { } } - pub fn xor(&self, other: &BitArray) -> Result<(), IllegalArgumentException> { + pub fn xor(&mut self, other: &BitArray) -> Result<(), IllegalArgumentException> { if self.size != other.size { return Err(IllegalArgumentException::new("Sizes don't match")); } @@ -577,9 +588,10 @@ impl BitArray { * @param numBytes how many bytes to write */ pub fn toBytes(&self, bitOffset: usize, array: &mut [u8], offset: usize, numBytes: usize) { + let mut bitOffset = bitOffset; for i in 0..numBytes { //for (int i = 0; i < numBytes; i++) { - let theByte = 0; + let mut theByte = 0; for j in 0..8 { //for (int j = 0; j < 8; j++) { if self.get(bitOffset) { @@ -595,15 +607,15 @@ impl BitArray { * @return underlying array of ints. The first element holds the first 32 bits, and the least * significant bit is bit 0. */ - pub fn getBitArray(&self) -> Vec { - return self.bits; + pub fn getBitArray(&self) -> &Vec { + return &self.bits; } /** * Reverses all bits in the array. */ - pub fn reverse(&self) { - let newBits = Vec::with_capacity(self.bits.len()); + pub fn reverse(&mut self) { + let mut newBits = Vec::with_capacity(self.bits.len()); // reverse all int's first let len = (self.size - 1) / 32; let oldBitsLen = len + 1; @@ -614,7 +626,7 @@ impl BitArray { // now correct the int's if the bit size isn't a multiple of 32 if self.size != oldBitsLen * 32 { let leftOffset = oldBitsLen * 32 - self.size; - let currentInt = newBits[0] >> leftOffset; + let mut currentInt = newBits[0] >> leftOffset; for i in 1..oldBitsLen { //for (int i = 1; i < oldBitsLen; i++) { let nextInt = newBits[i]; @@ -653,7 +665,7 @@ impl BitArray { impl fmt::Display for BitArray { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let _str = String::with_capacity(self.size + (self.size / 8) + 1); + let mut _str = String::with_capacity(self.size + (self.size / 8) + 1); for i in 0..self.size { //for (int i = 0; i < size; i++) { if (i & 0x07) == 0 { @@ -705,12 +717,12 @@ impl DetectorRXingResult { } } - pub fn getBits(&self) -> BitMatrix { - return self.bits; + pub fn getBits(&self) -> &BitMatrix { + return &self.bits; } - pub fn getPoints(&self) -> Vec { - return self.points; + pub fn getPoints(&self) -> &Vec { + return &self.points; } } @@ -809,10 +821,10 @@ impl BitMatrix { pub fn parse_bools(image: &Vec>) -> Self { let height: u32 = image.len().try_into().unwrap(); let width: u32 = image[0].len().try_into().unwrap(); - let bits = BitMatrix::new(width, height).unwrap(); + let mut bits = BitMatrix::new(width, height).unwrap(); for i in 0..height as usize { //for (int i = 0; i < height; i++) { - let imageI = image[i]; + let imageI = &image[i]; for j in 0..width as usize { //for (int j = 0; j < width; j++) { if imageI[j] { @@ -833,15 +845,16 @@ impl BitMatrix { // throw new IllegalArgumentException(); // } - let bits = Vec::with_capacity(stringRepresentation.len()); - let bitsPos = 0; - let rowStartPos = 0; - let rowLength = 0;//-1; + let mut bits = Vec::with_capacity(stringRepresentation.len()); + let mut bitsPos = 0; + let mut rowStartPos = 0; + let mut rowLength = 0; //-1; let mut first_run = true; - let nRows = 0; - let pos = 0; + 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' + if stringRepresentation.chars().nth(pos).unwrap() == '\n' + || stringRepresentation.chars().nth(pos).unwrap() == '\r' { if bitsPos > rowStartPos { //if rowLength == -1 { @@ -883,11 +896,14 @@ impl BitMatrix { nRows += 1; } - let matrix = BitMatrix::new(rowLength.try_into().unwrap(), nRows)?; + let mut matrix = BitMatrix::new(rowLength.try_into().unwrap(), nRows)?; for i in 0..bitsPos { //for (int i = 0; i < bitsPos; i++) { if bits[i] { - matrix.set((i % rowLength).try_into().unwrap(), (i / rowLength).try_into().unwrap()); + matrix.set( + (i % rowLength).try_into().unwrap(), + (i / rowLength).try_into().unwrap(), + ); } } return Ok(matrix); @@ -911,12 +927,12 @@ impl BitMatrix { * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ - pub fn set(&self, x: u32, y: u32) { + pub fn set(&mut self, x: u32, y: u32) { let offset = y as usize * self.rowSize + (x as usize / 32); self.bits[offset] |= 1 << (x & 0x1f); } - pub fn unset(&self, x: u32, y: u32) { + pub fn unset(&mut self, x: u32, y: u32) { let offset = y as usize * self.rowSize + (x as usize / 32); self.bits[offset] &= !(1 << (x & 0x1f)); } @@ -927,7 +943,7 @@ impl BitMatrix { * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ - pub fn flip_coords(&self, x: u32, y: u32) { + pub fn flip_coords(&mut self, x: u32, y: u32) { let offset = y as usize * self.rowSize + (x as usize / 32); self.bits[offset] ^= 1 << (x & 0x1f); } @@ -935,7 +951,7 @@ impl BitMatrix { /** *

Flips every bit in the matrix.

*/ - pub fn flip_self(&self) { + pub fn flip_self(&mut self) { let max = self.bits.len(); for i in 0..max { //for (int i = 0; i < max; i++) { @@ -949,7 +965,7 @@ impl BitMatrix { * * @param mask XOR mask */ - pub fn xor(&self, mask: &BitMatrix) -> Result<(), IllegalArgumentException> { + pub fn xor(&mut self, mask: &BitMatrix) -> Result<(), IllegalArgumentException> { if self.width != mask.width || self.height != mask.height || self.rowSize != mask.rowSize { return Err(IllegalArgumentException::new( "input matrix dimensions do not match", @@ -959,7 +975,8 @@ impl BitMatrix { for y in 0..self.height { //for (int y = 0; y < height; y++) { let offset = y as usize * self.rowSize; - let row = mask.getRow(y, &rowArray).getBitArray(); + let tmp = mask.getRow(y, &rowArray); + let row = tmp.getBitArray(); for x in 0..self.rowSize { //for (int x = 0; x < rowSize; x++) { self.bits[offset + x] ^= row[x]; @@ -971,7 +988,7 @@ impl BitMatrix { /** * Clears all bits (sets to false). */ - pub fn clear(&self) { + pub fn clear(&mut self) { let max = self.bits.len(); for i in 0..max { //for (int i = 0; i < max; i++) { @@ -988,7 +1005,7 @@ impl BitMatrix { * @param height The height of the region */ pub fn setRegion( - &self, + &mut self, left: u32, top: u32, width: u32, @@ -1013,7 +1030,7 @@ impl BitMatrix { } for y in top..bottom { //for (int y = top; y < bottom; y++) { - let offset = y as usize* self.rowSize; + let offset = y as usize * self.rowSize; for x in left..right { //for (int x = left; x < right; x++) { self.bits[offset + (x as usize / 32)] |= 1 << (x & 0x1f); @@ -1031,11 +1048,14 @@ impl BitMatrix { * your own row */ pub fn getRow(&self, y: u32, row: &BitArray) -> BitArray { - let rw: BitArray = if row.getSize() < self.width as usize { + let mut rw: BitArray = if row.getSize() < self.width as usize { BitArray::with_size(self.width as usize) } else { - row.clear(); - *row + let mut z = row.clone(); + z.clear(); + z + // row.clear(); + // row.clone() }; let offset = y as usize * self.rowSize; @@ -1050,8 +1070,8 @@ impl BitMatrix { * @param y row to set * @param row {@link BitArray} to copy from */ - pub fn setRow(&self, y: u32, row: &BitArray) { - return self.bits[y as usize* self.rowSize..self.rowSize] + pub fn setRow(&mut self, y: u32, row: &BitArray) { + return self.bits[y as usize * self.rowSize..self.rowSize] .clone_from_slice(&row.getBitArray()[0..self.rowSize]); //System.arraycopy(row.getBitArray(), 0, self.bits, y * self.rowSize, self.rowSize); } @@ -1061,7 +1081,7 @@ impl BitMatrix { * * @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270) */ - pub fn rotate(&self, degrees: u32) -> Result<(), IllegalArgumentException> { + pub fn rotate(&mut self, degrees: u32) -> Result<(), IllegalArgumentException> { match degrees % 360 { 0 => Ok(()), 90 => { @@ -1086,7 +1106,7 @@ impl BitMatrix { /** * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees */ - pub fn rotate180(&self) { + pub fn rotate180(&mut self) { let mut topRow = BitArray::with_size(self.width as usize); let mut bottomRow = BitArray::with_size(self.width as usize); let mut maxHeight = (self.height + 1) / 2; @@ -1105,7 +1125,7 @@ impl BitMatrix { /** * Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise */ - pub fn rotate90(&self) { + pub fn rotate90(&mut self) { let mut newWidth = self.height; let mut newHeight = self.width; let mut newRowSize = (newWidth + 31) / 32; @@ -1117,7 +1137,9 @@ impl BitMatrix { //for (int x = 0; x < width; x++) { let offset = y as usize * self.rowSize + (x as usize / 32); if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 { - let newOffset:usize = ((newHeight - 1 - x) * newRowSize + (y / 32)).try_into().unwrap(); + let newOffset: usize = ((newHeight - 1 - x) * newRowSize + (y / 32)) + .try_into() + .unwrap(); newBits[newOffset] |= 1 << (y & 0x1f); } } @@ -1134,12 +1156,12 @@ impl BitMatrix { * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white */ pub fn getEnclosingRectangle(&self) -> Option> { - let left = self.width; - let top = self.height; + let mut left = self.width; + let mut top = self.height; // let right = -1; // let bottom = -1; - let right:u32 = 0; - let bottom = 0; + let mut right: u32 = 0; + let mut bottom = 0; for y in 0..self.height { //for (int y = 0; y < height; y++) { @@ -1154,7 +1176,7 @@ impl BitMatrix { bottom = y; } if x32 * 32 < left.try_into().unwrap() { - let bit = 0; + let mut bit = 0; while (theBits << (31 - bit)) == 0 { bit += 1; } @@ -1163,12 +1185,12 @@ impl BitMatrix { } } if x32 * 32 + 31 > right.try_into().unwrap() { - let bit = 31; + let mut bit = 31; while (theBits >> bit) == 0 { bit -= 1; } if (x32 * 32 + bit) > right.try_into().unwrap() { - right =( x32 * 32 + bit).try_into().unwrap(); + right = (x32 * 32 + bit).try_into().unwrap(); } } } @@ -1188,7 +1210,7 @@ impl BitMatrix { * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white */ pub fn getTopLeftOnBit(&self) -> Option> { - let bitsOffset = 0; + let mut bitsOffset = 0; while bitsOffset < self.bits.len() && self.bits[bitsOffset] == 0 { bitsOffset += 1; } @@ -1196,10 +1218,10 @@ impl BitMatrix { return None; } let y = bitsOffset / self.rowSize; - let x = (bitsOffset % self.rowSize) * 32; + let mut x = (bitsOffset % self.rowSize) * 32; let theBits = self.bits[bitsOffset]; - let bit = 0; + let mut bit = 0; while (theBits << (31 - bit)) == 0 { bit += 1; } @@ -1208,7 +1230,7 @@ impl BitMatrix { } pub fn getBottomRightOnBit(&self) -> Option> { - let bitsOffset = self.bits.len() - 1; + let mut bitsOffset = self.bits.len() - 1; while bitsOffset >= 0 && self.bits[bitsOffset] == 0 { bitsOffset -= 1; } @@ -1217,10 +1239,10 @@ impl BitMatrix { } let y = bitsOffset / self.rowSize; - let x = (bitsOffset % self.rowSize) * 32; + let mut x = (bitsOffset % self.rowSize) * 32; let theBits = self.bits[bitsOffset]; - let bit = 31; + let mut bit = 31; while (theBits >> bit) == 0 { bit -= 1; } @@ -1292,7 +1314,8 @@ impl BitMatrix { // } fn buildToString(&self, setString: &str, unsetString: &str, lineSeparator: &str) -> String { - let result = String::with_capacity((self.height * (self.width + 1)).try_into().unwrap()); + let mut result = + String::with_capacity((self.height * (self.width + 1)).try_into().unwrap()); for y in 0..self.height { //for (int y = 0; y < height; y++) { for x in 0..self.width { @@ -1493,12 +1516,14 @@ impl BitSource { * bits of the int * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available */ - pub fn readBits(&self, numBits: usize) -> Result { + pub fn readBits(&mut self, numBits: usize) -> Result { if numBits < 1 || numBits > 32 || numBits > self.available() { return Err(IllegalArgumentException::new(&numBits.to_string())); } - let result = 0; + let mut result = 0; + + let mut numBits = numBits; // First, read remainder from current byte if self.bitOffset > 0 { diff --git a/src/common/reedsolomon/GenericGFPolyTestCase.rs b/src/common/reedsolomon/GenericGFPolyTestCase.rs index d611989..173c01e 100644 --- a/src/common/reedsolomon/GenericGFPolyTestCase.rs +++ b/src/common/reedsolomon/GenericGFPolyTestCase.rs @@ -25,28 +25,36 @@ use super::{GenericGF, GenericGFPoly}; * Tests {@link GenericGFPoly}. */ -const FIELD: GenericGF = super::QR_CODE_FIELD_256; +//const FIELD: GenericGF = super::QR_CODE_FIELD_256; #[test] fn testPolynomialString() { - assert_eq!("0", FIELD.getZero().to_string()); + let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256); + let fz = super::GenericGFPoly::new(FIELD.clone(), &vec![0;0]).unwrap(); + + assert_eq!("0", fz.getZero().to_string()); assert_eq!("-1", FIELD.buildMonomial(0, -1).to_string()); - let p = GenericGFPoly::new(Box::new(FIELD), &vec![3, 0, -2, 1, 1]).unwrap(); + let p = GenericGFPoly::new(FIELD.clone(), &vec![3, 0, -2, 1, 1]).unwrap(); assert_eq!("a^25x^4 - ax^2 + x + 1", p.to_string()); - let p = GenericGFPoly::new(Box::new(FIELD), &vec![3]).unwrap(); + let p = GenericGFPoly::new(FIELD.clone(), &vec![3]).unwrap(); assert_eq!("a^25", p.to_string()); } #[test] fn testZero() { - assert_eq!(*FIELD.getZero(), *FIELD.buildMonomial(1, 0)); + let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256); + let fz = super::GenericGFPoly::new(FIELD.clone(), &vec![0;0]).unwrap(); + + assert_eq!(fz.getZero(), FIELD.buildMonomial(1, 0)); assert_eq!( - *FIELD.getZero(), - *FIELD.buildMonomial(1, 2).multiply_with_scalar(0) + fz.getZero(), + FIELD.buildMonomial(1, 2).multiply_with_scalar(0) ); } #[test] fn testEvaluate() { + let FIELD = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256); + assert_eq!(3, FIELD.buildMonomial(0, 3).evaluateAt(0)); } diff --git a/src/common/reedsolomon/ReedSolomonTestCase.rs b/src/common/reedsolomon/ReedSolomonTestCase.rs index c32894a..251ee26 100644 --- a/src/common/reedsolomon/ReedSolomonTestCase.rs +++ b/src/common/reedsolomon/ReedSolomonTestCase.rs @@ -36,14 +36,15 @@ const DECODER_TEST_ITERATIONS: i32 = 10; #[test] fn testDataMatrix() { + let dm256 = super::get_predefined_genericgf(super::PredefinedGenericGF::DataMatrixField256); // real life test cases testEncodeDecode( - &super::DATA_MATRIX_FIELD_256, + &dm256, &vec![142, 164, 186], &vec![114, 25, 5, 88, 102], ); testEncodeDecode( - &super::DATA_MATRIX_FIELD_256, + &dm256, &vec![ 0x69, 0x75, 0x75, 0x71, 0x3B, 0x30, 0x30, 0x64, 0x70, 0x65, 0x66, 0x2F, 0x68, 0x70, 0x70, 0x68, 0x6D, 0x66, 0x2F, 0x64, 0x70, 0x6E, 0x30, 0x71, 0x30, 0x7B, 0x79, 0x6A, @@ -55,16 +56,17 @@ fn testDataMatrix() { ], ); // synthetic test cases - testEncodeDecodeRandom(super::DATA_MATRIX_FIELD_256, 10, 240); - testEncodeDecodeRandom(super::DATA_MATRIX_FIELD_256, 128, 127); - testEncodeDecodeRandom(super::DATA_MATRIX_FIELD_256, 220, 35); + testEncodeDecodeRandom(dm256.clone(), 10, 240); + testEncodeDecodeRandom(dm256.clone(), 128, 127); + testEncodeDecodeRandom(dm256.clone(), 220, 35); } #[test] fn testQRCode() { + let qrcf256 = super::get_predefined_genericgf(super::PredefinedGenericGF::QrCodeField256); // Test case from example given in ISO 18004, Annex I testEncodeDecode( - &super::QR_CODE_FIELD_256, + &qrcf256, &vec![ 0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, @@ -72,7 +74,7 @@ fn testQRCode() { &vec![0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87, 0x2C, 0x55], ); testEncodeDecode( - &super::QR_CODE_FIELD_256, + &qrcf256, &vec![ 0x72, 0x67, 0x2F, 0x77, 0x69, 0x6B, 0x69, 0x2F, 0x4D, 0x61, 0x69, 0x6E, 0x5F, 0x50, 0x61, 0x67, 0x65, 0x3B, 0x3B, 0x00, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, @@ -85,36 +87,37 @@ fn testQRCode() { ); // real life test cases // synthetic test cases - testEncodeDecodeRandom(super::QR_CODE_FIELD_256, 10, 240); - testEncodeDecodeRandom(super::QR_CODE_FIELD_256, 128, 127); - testEncodeDecodeRandom(super::QR_CODE_FIELD_256, 220, 35); + testEncodeDecodeRandom(qrcf256.clone(), 10, 240); + testEncodeDecodeRandom(qrcf256.clone(), 128, 127); + testEncodeDecodeRandom(qrcf256.clone(), 220, 35); } #[test] fn testAztec() { // real life test cases testEncodeDecode( - &super::AZTEC_PARAM, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecParam), &vec![0x5, 0x6], &vec![0x3, 0x2, 0xB, 0xB, 0x7], ); testEncodeDecode( - &super::AZTEC_PARAM, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecParam), &vec![0x0, 0x0, 0x0, 0x9], &vec![0xA, 0xD, 0x8, 0x6, 0x5, 0x6], ); testEncodeDecode( - &super::AZTEC_PARAM, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecParam), &vec![0x2, 0x8, 0x8, 0x7], &vec![0xE, 0xC, 0xA, 0x9, 0x6, 0x8], ); testEncodeDecode( - &super::AZTEC_DATA_6, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData6), &vec![0x9, 0x32, 0x1, 0x29, 0x2F, 0x2, 0x27, 0x25, 0x1, 0x1B], &vec![0x2C, 0x2, 0xD, 0xD, 0xA, 0x16, 0x28, 0x9, 0x22, 0xA, 0x14], ); + testEncodeDecode( - &super::AZTEC_DATA_8, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData8), &vec![ 0xE0, 0x86, 0x42, 0x98, 0xE8, 0x4A, 0x96, 0xC6, 0xB9, 0xF0, 0x8C, 0xA7, 0x4A, 0xDA, 0xF8, 0xCE, 0xB7, 0xDE, 0x88, 0x64, 0x29, 0x8E, 0x84, 0xA9, 0x6C, 0x6B, 0x9F, 0x08, @@ -130,7 +133,7 @@ fn testAztec() { ], ); testEncodeDecode( - &super::AZTEC_DATA_10, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData10), &vec![ 0x15C, 0x1E1, 0x2D5, 0x02E, 0x048, 0x1E2, 0x037, 0x0CD, 0x02E, 0x056, 0x26A, 0x281, 0x1C2, 0x1A6, 0x296, 0x045, 0x041, 0x0AA, 0x095, 0x2CE, 0x003, 0x38F, 0x2CD, 0x1A2, @@ -177,7 +180,7 @@ fn testAztec() { ], ); testEncodeDecode( - &super::AZTEC_DATA_12, + &super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData12), &vec![ 0x571, 0xE1B, 0x542, 0xE12, 0x1E2, 0x0DC, 0xCD0, 0xB85, 0x69A, 0xA81, 0x709, 0xA6A, 0x584, 0x510, 0x4AA, 0x256, 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xAD1, 0x389, 0x09C, @@ -324,15 +327,21 @@ fn testAztec() { ], ); // synthetic test cases - testEncodeDecodeRandom(super::AZTEC_PARAM, 2, 5); // compact mode message - testEncodeDecodeRandom(super::AZTEC_PARAM, 4, 6); // full mode message - testEncodeDecodeRandom(super::AZTEC_DATA_6, 10, 7); - testEncodeDecodeRandom(super::AZTEC_DATA_6, 20, 12); - testEncodeDecodeRandom(super::AZTEC_DATA_8, 20, 11); - testEncodeDecodeRandom(super::AZTEC_DATA_8, 128, 127); - testEncodeDecodeRandom(super::AZTEC_DATA_10, 128, 128); - testEncodeDecodeRandom(super::AZTEC_DATA_10, 768, 255); - testEncodeDecodeRandom(super::AZTEC_DATA_12, 3072, 1023); + let azp = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecParam); + let azd6 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData6); + let azd8 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData8); + let azd10 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData10); + let azd12 = super::get_predefined_genericgf(super::PredefinedGenericGF::AztecData12); + + testEncodeDecodeRandom(azp.clone(), 2, 5); // compact mode message + testEncodeDecodeRandom(azp.clone(), 4, 6); // full mode message + testEncodeDecodeRandom(azd6.clone(), 10, 7); + testEncodeDecodeRandom(azd6.clone(), 20, 12); + testEncodeDecodeRandom(azd8.clone(), 20, 11); + testEncodeDecodeRandom(azd8.clone(), 128, 127); + testEncodeDecodeRandom(azd10.clone(), 128, 128); + testEncodeDecodeRandom(azd10.clone(), 768, 255); + testEncodeDecodeRandom(azd12.clone(), 3072, 1023); } fn corrupt(received: &mut Vec, howMany: i32, random: &mut rand::rngs::ThreadRng, max: i32) { @@ -367,7 +376,7 @@ fn testEncodeDecodeRandom(field: GenericGF, dataSize: usize, ecSize: usize) { "Invalid ECC size for {}", field ); - let encoder = ReedSolomonEncoder::new(Box::new(field.clone())); + let mut encoder = ReedSolomonEncoder::new(field.clone()); let mut message = Vec::with_capacity(dataSize + ecSize); let mut dataWords: Vec = Vec::with_capacity(dataSize); let mut ecWords = Vec::with_capacity(ecSize); @@ -401,7 +410,7 @@ fn testEncodeDecode(field: &GenericGF, dataWords: &Vec, ecWords: &Vec) } fn testEncoder(field: &GenericGF, dataWords: &Vec, ecWords: &Vec) { - let encoder = ReedSolomonEncoder::new(Box::new(field.clone())); + let mut encoder = ReedSolomonEncoder::new(field.clone()); let mut messageExpected = Vec::with_capacity(dataWords.len() + ecWords.len()); let mut message = Vec::with_capacity(dataWords.len() + ecWords.len()); messageExpected[0..dataWords.len()].clone_from_slice(&dataWords[0..dataWords.len()]); diff --git a/src/common/reedsolomon/mod.rs b/src/common/reedsolomon/mod.rs index 7fa630a..17e279e 100644 --- a/src/common/reedsolomon/mod.rs +++ b/src/common/reedsolomon/mod.rs @@ -69,14 +69,37 @@ impl fmt::Display for ReedSolomonException { //package com.google.zxing.common.reedsolomon; -pub const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1 -pub const AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1); // x^10 + x^3 + 1 -pub const AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1); // x^6 + x + 1 -pub const AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1); // x^4 + x + 1 -pub const QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 -pub const DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1 -pub const AZTEC_DATA_8: GenericGF = DATA_MATRIX_FIELD_256; -pub const MAXICODE_FIELD_64: GenericGF = AZTEC_DATA_6; +// pub const AZTEC_DATA_12: GenericGF = GenericGF::new(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1 +// pub const AZTEC_DATA_10: GenericGF = GenericGF::new(0x409, 1024, 1); // x^10 + x^3 + 1 +// pub const AZTEC_DATA_6: GenericGF = GenericGF::new(0x43, 64, 1); // x^6 + x + 1 +// pub const AZTEC_PARAM: GenericGF = GenericGF::new(0x13, 16, 1); // x^4 + x + 1 +// pub const QR_CODE_FIELD_256: GenericGF = GenericGF::new(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 +// pub const DATA_MATRIX_FIELD_256: GenericGF = GenericGF::new(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1 +// pub const AZTEC_DATA_8: GenericGF = DATA_MATRIX_FIELD_256; +// pub const MAXICODE_FIELD_64: GenericGF = AZTEC_DATA_6; + +pub enum PredefinedGenericGF { + AztecData12, + AztecData10, + AztecData6, + AztecParam, + QrCodeField256, + DataMatrixField256, + AztecData8, + MaxicodeField64 +} + +/// Replacement for old const options, has the downside of generating new versions whenever one is requested. +pub fn get_predefined_genericgf(request:PredefinedGenericGF) -> GenericGF { + match request { + PredefinedGenericGF::AztecData12 => GenericGF::new(0x1069, 4096, 1), // x^12 + x^6 + x^5 + x^3 + 1, + PredefinedGenericGF::AztecData10 => GenericGF::new(0x409, 1024, 1), // x^10 + x^3 + 1 + PredefinedGenericGF::AztecData6 | PredefinedGenericGF::MaxicodeField64 => GenericGF::new(0x43, 64, 1), // x^6 + x + 1 + PredefinedGenericGF::AztecParam => GenericGF::new(0x13, 16, 1), // x^4 + x + 1 + PredefinedGenericGF::QrCodeField256 => GenericGF::new(0x011D, 256, 0), // x^8 + x^4 + x^3 + x^2 + 1 + PredefinedGenericGF::DataMatrixField256 | PredefinedGenericGF::AztecData8 => GenericGF::new(0x012D, 256, 1), // x^8 + x^5 + x^3 + x^2 + 1 + } +} /** *

This class contains utility methods for performing mathematical operations over @@ -89,7 +112,7 @@ pub const MAXICODE_FIELD_64: GenericGF = AZTEC_DATA_6; * @author Sean Owen * @author David Olivier */ -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct GenericGF { expTable: Vec, logTable: Vec, @@ -278,7 +301,7 @@ impl fmt::Display for GenericGF { * * @author Sean Owen */ -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct GenericGFPoly { field: GenericGF, coefficients: Vec, @@ -323,9 +346,8 @@ impl GenericGFPoly { } else { let mut new_coefficients = Vec::with_capacity(coefficientsLength - firstNonZero); - let l = new_coefficients.len(); - new_coefficients[0..l] - .clone_from_slice(&coefficients[firstNonZero..l]); + let l = new_coefficients.len(); + new_coefficients[0..l].clone_from_slice(&coefficients[firstNonZero..l]); // System.arraycopy(coefficients, // firstNonZero, // this.coefficients, @@ -495,11 +517,11 @@ impl GenericGFPoly { return GenericGFPoly::new(self.field.clone(), &product).unwrap(); } - pub fn getZero(&self) -> Self{ + pub fn getZero(&self) -> Self { GenericGFPoly::new(self.field.clone(), &vec![0]).unwrap() } - pub fn getOne(&self) -> Self{ + pub fn getOne(&self) -> Self { GenericGFPoly::new(self.field.clone(), &vec![1]).unwrap() } @@ -586,15 +608,16 @@ impl fmt::Display for GenericGFPoly { } } if degree == 0 || coefficient != 1 { - if let Ok(alphaPower) = self.field.log(coefficient){ - if alphaPower == 0 { - result.push_str("1"); - } else if alphaPower == 1 { - result.push_str("a"); - } else { - result.push_str("a^"); - result.push_str(&format!("{}", alphaPower)); - }} + if let Ok(alphaPower) = self.field.log(coefficient) { + if alphaPower == 0 { + result.push_str("1"); + } else if alphaPower == 1 { + result.push_str("a"); + } else { + result.push_str("a^"); + result.push_str(&format!("{}", alphaPower)); + } + } } if degree != 0 { if degree == 1 { @@ -655,9 +678,7 @@ pub struct ReedSolomonDecoder { impl ReedSolomonDecoder { pub fn new(field: GenericGF) -> Self { - Self { - field: field, - } + Self { field: field } } /** @@ -726,8 +747,8 @@ impl ReedSolomonDecoder { R: usize, ) -> Result, ReedSolomonException> { // Assume a's degree is >= b's - let mut a = a; - let mut b = b; + let mut a = a.clone(); + let mut b = b.clone(); if a.getDegree() < b.getDegree() { let temp = a; a = b; @@ -738,8 +759,8 @@ impl ReedSolomonDecoder { let mut r = b; // let tLast = self.field.getZero(); // let t = self.field.getOne(); - let mut tLast = a.getZero(); - let mut t = a.getOne(); + let mut tLast = rLast.getZero(); + let mut t = rLast.getOne(); // Run Euclidean algorithm until r's degree is less than R/2 while 2 * r.getDegree() >= R { @@ -754,7 +775,7 @@ impl ReedSolomonDecoder { return Err(ReedSolomonException::new("r_{i-1} was zero")); } r = rLastLast; - let q = a.getZero(); + let mut q = r.getZero(); let denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree()); let dltInverse = match self.field.inverse(denominatorLeadingTerm) { Ok(inv) => inv, @@ -769,11 +790,11 @@ impl ReedSolomonDecoder { Ok(res) => res, Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), }; - r = match r.addOrSubtract(match rLast.multiplyByMonomial(degreeDiff, scale) { - Ok(res) => &res, + r = match r.addOrSubtract(&match rLast.multiplyByMonomial(degreeDiff, scale) { + Ok(res) => res, Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), }) { - Ok(res) =>&res, + Ok(res) => res, Err(err) => return Err(ReedSolomonException::new("IllegalArgumentException")), }; } @@ -821,7 +842,7 @@ impl ReedSolomonDecoder { return Ok(vec![errorLocator.getCoefficient(1).try_into().unwrap()]); } - let result: Vec = Vec::with_capacity(numErrors); + let mut result: Vec = Vec::with_capacity(numErrors); let mut e = 0; for i in 1..self.field.getSize() { //for (int i = 1; i < field.getSize() && e < numErrors; i++) { @@ -851,11 +872,14 @@ impl ReedSolomonDecoder { ) -> Vec { // This is directly applying Forney's Formula let s = errorLocations.len(); - let result = Vec::with_capacity(s); + let mut result = Vec::with_capacity(s); for i in 0..s { //for (int i = 0; i < s; i++) { - let xiInverse = self.field.inverse(errorLocations[i].try_into().unwrap()); - let denominator = 1; + let xiInverse = self + .field + .inverse(errorLocations[i].try_into().unwrap()) + .unwrap(); + let mut denominator = 1; for j in 0..s { //for (int j = 0; j < s; j++) { if i != j { @@ -865,7 +889,7 @@ impl ReedSolomonDecoder { // Below is a funny-looking workaround from Steven Parkes let term = self .field - .multiply(errorLocations[j].try_into().unwrap(), xiInverse.unwrap()); + .multiply(errorLocations[j].try_into().unwrap(), xiInverse); let termPlus1 = if (term & 0x1) == 0 { term | 1 } else { @@ -875,11 +899,11 @@ impl ReedSolomonDecoder { } } result[i] = self.field.multiply( - errorEvaluator.evaluateAt(xiInverse.unwrap().try_into().unwrap()), + errorEvaluator.evaluateAt(xiInverse.try_into().unwrap()), self.field.inverse(denominator).unwrap(), ); if self.field.getGeneratorBase() != 0 { - result[i] = self.field.multiply(result[i], xiInverse.unwrap()); + result[i] = self.field.multiply(result[i], xiInverse); } } return result; @@ -921,23 +945,25 @@ pub struct ReedSolomonEncoder { impl ReedSolomonEncoder { pub fn new(field: GenericGF) -> Self { Self { + cachedGenerators: vec![GenericGFPoly::new(field.clone(), &vec![1]).unwrap()], field: field, - cachedGenerators: vec![GenericGFPoly::new(field, &vec![1]).unwrap()], } } - fn buildGenerator(&self, degree: usize) -> GenericGFPoly { + fn buildGenerator(&mut self, degree: usize) -> &GenericGFPoly { if degree >= self.cachedGenerators.len() { let mut lastGenerator = self .cachedGenerators .get(self.cachedGenerators.len() - 1) .unwrap(); - for d in self.cachedGenerators.len()..=degree { + let cg_len = self.cachedGenerators.len(); + let mut nextGenerator; + for d in cg_len..=degree { //for (int d = cachedGenerators.size(); d <= degree; d++) { - let nextGenerator = lastGenerator + nextGenerator = lastGenerator .multiply( &GenericGFPoly::new( - self.field, + self.field.clone(), &vec![ 1, self.field.exp(d as i32 - 1 + self.field.getGeneratorBase()), @@ -947,14 +973,16 @@ impl ReedSolomonEncoder { ) .unwrap(); self.cachedGenerators.push(nextGenerator); - lastGenerator = &nextGenerator; + lastGenerator = self.cachedGenerators.get(d).unwrap(); + //lastGenerator = &nextGenerator; } } - return *self.cachedGenerators.get(degree).unwrap(); + let rv = self.cachedGenerators.get(degree).unwrap(); + return rv; } pub fn encode( - &self, + &mut self, toEncode: &mut Vec, ecBytes: usize, ) -> Result<(), IllegalArgumentException> { @@ -965,13 +993,14 @@ impl ReedSolomonEncoder { if dataBytes <= 0 { return Err(IllegalArgumentException::new("No data bytes provided")); } + let fld = self.field.clone(); let generator = self.buildGenerator(ecBytes); let mut infoCoefficients: Vec = Vec::with_capacity(dataBytes); infoCoefficients[0..dataBytes].clone_from_slice(&toEncode[0..dataBytes]); //System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); - let mut info = GenericGFPoly::new(self.field.clone(), &infoCoefficients)?; + let mut info = GenericGFPoly::new(fld, &infoCoefficients)?; info = info.multiplyByMonomial(ecBytes.try_into().unwrap(), 1)?; - let remainder = info.divide(&generator)?[1]; + let remainder = &info.divide(&generator)?[1]; let coefficients = remainder.getCoefficients(); let numZeroCoefficients = ecBytes - coefficients.len(); for i in 0..numZeroCoefficients { diff --git a/src/lib.rs b/src/lib.rs index 3e90036..41be787 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -489,7 +489,7 @@ pub trait Reader { * @throws ChecksumException if a potential barcode is found but does not pass its checksum * @throws FormatException if a potential barcode is found but format is invalid */ - fn decode(image: BinaryBitmap) -> Result, ReaderDecodeException>; + fn decode(image: BinaryBitmap) -> Result; /** * Locates and decodes a barcode in some format within an image. This method also accepts @@ -508,7 +508,7 @@ pub trait Reader { fn decode_with_hints( image: BinaryBitmap, hints: HashMap, - ) -> Result, ReaderDecodeException>; + ) -> Result; /** * Resets any internal state the implementation has after a decode, to prepare it @@ -647,16 +647,16 @@ pub enum RXingResultMetadataType { * * @author Sean Owen */ -pub struct RXingResult<'a> { +pub struct RXingResult { text: String, rawBytes: Vec, numBits: usize, resultPoints: Vec, format: BarcodeFormat, - resultMetadata: Option>, + resultMetadata: HashMap, timestamp: u128, } -impl RXingResult<'_> { +impl RXingResult { pub fn new( text: &str, rawBytes: Vec, @@ -682,10 +682,11 @@ impl RXingResult<'_> { format: BarcodeFormat, timestamp: u128, ) -> Self { + let l = rawBytes.len(); Self::new_complex( text, rawBytes, - 8 * rawBytes.len(), + 8 * l, resultPoints, format, timestamp, @@ -706,7 +707,7 @@ impl RXingResult<'_> { numBits, resultPoints, format, - resultMetadata: None, + resultMetadata: HashMap::new(), timestamp, } } @@ -714,15 +715,15 @@ impl RXingResult<'_> { /** * @return raw text encoded by the barcode */ - pub fn getText(&self) -> String { - return self.text; + pub fn getText(&self) -> &String { + return &self.text; } /** * @return raw bytes encoded by the barcode, if applicable, otherwise {@code null} */ - pub fn getRawBytes(&self) -> Vec { - return self.rawBytes; + pub fn getRawBytes(&self) -> &Vec { + return &self.rawBytes; } /** @@ -738,15 +739,15 @@ impl RXingResult<'_> { * identifying finder patterns or the corners of the barcode. The exact meaning is * specific to the type of barcode that was decoded. */ - pub fn getRXingResultPoints(&self) -> Vec { - return self.resultPoints; + pub fn getRXingResultPoints(&self) -> &Vec { + return &self.resultPoints; } /** * @return {@link BarcodeFormat} representing the format of the barcode that was decoded */ - pub fn getBarcodeFormat(&self) -> BarcodeFormat { - return self.format; + pub fn getBarcodeFormat(&self) -> &BarcodeFormat { + return &self.format; } /** @@ -754,35 +755,32 @@ impl RXingResult<'_> { * {@code null}. This contains optional metadata about what was detected about the barcode, * like orientation. */ - pub fn getRXingResultMetadata(&self) -> HashMap { - return self.resultMetadata.unwrap(); + pub fn getRXingResultMetadata(&self) -> &HashMap { + return &self.resultMetadata; } - pub fn putMetadata(&self, md_type: RXingResultMetadataType, value: &dyn Any) { - if (self.resultMetadata.is_none()) { - self.resultMetadata = Some(HashMap::new()); - } - self.resultMetadata.unwrap().insert(md_type, value); + pub fn putMetadata(&mut self, md_type: RXingResultMetadataType, value:String) { + self.resultMetadata.insert(md_type, value); } - pub fn putAllMetadata(&self, metadata: HashMap) { - if (self.resultMetadata.is_none()) { - self.resultMetadata = Some(metadata); + pub fn putAllMetadata(&mut self, metadata: HashMap) { + if self.resultMetadata.is_empty() { + self.resultMetadata = metadata; } else { for (key, value) in metadata.into_iter() { - self.resultMetadata.unwrap().insert(key, value); + self.resultMetadata.insert(key, value); } } } - pub fn addRXingResultPoints(&self, newPoints: Vec) { + pub fn addRXingResultPoints(&mut self, newPoints: &mut Vec) { //RXingResultPoint[] oldPoints = resultPoints; if !newPoints.is_empty() { // let allPoints:Vec= Vec::with_capacity(oldPoints.len() + newPoints.len()); //System.arraycopy(oldPoints, 0, allPoints, 0, oldPoints.length); //System.arraycopy(newPoints, 0, allPoints, oldPoints.length, newPoints.length); //resultPoints = allPoints; - self.resultPoints.append(&mut newPoints); + self.resultPoints.append(newPoints); } } @@ -791,7 +789,7 @@ impl RXingResult<'_> { } } -impl fmt::Display for RXingResult<'_> { +impl fmt::Display for RXingResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.text) } @@ -822,6 +820,7 @@ use crate::common::detector::MathUtils; * * @author Sean Owen */ +#[derive(Debug,Clone)] pub struct RXingResultPoint { x: f32, y: f32, @@ -857,7 +856,7 @@ impl RXingResultPoint { * * @param patterns array of three {@code RXingResultPoint} to order */ - pub fn orderBestPatterns(patterns: &Vec) { + pub fn orderBestPatterns(patterns: &mut Vec) { // Find distances between pattern centers let zeroOneDistance = MathUtils::distance_float( patterns[0].getX(), @@ -878,37 +877,41 @@ impl RXingResultPoint { patterns[2].getY(), ); - let pointA: RXingResultPoint; - let pointB: RXingResultPoint; - let pointC: RXingResultPoint; + let mut pointA: &RXingResultPoint; + let mut pointB: &RXingResultPoint; + let mut pointC: &RXingResultPoint; // Assume one closest to other two is B; A and C will just be guesses at first - if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { - pointB = patterns[0]; - pointA = patterns[1]; - pointC = patterns[2]; - } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { - pointB = patterns[1]; - pointA = patterns[0]; - pointC = patterns[2]; + if oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance { + pointB = &patterns[0]; + pointA = &patterns[1]; + pointC = &patterns[2]; + } else if zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance { + pointB = &patterns[1]; + pointA = &patterns[0]; + pointC = &patterns[2]; } else { - pointB = patterns[2]; - pointA = patterns[0]; - pointC = patterns[1]; + pointB = &patterns[2]; + pointA = &patterns[0]; + pointC = &patterns[1]; } // Use cross product to figure out whether A and C are correct or flipped. // This asks whether BC x BA has a positive z component, which is the arrangement // we want for A, B, C. If it's negative, then we've got it flipped around and // should swap A and C. - if (RXingResultPoint::crossProductZ(&pointA, &pointB, &pointC) < 0.0f32) { + if RXingResultPoint::crossProductZ(&pointA, &pointB, &pointC) < 0.0f32 { let temp = pointA; pointA = pointC; pointC = temp; } - patterns[0] = pointA; - patterns[1] = pointB; - patterns[2] = pointC; + let pa = (*pointA).clone(); + let pb = (*pointB).clone(); + let pc = (*pointC).clone(); + + patterns[0] = pa; + patterns[1] = pb; + patterns[2] = pc; } /** @@ -969,7 +972,7 @@ pub struct Dimension { impl Dimension { pub fn new(width: usize, height: usize) -> Result { - if (width < 0 || height < 0) { + if width < 0 || height < 0 { return Err(IllegalArgumentException::new("")); } Ok(Self { width, height }) @@ -1020,7 +1023,7 @@ pub trait Binarizer { //private final LuminanceSource source; //fn new(source:dyn LuminanceSource) -> Self; - fn getLuminanceSource(&self) -> dyn LuminanceSource; + fn getLuminanceSource(&self) -> &dyn LuminanceSource; /** * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return @@ -1096,8 +1099,8 @@ pub struct BinaryBitmap { impl BinaryBitmap { pub fn new(binarizer: Box) -> Self { Self { - binarizer: binarizer, matrix: binarizer.getBlackMatrix().unwrap(), + binarizer: binarizer, } } @@ -1139,20 +1142,23 @@ impl BinaryBitmap { * @return The 2D array of bits for the image (true means black). * @throws NotFoundException if image can't be binarized to make a matrix */ - pub fn getBlackMatrix(&self) -> Result { + pub fn getBlackMatrix(&self) -> Result<&BitMatrix, NotFoundException> { // The matrix is created on demand the first time it is requested, then cached. There are two // reasons for this: // 1. This work will never be done if the caller only installs 1D Reader objects, or if a // 1D Reader finds a barcode before the 2D Readers run. // 2. This work will only be done once even if the caller installs multiple 2D Readers. - return Ok(self.matrix); + return Ok(&self.matrix); } /** * @return Whether this bitmap can be cropped. */ pub fn isCropSupported(&self) -> bool { - return self.binarizer.getLuminanceSource().isCropSupported(); + let b = &self.binarizer; + let r = &b.getLuminanceSource(); + let isCropOk = r.isCropSupported(); + return isCropOk; } /** @@ -1453,19 +1459,11 @@ impl InvertedLuminanceSource { delegate, } } - - fn new(width: usize, height: usize) -> Self { - let new_ils: Self; - new_ils.width = width; - new_ils.height = height; - - new_ils - } } impl LuminanceSource for InvertedLuminanceSource { fn getRow(&self, y: usize, row: &Vec) -> Vec { - let new_row = self.delegate.getRow(y, row); + let mut new_row = self.delegate.getRow(y, row); let width = self.getWidth(); for i in 0..width { //for (int i = 0; i < width; i++) { @@ -1477,7 +1475,7 @@ impl LuminanceSource for InvertedLuminanceSource { fn getMatrix(&self) -> Vec { let matrix = self.delegate.getMatrix(); let length = self.getWidth() * self.getHeight(); - let invertedMatrix = Vec::with_capacity(length); + let mut invertedMatrix = Vec::with_capacity(length); for i in 0..length { //for (int i = 0; i < length; i++) { invertedMatrix[i] = (255 - (matrix[i] & 0xFF)); @@ -1515,7 +1513,7 @@ impl LuminanceSource for InvertedLuminanceSource { /** * @return original delegate {@link LuminanceSource} since invert undoes itself */ - fn invert(&self) -> Box<(dyn LuminanceSource)> { + fn invert(&self) -> Box { return self.delegate; } @@ -1564,6 +1562,7 @@ const THUMBNAIL_SCALE_FACTOR: usize = 2; * * @author dswitkin@google.com (Daniel Switkin) */ +#[derive(Debug,Clone)] pub struct PlanarYUVLuminanceSource { yuvData: Vec, dataWidth: usize, @@ -1585,13 +1584,13 @@ impl PlanarYUVLuminanceSource { height: usize, reverseHorizontal: bool, ) -> Result { - if (left + width > dataWidth || top + height > dataHeight) { + if left + width > dataWidth || top + height > dataHeight { return Err(IllegalArgumentException::new( "Crop rectangle does not fit within image data.", )); } - let new_s: Self = Self { + let mut new_s: Self = Self { yuvData, dataWidth, dataHeight, @@ -1611,9 +1610,9 @@ impl PlanarYUVLuminanceSource { pub fn renderThumbnail(&self) -> Vec { let width = self.getWidth() / THUMBNAIL_SCALE_FACTOR; let height = self.getHeight() / THUMBNAIL_SCALE_FACTOR; - let pixels = Vec::with_capacity(width * height); + let mut pixels = Vec::with_capacity(width * height); let yuv: Vec = Vec::new(); - let inputOffset = self.top * self.dataWidth + self.left; + let mut inputOffset = self.top * self.dataWidth + self.left; for y in 0..height { //for (int y = 0; y < height; y++) { @@ -1642,22 +1641,22 @@ impl PlanarYUVLuminanceSource { return self.getHeight() / THUMBNAIL_SCALE_FACTOR; } - fn reverseHorizontal(&self, width: usize, height: usize) { - let yuvData = self.yuvData; + fn reverseHorizontal(&mut self, width: usize, height: usize) { + //let mut yuvData = self.yuvData; let mut rowStart = self.top * self.dataWidth + self.left; for y in 0..height { let middle = rowStart + width / 2; let mut x2 = rowStart + width - 1; for x1 in rowStart..middle { //for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { - let temp = yuvData[x1]; - yuvData[x1] = yuvData[x2]; - yuvData[x2] = temp; + let temp = self.yuvData[x1]; + self.yuvData[x1] = self.yuvData[x2]; + self.yuvData[x2] = temp; x2 -= 1; } rowStart += self.dataWidth; } - self.yuvData = yuvData; + //self.yuvData = yuvData; /*for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) { let middle = rowStart + width / 2; for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { @@ -1667,20 +1666,12 @@ impl PlanarYUVLuminanceSource { } }*/ } - - fn new(width: usize, height: usize) -> Self { - let new_ils: Self; - new_ils.width = width; - new_ils.height = height; - - new_ils - } } impl LuminanceSource for PlanarYUVLuminanceSource { fn getRow(&self, y: usize, row: &Vec) -> Vec { let mut row = row.to_vec(); - if (y < 0 || y >= self.getHeight()) { + if y < 0 || y >= self.getHeight() { //throw new IllegalArgumentException("Requested row is outside the image: " + y); panic!("Requested row is outside the image: {}", y); } @@ -1699,16 +1690,16 @@ impl LuminanceSource for PlanarYUVLuminanceSource { // If the caller asks for the entire underlying image, save the copy and give them the // original data. The docs specifically warn that result.length must be ignored. - if (width == self.dataWidth && height == self.dataHeight) { - return self.yuvData; + if width == self.dataWidth && height == self.dataHeight { + return self.yuvData.clone(); } let area = width * height; - let matrix = Vec::with_capacity(area); - let inputOffset = self.top * self.dataWidth + self.left; + let mut matrix = Vec::with_capacity(area); + let mut inputOffset = self.top * self.dataWidth + self.left; // If the width matches the full width of the underlying data, perform a single copy. - if (width == self.dataWidth) { + if width == self.dataWidth { matrix[0..area].clone_from_slice(&self.yuvData[inputOffset..area]); //System.arraycopy(yuvData, inputOffset, matrix, 0, area); return matrix; @@ -1745,7 +1736,7 @@ impl LuminanceSource for PlanarYUVLuminanceSource { height: usize, ) -> Result, UnsupportedOperationException> { match PlanarYUVLuminanceSource::new_with_all( - self.yuvData, + self.yuvData.clone(), self.dataWidth, self.dataHeight, self.left + left, @@ -1764,7 +1755,7 @@ impl LuminanceSource for PlanarYUVLuminanceSource { } fn invert(&self) -> Box { - let new_i = InvertedLuminanceSource::new_with_delegate(Box::new(*self)); + let new_i = InvertedLuminanceSource::new_with_delegate(Box::new(self.clone())); Box::new(new_i) } @@ -1795,7 +1786,8 @@ impl LuminanceSource for PlanarYUVLuminanceSource { * @author dswitkin@google.com (Daniel Switkin) * @author Betaminos */ -pub struct RGBLuminanceSource { +#[derive(Debug,Clone)] + pub struct RGBLuminanceSource { luminances: Vec, dataWidth: usize, dataHeight: usize, @@ -1807,7 +1799,7 @@ pub struct RGBLuminanceSource { impl LuminanceSource for RGBLuminanceSource { fn getRow(&self, y: usize, row: &Vec) -> Vec { - let row = row.to_vec(); + let mut row = row.to_vec(); if y < 0 || y >= self.getHeight() { panic!("Requested row is outside the image: {}", y); } @@ -1825,8 +1817,8 @@ impl LuminanceSource for RGBLuminanceSource { // If the caller asks for the entire underlying image, save the copy and give them the // original data. The docs specifically warn that result.length must be ignored. - if (width == self.dataWidth && height == self.dataHeight) { - return self.luminances; + if width == self.dataWidth && height == self.dataHeight { + return self.luminances.clone(); } let area = width * height; @@ -1834,7 +1826,7 @@ impl LuminanceSource for RGBLuminanceSource { let mut inputOffset = self.top * self.dataWidth + self.left; // If the width matches the full width of the underlying data, perform a single copy. - if (width == self.dataWidth) { + if width == self.dataWidth { matrix[0..area].clone_from_slice(&self.luminances[inputOffset..area]); //System.arraycopy(self.luminances, inputOffset, matrix, 0, area); return matrix; @@ -1885,21 +1877,13 @@ impl LuminanceSource for RGBLuminanceSource { } fn invert(&self) -> Box { - let new_i = InvertedLuminanceSource::new_with_delegate(Box::new(*self)); + let new_i = InvertedLuminanceSource::new_with_delegate(Box::new(self.clone())); Box::new(new_i) } } impl RGBLuminanceSource { - fn new(width: usize, height: usize) -> Self { - let new_ils: Self; - new_ils.width = width; - new_ils.height = height; - - new_ils - } - pub fn new_with_width_height_pixels(width: usize, height: usize, pixels: &Vec) -> Self { //super(width, height);