From 76e8998f4b803f8dc64c073267e80f6e1910ef19 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 7 Feb 2024 13:22:07 -0600 Subject: [PATCH] stage: moving performance enhancements into main several incomplete features are gated behind the `experimental_features` flag. --- crates/cli/Cargo.toml | 3 + src/buffered_image_luminance_source.rs | 13 +- src/common/BitArrayTestCase.rs | 87 ++++++- src/common/adaptive_threshold_binarizer.rs | 95 ++++++++ src/common/bit_array.rs | 148 +++++------- src/common/bit_matrix.rs | 47 ++-- src/common/bit_matrix_test_case.rs | 2 +- src/common/bit_source.rs | 26 ++ src/common/bit_source_builder.rs | 18 ++ src/common/eci_string_builder.rs | 15 ++ src/common/hybrid_binarizer.rs | 9 +- src/common/mod.rs | 8 + src/datamatrix/decoder/version.rs | 20 +- src/lib.rs | 2 + src/luma_luma_source.rs | 49 ++-- src/luminance_source.rs | 20 +- src/maxicode/detector.rs | 2 +- src/oned/code_128_reader.rs | 216 ++++++++--------- src/oned/cpp/dxfilm_edge_reader.rs | 2 +- src/oned/ean_manufacturer_org_support.rs | 226 +++++++++--------- src/oned/rss/abstract_rss_reader.rs | 9 +- .../decoders/abstract_expanded_decoder.rs | 64 +---- .../expanded/decoders/ai_013x0x1x_decoder.rs | 8 +- src/oned/rss/rss_14_reader.rs | 47 ++-- src/oned/telepen_writer.rs | 4 +- src/oned/upc_ean_extension_5_support.rs | 2 +- src/planar_yuv_luminance_source.rs | 11 +- src/qrcode/decoder/error_correction_level.rs | 4 +- src/qrcode/decoder/version.rs | 37 +-- .../decoder/version_build_versions_arrays.rs | 28 +-- src/qrcode/encoder/bit_vector_testcase.rs | 2 +- src/rgb_luminance_source.rs | 6 +- tests/dx_film_edge.rs | 2 +- 33 files changed, 684 insertions(+), 548 deletions(-) create mode 100644 src/common/adaptive_threshold_binarizer.rs diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 2b9ae78..22b07a8 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -12,3 +12,6 @@ keywords = ["barcode", "2d_barcode", "1d_barcode", "barcode_reader", "barcode_wr [dependencies] clap = { version = "4.4.13", features = ["derive"] } rxing = {path = "../../", version = "~0.5.7", features = ["image", "svg_read", "svg_write"] } + +#[profile.release] +#debug = true \ No newline at end of file diff --git a/src/buffered_image_luminance_source.rs b/src/buffered_image_luminance_source.rs index 67e8f18..74ed2c4 100644 --- a/src/buffered_image_luminance_source.rs +++ b/src/buffered_image_luminance_source.rs @@ -66,6 +66,9 @@ impl BufferedImageLuminanceSource { } impl LuminanceSource for BufferedImageLuminanceSource { + const SUPPORTS_CROP: bool = true; + const SUPPORTS_ROTATION: bool = true; + fn get_row(&self, y: usize) -> Vec { let width = self.get_width(); // - self.left as usize; @@ -87,8 +90,6 @@ impl LuminanceSource for BufferedImageLuminanceSource { } fn get_column(&self, x: usize) -> Vec { - let width = self.get_height(); // - self.left as usize; - let pixels: Vec = || -> Option> { Some( self.image @@ -153,10 +154,6 @@ impl LuminanceSource for BufferedImageLuminanceSource { self.height } - fn is_crop_supported(&self) -> bool { - true - } - fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result { Ok(Self { image: self.image.clone(), @@ -167,10 +164,6 @@ impl LuminanceSource for BufferedImageLuminanceSource { }) } - fn is_rotate_supported(&self) -> bool { - true - } - fn invert(&mut self) { let mut img = (*self.image).clone(); img.invert(); diff --git a/src/common/BitArrayTestCase.rs b/src/common/BitArrayTestCase.rs index 6dad57e..4ca8853 100644 --- a/src/common/BitArrayTestCase.rs +++ b/src/common/BitArrayTestCase.rs @@ -136,7 +136,7 @@ fn test_get_next_set5() { #[test] fn test_set_bulk() { let mut array = BitArray::with_size(64); - array.setBulk(32, 0xFFFF0000); + array.setBulk(32, 0b11111111111111110000000000000000); for i in 0..48 { // for (int i = 0; i < 48; i++) { assert!(!array.get(i)); @@ -150,7 +150,7 @@ fn test_set_bulk() { #[test] fn test_append_bit() { let mut array = BitArray::new(); - array.appendBits(0x000001E, 6).expect("must append)"); + array.appendBits(0b11110, 6).expect("must append)"); let mut array_2 = BitArray::new(); array_2.appendBit(false); array_2.appendBit(true); @@ -159,7 +159,9 @@ fn test_append_bit() { array_2.appendBit(true); array_2.appendBit(false); - assert_eq!(array, array_2) + assert_eq!(array.get_size(), array_2.get_size()); + + assert_eq!(array.getBitArray(), array_2.getBitArray()) } #[test] @@ -234,18 +236,37 @@ fn test_is_range() { #[test] fn reverse_algorithm_test() { - let oldBits: Vec = vec![128, 256, 512, 6453324, 50934953]; + let oldBits: Vec = vec![128, 256, 512, 6453324, 50934953]; for size in 1..160 { // for (int size = 1; size < 160; size++) { let newBitsOriginal = reverse_original(&oldBits.clone(), size); let mut newBitArray = BitArray::with_initial_values(oldBits.clone(), size); newBitArray.reverse(); let newBitsNew = newBitArray.getBitArray(); - assert!(arrays_are_equal( - &newBitsOriginal, - newBitsNew, - size / 32 + 1 - )); + assert!( + arrays_are_equal(&newBitsOriginal, newBitsNew, size / 32 + 1), + "size: ({}) : {:?}/{:?}", + size, + newBitsOriginal, + newBitsNew + ); + } +} + +#[test] +fn reverse_test_2() { + let initial_data: super::BitFieldBaseType = 0b00_00_11_00_00_00_00_00_00_00_00_00_00_00_00_00; + // let expected_data = vec![0b00_00_00_00_00_00_00_00_00_00_00_00_00_11_00_00_u32]; + // let mut array = BitArray::with_initial_values(initial_data.clone(), 4); + for x in 1..=32 { + let expected_data = reverse_original(&[initial_data], x); + let mut array = BitArray::with_size(x); + array.setBulk(0, initial_data); + // dbg!(&array); + assert_eq!(&[initial_data], array.getBitArray()); + array.reverse(); + // dbg!(&array); + assert_eq!(expected_data, array.getBitArray(), "for x = {x}"); } } @@ -271,7 +292,48 @@ fn test_equals() { // assert_eq!(a.hash(), b.hash()); } -fn reverse_original(oldBits: &[u32], size: usize) -> Vec { +#[test] +fn test_xor() { + let val_1: super::BitFieldBaseType = 0b01_00_11; + let val_2: super::BitFieldBaseType = 0b10_11_10; + let mut array_1 = BitArray::with_initial_values(vec![val_1], 32); + let array_2 = BitArray::with_initial_values(vec![val_2], 32); + + array_1.xor(&array_2).expect("xor complete"); + + assert_eq!(array_1.getBitArray(), &[0b11_11_01]); +} + +#[test] +fn test_xor_2() { + for i in 1..33 { + let val_1: super::BitFieldBaseType = 0b01_00_11; + let val_2: super::BitFieldBaseType = 0b10_01_10; + let mut array_1 = BitArray::new(); //BitArray::with_initial_values(vec![val_1], i); + let mut array_2 = BitArray::new(); //BitArray::with_initial_values(vec![val_2], i); + + array_1.appendBits(val_1, i).expect("append"); + array_2.appendBits(val_2, i).expect("append"); + + array_1.xor(&array_2).expect("xor complete"); + + match i { + 1 => assert_eq!(array_1.getBitArray(), &[0b1]), + 2 => assert_eq!(array_1.getBitArray(), &[0b10]), + 3 => assert_eq!(array_1.getBitArray(), &[0b10_1]), + 4 => assert_eq!(array_1.getBitArray(), &[0b10_10]), + 5 => assert_eq!(array_1.getBitArray(), &[0b10_10_1]), + 6 => assert_eq!(array_1.getBitArray(), &[0b10_10_11]), + 7..=24 => assert_eq!(array_1.getBitArray(), &[0b10_10_11 << (i - 6)], "{i}"), + _ => assert_eq!(array_1.getBitArray(), &[0b10_10_11 << i - 6, 0], "{i}"), + } + } +} + +fn reverse_original( + oldBits: &[super::BitFieldBaseType], + size: usize, +) -> Vec { let mut newBits = vec![0; oldBits.len()]; for i in 0..size { // for (int i = 0; i < size; i++) { @@ -282,13 +344,12 @@ fn reverse_original(oldBits: &[u32], size: usize) -> Vec { newBits } -fn bit_set(bits: &[u32], i: usize) -> bool { +fn bit_set(bits: &[super::BitFieldBaseType], i: usize) -> bool { (bits[i / 32] & (1 << (i & 0x1F))) != 0 } -fn arrays_are_equal(left: &[u32], right: &[u32], size: usize) -> bool { +fn arrays_are_equal(left: &[T], right: &[T], size: usize) -> bool { for i in 0..size { - // for (int i = 0; i < size; i++) { if left[i] != right[i] { return false; } diff --git a/src/common/adaptive_threshold_binarizer.rs b/src/common/adaptive_threshold_binarizer.rs new file mode 100644 index 0000000..7d51966 --- /dev/null +++ b/src/common/adaptive_threshold_binarizer.rs @@ -0,0 +1,95 @@ +use std::borrow::Cow; + +use image::{DynamicImage, ImageBuffer, Luma}; +use once_cell::sync::OnceCell; + +use crate::{Binarizer, Exceptions, LuminanceSource}; + +use super::{BitArray, BitMatrix, Result}; + +/// The `AdaptiveThresholdBinarizer` works using the `imageproc::contrast::adaptive_threshold` +/// function. This is an alternative to the other Binarizers available. It is largely +/// untested. +pub struct AdaptiveThresholdBinarizer { + source: LS, + matrix: OnceCell, + radius: u32, +} + +impl AdaptiveThresholdBinarizer { + pub fn new(source: LS, radius: u32) -> Self { + Self { + source, + radius, + matrix: OnceCell::new(), + } + } +} + +impl AdaptiveThresholdBinarizer { + fn buildMatrix(&self) -> Result { + let image_buffer = { + let Some(buff): Option, Vec>> = ImageBuffer::from_vec( + self.source.get_width() as u32, + self.source.get_height() as u32, + self.source.get_matrix(), + ) else { + return Err(Exceptions::ILLEGAL_ARGUMENT); + }; + buff + }; + + let filtered_iamge = + imageproc::contrast::adaptive_threshold(&image_buffer, self.radius.into()); + + let dynamic_filtered = DynamicImage::from(filtered_iamge); + + dynamic_filtered.try_into() + } +} + +impl Binarizer for AdaptiveThresholdBinarizer { + type Source = LS; + + fn get_luminance_source(&self) -> &Self::Source { + &self.source + } + + fn get_black_row(&self, y: usize) -> Result> { + let matrix = self.matrix.get_or_try_init(|| self.buildMatrix())?; + Ok(Cow::Owned(matrix.getRow(y as u32))) + } + + fn get_black_matrix(&self) -> super::Result<&BitMatrix> { + self.matrix.get_or_try_init(|| self.buildMatrix()) + } + + fn get_black_line(&self, l: usize, lt: super::LineOrientation) -> Result> { + match lt { + super::LineOrientation::Row => self.get_black_row(l), + super::LineOrientation::Column => { + let matrix = self.matrix.get_or_try_init(|| self.buildMatrix())?; + Ok(Cow::Owned(matrix.getCol(l as u32))) + } + } + } + + fn create_binarizer(&self, source: Self::Source) -> Self + where + Self: Sized, + { + Self { + source: source, + matrix: OnceCell::new(), + radius: self.radius, + } + } + + fn get_width(&self) -> usize { + self.source.get_width() + } + + fn get_height(&self) -> usize { + self.source.get_height() + } +} diff --git a/src/common/bit_array.rs b/src/common/bit_array.rs index 5b96873..262d13c 100644 --- a/src/common/bit_array.rs +++ b/src/common/bit_array.rs @@ -18,13 +18,15 @@ // import java.util.Arrays; -use std::ops::Index; use std::{cmp, fmt}; use crate::common::Result; use crate::Exceptions; -static LOAD_FACTOR: f32 = 0.75; +const LOAD_FACTOR: f32 = 0.75; + +type BaseType = super::BitFieldBaseType; +const BASE_BITS: usize = super::BIT_FIELD_BASE_BITS; /** *

A simple, fast array of bits, represented compactly by an array of ints internally.

@@ -33,7 +35,7 @@ static LOAD_FACTOR: f32 = 0.75; */ #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct BitArray { - bits: Vec, + bits: Vec, size: usize, } @@ -47,14 +49,14 @@ impl BitArray { pub fn with_size(size: usize) -> Self { Self { - bits: BitArray::makeArray(size), + bits: makeArray(size), size, } } /// For testing only #[cfg(test)] - pub fn with_initial_values(bits: Vec, size: usize) -> Self { + pub fn with_initial_values(bits: Vec, size: usize) -> Self { Self { bits, size } } @@ -66,12 +68,14 @@ impl BitArray { (self.size + 7) / 8 } + #[inline] fn ensure_capacity(&mut self, newSize: usize) { - if newSize > self.bits.len() * 32 { - 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; + let target_size = (newSize as f32 / LOAD_FACTOR).ceil() as usize; + let array_desired_length = (target_size + BASE_BITS - 1) / BASE_BITS; + + if self.bits.len() < array_desired_length { + let additional_capacity = array_desired_length - self.bits.len(); + self.bits.extend(vec![0; additional_capacity]); } } @@ -80,11 +84,11 @@ impl BitArray { * @return true iff bit i is set */ pub fn get(&self, i: usize) -> bool { - (self.bits[i / 32] & (1 << (i & 0x1F))) != 0 + (self.bits[i / BASE_BITS] & (1 << (i & 0x1F))) != 0 } pub fn try_get(&self, i: usize) -> Option { - if (i / 32) >= self.bits.len() { + if (i / BASE_BITS) >= self.bits.len() { None } else { Some(self.get(i)) @@ -97,7 +101,7 @@ impl BitArray { * @param i bit to set */ pub fn set(&mut self, i: usize) { - self.bits[i / 32] |= 1 << (i & 0x1F); + self.bits[i / BASE_BITS] |= 1 << (i & 0x1F); } /** @@ -106,7 +110,7 @@ impl BitArray { * @param i bit to set */ pub fn flip(&mut self, i: usize) { - self.bits[i / 32] ^= 1 << (i & 0x1F); + self.bits[i / BASE_BITS] ^= 1 << (i & 0x1F); } /** @@ -119,7 +123,7 @@ impl BitArray { if from >= self.size { return self.size; } - let mut bitsOffset = from / 32; + let mut bitsOffset = from / BASE_BITS; let mut currentBits = self.bits[bitsOffset] as i64; // mask off lesser bits first currentBits &= -(1 << (from & 0x1F)); @@ -130,7 +134,7 @@ impl BitArray { } currentBits = self.bits[bitsOffset] as i64; } - let result = (bitsOffset * 32) + currentBits.trailing_zeros() as usize; + let result = (bitsOffset * BASE_BITS) + currentBits.trailing_zeros() as usize; cmp::min(result, self.size) } @@ -143,7 +147,7 @@ impl BitArray { if from >= self.size { return self.size; } - let mut bitsOffset = from / 32; + let mut bitsOffset = from / BASE_BITS; let mut currentBits = !self.bits[bitsOffset] as i64; // mask off lesser bits first currentBits &= -(1 << (from & 0x1F)); @@ -154,7 +158,7 @@ impl BitArray { } currentBits = !self.bits[bitsOffset] as i64; } - let result = (bitsOffset * 32) + currentBits.trailing_zeros() as usize; + let result = (bitsOffset * BASE_BITS) + currentBits.trailing_zeros() as usize; cmp::min(result, self.size) } @@ -165,8 +169,8 @@ 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(&mut self, i: usize, newBits: u32) { - self.bits[i / 32] = newBits; + pub fn setBulk(&mut self, i: usize, newBits: BaseType) { + self.bits[i / BASE_BITS] = newBits; } /** @@ -184,15 +188,15 @@ impl BitArray { return Ok(()); } end -= 1; // will be easier to treat this as the last actually set bit -- inclusive - let firstInt = start / 32; - let lastInt = end / 32; + let firstInt = start / BASE_BITS; + let lastInt = end / BASE_BITS; for i in firstInt..=lastInt { //for (int i = firstInt; i <= lastInt; i++) { let firstBit = if i > firstInt { 0 } else { start & 0x1F }; let lastBit = if i < lastInt { 31 } else { end & 0x1F }; // Ones from firstBit to lastBit, inclusive let mask: u64 = (2 << lastBit) - (1 << firstBit); - self.bits[i] |= mask as u32; + self.bits[i] |= mask as BaseType; } Ok(()) } @@ -201,11 +205,6 @@ impl BitArray { * Clears all bits (sets to false). */ pub fn clear(&mut self) { - // let max = self.bits.len(); - // for i in 0..max { - // //for (int i = 0; i < max; i++) { - // self.bits[i] = 0; - // } self.bits.fill(0); } @@ -227,8 +226,8 @@ impl BitArray { return Ok(true); // empty range matches } end -= 1; // will be easier to treat this as the last actually set bit -- inclusive - let firstInt = start / 32; - let lastInt = end / 32; + let firstInt = start / BASE_BITS; + let lastInt = end / BASE_BITS; for i in firstInt..=lastInt { //for (int i = firstInt; i <= lastInt; i++) { let firstBit = if i > firstInt { 0 } else { start & 0x1F }; @@ -238,7 +237,7 @@ impl BitArray { // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, // equals the mask, or we're looking for 0s and the masked portion is not all 0s - if (self.bits[i] & mask as u32) != (if value { mask as u32 } else { 0 }) { + if (self.bits[i] & mask as BaseType) != (if value { mask as BaseType } else { 0 }) { return Ok(false); } } @@ -248,7 +247,7 @@ impl BitArray { pub fn appendBit(&mut self, bit: bool) { self.ensure_capacity(self.size + 1); if bit { - self.bits[self.size / 32] |= 1 << (self.size & 0x1F); + self.bits[self.size / BASE_BITS] |= 1 << (self.size & 0x1F); } self.size += 1; } @@ -261,11 +260,12 @@ impl BitArray { * @param value {@code int} containing bits to append * @param numBits bits from value to append */ - pub fn appendBits(&mut self, value: u32, num_bits: usize) -> Result<()> { - if num_bits > 32 { - return Err(Exceptions::illegal_argument_with( - "num bits must be between 0 and 32", - )); + pub fn appendBits(&mut self, value: BaseType, num_bits: usize) -> Result<()> { + if num_bits > BASE_BITS { + return Err(Exceptions::illegal_argument_with(format!( + "num bits must be between 0 and {}", + BaseType::BITS + ))); } if num_bits == 0 { @@ -277,7 +277,7 @@ impl BitArray { for numBitsLeft in (0..num_bits).rev() { //for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) { if (value & (1 << numBitsLeft)) != 0 { - self.bits[next_size / 32] |= 1 << (next_size & 0x1F); + self.bits[next_size / BASE_BITS] |= 1 << (next_size & 0x1F); } next_size += 1; } @@ -298,11 +298,11 @@ impl BitArray { if self.size != other.size { return Err(Exceptions::illegal_argument_with("Sizes don't match")); } - for i in 0..self.bits.len() { + for (lhs, rhs) in self.bits.iter_mut().zip(other.bits.iter()) { //for (int i = 0; i < bits.length; i++) { // The last int could be incomplete (i.e. not have 32 bits in // it) but there is no problem since 0 XOR 0 == 0. - self.bits[i] ^= other.bits[i]; + *lhs ^= rhs; } Ok(()) } @@ -335,7 +335,7 @@ 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) -> &[u32] { + pub fn getBitArray(&self) -> &[BaseType] { &self.bits } @@ -343,52 +343,35 @@ impl BitArray { * Reverses all bits in the array. */ pub fn reverse(&mut self) { - let mut newBits = vec![0; self.bits.len()]; + // let mut newBits = vec![0; self.bits.len()]; // reverse all int's first let len = (self.size - 1) / 32; let oldBitsLen = len + 1; - for i in 0..oldBitsLen { - //for (int i = 0; i < oldBitsLen; i++) { - newBits[len - i] = self.bits[i].reverse_bits(); - } + // let array_size = self.size.div_ceil(BASE_TYPE::BITS as usize); + + // for (new_bits, old_bits) in newBits.iter_mut().take(oldBitsLen).zip(self.bits.iter().take(oldBitsLen).rev()) { + // *new_bits = old_bits.reverse_bits(); + // } + self.bits[..oldBitsLen].reverse(); + self.bits[..oldBitsLen] + .iter_mut() + .for_each(|bit_store| *bit_store = bit_store.reverse_bits()); + self.bits[oldBitsLen..].fill(0); + // 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 mut currentInt = newBits[0] >> leftOffset; + if self.size != oldBitsLen * BASE_BITS { + let leftOffset = oldBitsLen * BASE_BITS - self.size; + let mut currentInt = self.bits[0] >> leftOffset; for i in 1..oldBitsLen { //for (int i = 1; i < oldBitsLen; i++) { - let nextInt = newBits[i]; - currentInt |= nextInt << (32 - leftOffset); - newBits[i - 1] = currentInt; + let nextInt = self.bits[i]; + currentInt |= nextInt << (BASE_BITS - leftOffset); + self.bits[i - 1] = currentInt; currentInt = nextInt >> leftOffset; } - newBits[oldBitsLen - 1] = currentInt; + self.bits[oldBitsLen - 1] = currentInt; } - self.bits = newBits; } - - fn makeArray(size: usize) -> Vec { - vec![0; (size + 31) / 32] - } - - // @Override - // public boolean equals(Object o) { - // if (!(o instanceof BitArray)) { - // return false; - // } - // BitArray other = (BitArray) o; - // return size == other.size && Arrays.equals(bits, other.bits); - // } - - // @Override - // public int hashCode() { - // return 31 * size + Arrays.hashCode(bits); - // } - - // @Override - // public BitArray clone() { - // return new BitArray(bits.clone(), size); - // } } impl fmt::Display for BitArray { @@ -427,13 +410,6 @@ impl From<&BitArray> for Vec { impl From for Vec { fn from(value: BitArray) -> Self { - // let mut array = vec![false; value.size]; - - // for (pixel, element) in array.iter_mut().enumerate().take(value.size) { - // *element = value.get(pixel); - // } - - // array Self::from(&value) } } @@ -449,3 +425,7 @@ impl From<&BitArray> for Vec { array } } + +fn makeArray(size: usize) -> Vec { + vec![0; (size + BASE_BITS - 1) / BASE_BITS] +} diff --git a/src/common/bit_matrix.rs b/src/common/bit_matrix.rs index 8d4b14c..32771f7 100644 --- a/src/common/bit_matrix.rs +++ b/src/common/bit_matrix.rs @@ -25,6 +25,9 @@ use crate::{point_f, point_i, Exceptions, Point}; use super::BitArray; +type BaseType = super::BitFieldBaseType; +const BASE_BITS: usize = super::BIT_FIELD_BASE_BITS; + /** *

Represents a 2D matrix of bits. In function arguments below, and throughout the common * module, x is the column position, and y is the row position. The ordering is always x, y. @@ -45,7 +48,7 @@ pub struct BitMatrix { width: u32, height: u32, row_size: usize, - bits: Vec, + bits: Vec, } impl BitMatrix { @@ -73,8 +76,11 @@ impl BitMatrix { Ok(Self { width, height, - row_size: ((width + 31) / 32) as usize, - bits: vec![0; (((width + 31) / 32) * height) as usize], + row_size: ((width as usize + BASE_BITS - 1) / BASE_BITS) as usize, + bits: vec![ + 0; + (((width as usize + BASE_BITS - 1) / BASE_BITS) * height as usize) as usize + ], }) // this.width = width; // this.height = height; @@ -83,7 +89,7 @@ impl BitMatrix { } #[allow(dead_code)] - fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec) -> Self { + fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec) -> Self { Self { width, height, @@ -235,7 +241,7 @@ impl BitMatrix { #[inline(always)] fn get_offset(&self, y: u32, x: u32) -> usize { - y as usize * self.row_size + (x as usize / 32) + y as usize * self.row_size + (x as usize / BASE_BITS) } pub fn try_get(&self, x: u32, y: u32) -> Option { @@ -387,7 +393,7 @@ impl BitMatrix { let offset = y as usize * self.row_size; for x in left..right { //for (int x = left; x < right; x++) { - self.bits[offset + (x as usize / 32)] |= 1 << (x & 0x1f); + self.bits[offset + (x as usize / BASE_BITS)] |= 1 << (x & 0x1f); } } Ok(()) @@ -407,7 +413,7 @@ impl BitMatrix { let offset = y as usize * self.row_size; for x in 0..self.row_size { //for (int x = 0; x < rowSize; x++) { - rw.setBulk(x * 32, self.bits[offset + x]); + rw.setBulk(x * BASE_BITS, self.bits[offset + x]); } rw } @@ -489,7 +495,7 @@ impl BitMatrix { pub fn rotate90(&mut self) { let newWidth = self.height; let newHeight = self.width; - let newRowSize = (newWidth + 31) / 32; + let newRowSize = (newWidth + BASE_BITS as u32 - 1) / BASE_BITS as u32; let mut newBits = vec![0; (newRowSize * newHeight) as usize]; for y in 0..self.height { @@ -498,7 +504,8 @@ impl BitMatrix { //for (int x = 0; x < width; x++) { let offset = self.get_offset(y, x); if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 { - let newOffset: usize = ((newHeight - 1 - x) * newRowSize + (y / 32)) as usize; + let newOffset: usize = + ((newHeight - 1 - x) * newRowSize + (y / BASE_BITS as u32)) as usize; newBits[newOffset] |= 1 << (y & 0x1f); } } @@ -531,22 +538,22 @@ impl BitMatrix { top = top.min(y); bottom = bottom.max(y); - if x32 * 32 < left as usize { + if x32 * BASE_BITS < left as usize { let mut bit = 0; - while (theBits << (31 - bit)) == 0 { + while (theBits << (BASE_BITS - 1 - bit)) == 0 { bit += 1; } - if (x32 * 32 + bit) < left as usize { - left = (x32 * 32 + bit) as u32; + if (x32 * BASE_BITS + bit) < left as usize { + left = (x32 * BASE_BITS + bit) as u32; } } - if x32 * 32 + 31 > right as usize { - let mut bit = 31; + if x32 * BASE_BITS + BASE_BITS - 1 > right as usize { + let mut bit = BASE_BITS - 1; while (theBits >> bit) == 0 { bit -= 1; } - if (x32 * 32 + bit) > right as usize { - right = (x32 * 32 + bit) as u32; + if (x32 * BASE_BITS + bit) > right as usize { + right = (x32 * BASE_BITS + bit) as u32; } } } @@ -574,7 +581,7 @@ impl BitMatrix { return None; } let y = bitsOffset / self.row_size; - let mut x = (bitsOffset % self.row_size) * 32; + let mut x = (bitsOffset % self.row_size) * BASE_BITS; let theBits = self.bits[bitsOffset]; let mut bit = 0; @@ -595,10 +602,10 @@ impl BitMatrix { } let y = bitsOffset as usize / self.row_size; - let mut x = (bitsOffset as usize % self.row_size) * 32; + let mut x = (bitsOffset as usize % self.row_size) * BASE_BITS; let theBits = self.bits[bitsOffset as usize]; - let mut bit = 31; + let mut bit = BASE_BITS - 1; while (theBits >> bit) == 0 { bit -= 1; } diff --git a/src/common/bit_matrix_test_case.rs b/src/common/bit_matrix_test_case.rs index 18bbdf4..205bb88 100644 --- a/src/common/bit_matrix_test_case.rs +++ b/src/common/bit_matrix_test_case.rs @@ -31,7 +31,7 @@ use crate::point_f; use super::BitMatrix; -static BIT_MATRIX_POINTS: [u32; 6] = [1, 2, 2, 0, 3, 1]; +const BIT_MATRIX_POINTS: [u32; 6] = [1, 2, 2, 0, 3, 1]; #[test] fn test_get_set() { diff --git a/src/common/bit_source.rs b/src/common/bit_source.rs index 795209d..ccbf987 100644 --- a/src/common/bit_source.rs +++ b/src/common/bit_source.rs @@ -17,6 +17,7 @@ //package com.google.zxing.common; use std::cmp; +use std::io::{ErrorKind, Read}; use crate::common::Result; use crate::Exceptions; @@ -173,3 +174,28 @@ impl BitSource { 8 * (self.bytes.len() - self.byte_offset) - self.bit_offset } } + +impl Read for BitSource { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let requested_bytes = buf.len(); + let available = self.available(); + + let to_read = if requested_bytes <= available { + requested_bytes + } else { + available + }; + + for byte in buf.iter_mut().take(to_read) { + let Ok(bits) = self.readBits(8) else { + return Err(std::io::Error::new( + ErrorKind::Unsupported, + "unable to read bits", + )); + }; + *byte = bits as u8; + } + + Ok(to_read) + } +} diff --git a/src/common/bit_source_builder.rs b/src/common/bit_source_builder.rs index 2925a36..f82b602 100644 --- a/src/common/bit_source_builder.rs +++ b/src/common/bit_source_builder.rs @@ -18,6 +18,8 @@ // import java.io.ByteArrayOutputStream; +use std::io::Write; + /** * Class that lets one easily build an array of bytes by appending bits at a time. * @@ -71,3 +73,19 @@ impl Default for BitSourceBuilder { Self::new() } } + +impl Write for BitSourceBuilder { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let mut written = 0; + for byte in buf.iter() { + self.write(*byte as u32, 8); + written += 1; + } + + Ok(written) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} diff --git a/src/common/eci_string_builder.rs b/src/common/eci_string_builder.rs index 031bcff..544c6bc 100644 --- a/src/common/eci_string_builder.rs +++ b/src/common/eci_string_builder.rs @@ -349,3 +349,18 @@ impl Default for SymbologyIdentifier { } } } + +impl std::io::Write for ECIStringBuilder { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if buf.len() == 1 { + self.append_byte(buf[0]); + } else { + self.append_bytes(buf); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} diff --git a/src/common/hybrid_binarizer.rs b/src/common/hybrid_binarizer.rs index f96d6ec..e1f795f 100644 --- a/src/common/hybrid_binarizer.rs +++ b/src/common/hybrid_binarizer.rs @@ -175,12 +175,12 @@ impl HybridBinarizer { // for (int y = 0; y < subHeight; y++) { let yoffset = u32::min(y << BLOCK_SIZE_POWER, maxYOffset); - let top = Self::cap(y, sub_height - 3); + let top = u32::clamp(y, 2, sub_height - 3); // Self::cap(y, sub_height - 3); for x in 0..sub_width { // for (int x = 0; x < subWidth; x++) { let xoffset = u32::min(x << BLOCK_SIZE_POWER, maxXOffset); - let left = Self::cap(x, sub_width - 3); + let left = u32::clamp(x, 2, sub_width - 3); //Self::cap(x, sub_width - 3); let mut sum = 0; for z in -2..=2 { // for (int z = -2; z <= 2; z++) { @@ -197,11 +197,6 @@ impl HybridBinarizer { } } - #[inline(always)] - fn cap(value: u32, max: u32) -> u32 { - u32::clamp(value, 2, max) - } - /** * Applies a single threshold to a block of pixels. */ diff --git a/src/common/mod.rs b/src/common/mod.rs index fe878d1..c4b5af1 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -121,3 +121,11 @@ pub use line_orientation::LineOrientation; mod otsu_level_binarizer; #[cfg(feature = "otsu_level")] pub use otsu_level_binarizer::*; + +#[cfg(feature = "image")] +mod adaptive_threshold_binarizer; +#[cfg(feature = "image")] +pub use adaptive_threshold_binarizer::*; + +pub type BitFieldBaseType = u32; +pub const BIT_FIELD_BASE_BITS: usize = BitFieldBaseType::BITS as usize; diff --git a/src/datamatrix/decoder/version.rs b/src/datamatrix/decoder/version.rs index 4879e21..1886d9a 100644 --- a/src/datamatrix/decoder/version.rs +++ b/src/datamatrix/decoder/version.rs @@ -20,7 +20,7 @@ use once_cell::sync::Lazy; use crate::common::Result; use crate::Exceptions; -static VERSIONS: Lazy> = Lazy::new(Version::buildVersions); +static VERSIONS: Lazy> = Lazy::new(Version::buildVersions); pub type VersionRef = &'static Version; @@ -118,8 +118,8 @@ impl Version { /** * See ISO 16022:2006 5.5.1 Table 7 */ - fn buildVersions() -> Vec { - vec![ + fn buildVersions() -> Box<[Version]> { + Box::new([ Version::new(1, 10, 10, 8, 8, ECBlocks::new(5, ECB::new(1, 3))), Version::new(2, 12, 12, 10, 10, ECBlocks::new(7, ECB::new(1, 5))), Version::new(3, 14, 14, 12, 12, ECBlocks::new(10, ECB::new(1, 8))), @@ -177,7 +177,7 @@ impl Version { Version::new(46, 26, 40, 24, 18, ECBlocks::new(38, ECB::new(1, 70))), Version::new(47, 26, 48, 24, 22, ECBlocks::new(42, ECB::new(1, 90))), Version::new(48, 26, 64, 24, 14, ECBlocks::new(50, ECB::new(1, 118))), - ] + ]) } } @@ -195,20 +195,20 @@ impl fmt::Display for Version { */ pub struct ECBlocks { ecCodewords: u32, - ecBlocks: Vec, + ecBlocks: Box<[ECB]>, } impl ECBlocks { pub fn new(ecCodewords: u32, ecBlocks: ECB) -> Self { Self { ecCodewords, - ecBlocks: vec![ecBlocks], + ecBlocks: Box::new([ecBlocks]), } } pub fn new2(ecCodewords: u32, ecBlocks1: ECB, ecBlocks2: ECB) -> Self { Self { ecCodewords, - ecBlocks: vec![ecBlocks1, ecBlocks2], + ecBlocks: Box::new([ecBlocks1, ecBlocks2]), } } @@ -231,18 +231,18 @@ pub struct ECB { dataCodewords: u32, } impl ECB { - pub fn new(count: u32, dataCodewords: u32) -> Self { + pub const fn new(count: u32, dataCodewords: u32) -> Self { Self { count, dataCodewords, } } - pub fn getCount(&self) -> u32 { + pub const fn getCount(&self) -> u32 { self.count } - pub fn getDataCodewords(&self) -> u32 { + pub const fn getDataCodewords(&self) -> u32 { self.dataCodewords } } diff --git a/src/lib.rs b/src/lib.rs index b312d08..4091de5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,9 @@ pub mod helpers; mod luma_luma_source; pub use luma_luma_source::*; +#[cfg(feature = "experimental_features")] mod filtered_image_reader; +#[cfg(feature = "experimental_features")] pub use filtered_image_reader::*; #[cfg(feature = "svg_read")] diff --git a/src/luma_luma_source.rs b/src/luma_luma_source.rs index 11ec515..9cf1fce 100644 --- a/src/luma_luma_source.rs +++ b/src/luma_luma_source.rs @@ -9,13 +9,16 @@ pub struct Luma8LuminanceSource { /// image origin in the form (x,y) origin: (u32, u32), /// raw data for luma 8 - data: Vec, + data: Box<[u8]>, /// flag indicating if the underlying data needs to be inverted for use inverted: bool, /// original dimensions of the data, used to manage crop original_dimension: (u32, u32), } impl LuminanceSource for Luma8LuminanceSource { + const SUPPORTS_CROP: bool = true; + const SUPPORTS_ROTATION: bool = true; + fn get_row(&self, y: usize) -> Vec { let chunk_size = self.original_dimension.0 as usize; let row_skip = y + self.origin.1 as usize; @@ -30,16 +33,6 @@ impl LuminanceSource for Luma8LuminanceSource { } else { Vec::from(&self.data[data_start..data_end]) } - - // self.data - // .chunks_exact(chunk_size) - // .skip(row_skip) - // .take(1) - // .flatten() - // .skip(column_skip) - // .take(column_take) - // .map(|byte| Self::invert_if_should(*byte, self.inverted)) - // .collect() } fn get_column(&self, x: usize) -> Vec { @@ -85,10 +78,6 @@ impl LuminanceSource for Luma8LuminanceSource { self.inverted = !self.inverted; } - fn is_crop_supported(&self) -> bool { - true - } - fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result { Ok(Self { dimensions: (width as u32, height as u32), @@ -99,10 +88,6 @@ impl LuminanceSource for Luma8LuminanceSource { }) } - fn is_rotate_supported(&self) -> bool { - true - } - fn rotate_counter_clockwise(&self) -> Result { let mut new_matrix = Self { dimensions: self.dimensions, @@ -123,7 +108,14 @@ impl LuminanceSource for Luma8LuminanceSource { } fn get_luma8_point(&self, column: usize, row: usize) -> u8 { - self.get_row(row)[column] + let chunk_size = self.original_dimension.0 as usize; + let row_skip = row + self.origin.1 as usize; + let column_skip = self.origin.0 as usize; + + let data_start = (chunk_size * row_skip) + column_skip; + let data_point = data_start + column; + + Self::invert_if_should(self.data[data_point], self.inverted) } } @@ -163,7 +155,7 @@ impl Luma8LuminanceSource { new_data[offset_b] = self.data[offset_a]; } } - self.data = new_data; + self.data = new_data.into_boxed_slice(); self.dimensions = new_dim; self.original_dimension = (self.original_dimension.1, self.original_dimension.0); self.origin = (self.origin.1, self.origin.0); @@ -184,7 +176,7 @@ impl Luma8LuminanceSource { Self { dimensions: (width, height), origin: (0, 0), - data: source, + data: source.into_boxed_slice(), inverted: false, original_dimension: (width, height), } @@ -194,13 +186,13 @@ impl Luma8LuminanceSource { Self { dimensions: (width as u32, height as u32), origin: (0, 0), - data: vec![0u8; width * height], + data: vec![0u8; width * height].into_boxed_slice(), inverted: false, original_dimension: (width as u32, height as u32), } } - pub fn get_matrix_mut(&mut self) -> &mut Vec { + pub fn get_matrix_mut(&mut self) -> &mut Box<[u8]> { &mut self.data } @@ -244,16 +236,19 @@ mod tests { (rect_wide.dimensions.1, rect_wide.dimensions.0) ); - assert_eq!(rotated_square.data, vec![3, 6, 9, 2, 5, 8, 1, 4, 7]); + assert_eq!( + rotated_square.data, + vec![3, 6, 9, 2, 5, 8, 1, 4, 7].into_boxed_slice() + ); assert_eq!( rotated_wide_rect.data, - vec![1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1] + vec![1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1].into_boxed_slice() ); assert_eq!( rotated_tall_rect.data, - vec![0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0] + vec![0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0].into_boxed_slice() ); } } diff --git a/src/luminance_source.rs b/src/luminance_source.rs index 54ee32d..0599a2e 100644 --- a/src/luminance_source.rs +++ b/src/luminance_source.rs @@ -29,8 +29,8 @@ use crate::Exceptions; * @author dswitkin@google.com (Daniel Switkin) */ pub trait LuminanceSource { - //private final int width; - //private final int height; + const SUPPORTS_ROTATION: bool = false; + const SUPPORTS_CROP: bool = false; //fn new( width:usize, height:usize) -> Self; @@ -75,7 +75,14 @@ pub trait LuminanceSource { * @return Whether this subclass supports cropping. */ fn is_crop_supported(&self) -> bool { - false + Self::SUPPORTS_CROP + } + + /** + * @return Whether this subclass supports counter-clockwise rotation. + */ + fn is_rotate_supported(&self) -> bool { + Self::SUPPORTS_ROTATION } /** @@ -97,13 +104,6 @@ pub trait LuminanceSource { )) } - /** - * @return Whether this subclass supports counter-clockwise rotation. - */ - fn is_rotate_supported(&self) -> bool { - false - } - /** * @return a wrapper of this {@code LuminanceSource} which inverts the luminances it returns -- black becomes * white and vice versa, and each value becomes (255-value). diff --git a/src/maxicode/detector.rs b/src/maxicode/detector.rs index d09eb74..df37975 100644 --- a/src/maxicode/detector.rs +++ b/src/maxicode/detector.rs @@ -1143,7 +1143,7 @@ mod detector_test { .read_to_string(&mut expected_result) .unwrap(); - let detection = super::detect(bitmatrix, true).unwrap(); + let detection = super::detect(&bitmatrix, true).unwrap(); // let i: image::DynamicImage = detection.getBits().into(); // i.save("dbgfle-transformed.png") diff --git a/src/oned/code_128_reader.rs b/src/oned/code_128_reader.rs index 952b0e7..efc4bcb 100644 --- a/src/oned/code_128_reader.rs +++ b/src/oned/code_128_reader.rs @@ -433,115 +433,115 @@ impl Code128Reader { use once_cell::sync::Lazy; -pub static CODE_PATTERNS: Lazy<[Vec; 107]> = Lazy::new(|| { +pub static CODE_PATTERNS: Lazy<[Box<[u32]>; 107]> = Lazy::new(|| { [ - vec![2, 1, 2, 2, 2, 2], // 0 - vec![2, 2, 2, 1, 2, 2], - vec![2, 2, 2, 2, 2, 1], - vec![1, 2, 1, 2, 2, 3], - vec![1, 2, 1, 3, 2, 2], - vec![1, 3, 1, 2, 2, 2], // 5 - vec![1, 2, 2, 2, 1, 3], - vec![1, 2, 2, 3, 1, 2], - vec![1, 3, 2, 2, 1, 2], - vec![2, 2, 1, 2, 1, 3], - vec![2, 2, 1, 3, 1, 2], // 10 - vec![2, 3, 1, 2, 1, 2], - vec![1, 1, 2, 2, 3, 2], - vec![1, 2, 2, 1, 3, 2], - vec![1, 2, 2, 2, 3, 1], - vec![1, 1, 3, 2, 2, 2], // 15 - vec![1, 2, 3, 1, 2, 2], - vec![1, 2, 3, 2, 2, 1], - vec![2, 2, 3, 2, 1, 1], - vec![2, 2, 1, 1, 3, 2], - vec![2, 2, 1, 2, 3, 1], // 20 - vec![2, 1, 3, 2, 1, 2], - vec![2, 2, 3, 1, 1, 2], - vec![3, 1, 2, 1, 3, 1], - vec![3, 1, 1, 2, 2, 2], - vec![3, 2, 1, 1, 2, 2], // 25 - vec![3, 2, 1, 2, 2, 1], - vec![3, 1, 2, 2, 1, 2], - vec![3, 2, 2, 1, 1, 2], - vec![3, 2, 2, 2, 1, 1], - vec![2, 1, 2, 1, 2, 3], // 30 - vec![2, 1, 2, 3, 2, 1], - vec![2, 3, 2, 1, 2, 1], - vec![1, 1, 1, 3, 2, 3], - vec![1, 3, 1, 1, 2, 3], - vec![1, 3, 1, 3, 2, 1], // 35 - vec![1, 1, 2, 3, 1, 3], - vec![1, 3, 2, 1, 1, 3], - vec![1, 3, 2, 3, 1, 1], - vec![2, 1, 1, 3, 1, 3], - vec![2, 3, 1, 1, 1, 3], // 40 - vec![2, 3, 1, 3, 1, 1], - vec![1, 1, 2, 1, 3, 3], - vec![1, 1, 2, 3, 3, 1], - vec![1, 3, 2, 1, 3, 1], - vec![1, 1, 3, 1, 2, 3], // 45 - vec![1, 1, 3, 3, 2, 1], - vec![1, 3, 3, 1, 2, 1], - vec![3, 1, 3, 1, 2, 1], - vec![2, 1, 1, 3, 3, 1], - vec![2, 3, 1, 1, 3, 1], // 50 - vec![2, 1, 3, 1, 1, 3], - vec![2, 1, 3, 3, 1, 1], - vec![2, 1, 3, 1, 3, 1], - vec![3, 1, 1, 1, 2, 3], - vec![3, 1, 1, 3, 2, 1], // 55 - vec![3, 3, 1, 1, 2, 1], - vec![3, 1, 2, 1, 1, 3], - vec![3, 1, 2, 3, 1, 1], - vec![3, 3, 2, 1, 1, 1], - vec![3, 1, 4, 1, 1, 1], // 60 - vec![2, 2, 1, 4, 1, 1], - vec![4, 3, 1, 1, 1, 1], - vec![1, 1, 1, 2, 2, 4], - vec![1, 1, 1, 4, 2, 2], - vec![1, 2, 1, 1, 2, 4], // 65 - vec![1, 2, 1, 4, 2, 1], - vec![1, 4, 1, 1, 2, 2], - vec![1, 4, 1, 2, 2, 1], - vec![1, 1, 2, 2, 1, 4], - vec![1, 1, 2, 4, 1, 2], // 70 - vec![1, 2, 2, 1, 1, 4], - vec![1, 2, 2, 4, 1, 1], - vec![1, 4, 2, 1, 1, 2], - vec![1, 4, 2, 2, 1, 1], - vec![2, 4, 1, 2, 1, 1], // 75 - vec![2, 2, 1, 1, 1, 4], - vec![4, 1, 3, 1, 1, 1], - vec![2, 4, 1, 1, 1, 2], - vec![1, 3, 4, 1, 1, 1], - vec![1, 1, 1, 2, 4, 2], // 80 - vec![1, 2, 1, 1, 4, 2], - vec![1, 2, 1, 2, 4, 1], - vec![1, 1, 4, 2, 1, 2], - vec![1, 2, 4, 1, 1, 2], - vec![1, 2, 4, 2, 1, 1], // 85 - vec![4, 1, 1, 2, 1, 2], - vec![4, 2, 1, 1, 1, 2], - vec![4, 2, 1, 2, 1, 1], - vec![2, 1, 2, 1, 4, 1], - vec![2, 1, 4, 1, 2, 1], // 90 - vec![4, 1, 2, 1, 2, 1], - vec![1, 1, 1, 1, 4, 3], - vec![1, 1, 1, 3, 4, 1], - vec![1, 3, 1, 1, 4, 1], - vec![1, 1, 4, 1, 1, 3], // 95 - vec![1, 1, 4, 3, 1, 1], - vec![4, 1, 1, 1, 1, 3], - vec![4, 1, 1, 3, 1, 1], - vec![1, 1, 3, 1, 4, 1], - vec![1, 1, 4, 1, 3, 1], // 100 - vec![3, 1, 1, 1, 4, 1], - vec![4, 1, 1, 1, 3, 1], - vec![2, 1, 1, 4, 1, 2], - vec![2, 1, 1, 2, 1, 4], - vec![2, 1, 1, 2, 3, 2], // 105 - vec![2, 3, 3, 1, 1, 1, 2], + Box::new([2, 1, 2, 2, 2, 2]), // 0 + Box::new([2, 2, 2, 1, 2, 2]), + Box::new([2, 2, 2, 2, 2, 1]), + Box::new([1, 2, 1, 2, 2, 3]), + Box::new([1, 2, 1, 3, 2, 2]), + Box::new([1, 3, 1, 2, 2, 2]), // 5 + Box::new([1, 2, 2, 2, 1, 3]), + Box::new([1, 2, 2, 3, 1, 2]), + Box::new([1, 3, 2, 2, 1, 2]), + Box::new([2, 2, 1, 2, 1, 3]), + Box::new([2, 2, 1, 3, 1, 2]), // 10 + Box::new([2, 3, 1, 2, 1, 2]), + Box::new([1, 1, 2, 2, 3, 2]), + Box::new([1, 2, 2, 1, 3, 2]), + Box::new([1, 2, 2, 2, 3, 1]), + Box::new([1, 1, 3, 2, 2, 2]), // 15 + Box::new([1, 2, 3, 1, 2, 2]), + Box::new([1, 2, 3, 2, 2, 1]), + Box::new([2, 2, 3, 2, 1, 1]), + Box::new([2, 2, 1, 1, 3, 2]), + Box::new([2, 2, 1, 2, 3, 1]), // 20 + Box::new([2, 1, 3, 2, 1, 2]), + Box::new([2, 2, 3, 1, 1, 2]), + Box::new([3, 1, 2, 1, 3, 1]), + Box::new([3, 1, 1, 2, 2, 2]), + Box::new([3, 2, 1, 1, 2, 2]), // 25 + Box::new([3, 2, 1, 2, 2, 1]), + Box::new([3, 1, 2, 2, 1, 2]), + Box::new([3, 2, 2, 1, 1, 2]), + Box::new([3, 2, 2, 2, 1, 1]), + Box::new([2, 1, 2, 1, 2, 3]), // 30 + Box::new([2, 1, 2, 3, 2, 1]), + Box::new([2, 3, 2, 1, 2, 1]), + Box::new([1, 1, 1, 3, 2, 3]), + Box::new([1, 3, 1, 1, 2, 3]), + Box::new([1, 3, 1, 3, 2, 1]), // 35 + Box::new([1, 1, 2, 3, 1, 3]), + Box::new([1, 3, 2, 1, 1, 3]), + Box::new([1, 3, 2, 3, 1, 1]), + Box::new([2, 1, 1, 3, 1, 3]), + Box::new([2, 3, 1, 1, 1, 3]), // 40 + Box::new([2, 3, 1, 3, 1, 1]), + Box::new([1, 1, 2, 1, 3, 3]), + Box::new([1, 1, 2, 3, 3, 1]), + Box::new([1, 3, 2, 1, 3, 1]), + Box::new([1, 1, 3, 1, 2, 3]), // 45 + Box::new([1, 1, 3, 3, 2, 1]), + Box::new([1, 3, 3, 1, 2, 1]), + Box::new([3, 1, 3, 1, 2, 1]), + Box::new([2, 1, 1, 3, 3, 1]), + Box::new([2, 3, 1, 1, 3, 1]), // 50 + Box::new([2, 1, 3, 1, 1, 3]), + Box::new([2, 1, 3, 3, 1, 1]), + Box::new([2, 1, 3, 1, 3, 1]), + Box::new([3, 1, 1, 1, 2, 3]), + Box::new([3, 1, 1, 3, 2, 1]), // 55 + Box::new([3, 3, 1, 1, 2, 1]), + Box::new([3, 1, 2, 1, 1, 3]), + Box::new([3, 1, 2, 3, 1, 1]), + Box::new([3, 3, 2, 1, 1, 1]), + Box::new([3, 1, 4, 1, 1, 1]), // 60 + Box::new([2, 2, 1, 4, 1, 1]), + Box::new([4, 3, 1, 1, 1, 1]), + Box::new([1, 1, 1, 2, 2, 4]), + Box::new([1, 1, 1, 4, 2, 2]), + Box::new([1, 2, 1, 1, 2, 4]), // 65 + Box::new([1, 2, 1, 4, 2, 1]), + Box::new([1, 4, 1, 1, 2, 2]), + Box::new([1, 4, 1, 2, 2, 1]), + Box::new([1, 1, 2, 2, 1, 4]), + Box::new([1, 1, 2, 4, 1, 2]), // 70 + Box::new([1, 2, 2, 1, 1, 4]), + Box::new([1, 2, 2, 4, 1, 1]), + Box::new([1, 4, 2, 1, 1, 2]), + Box::new([1, 4, 2, 2, 1, 1]), + Box::new([2, 4, 1, 2, 1, 1]), // 75 + Box::new([2, 2, 1, 1, 1, 4]), + Box::new([4, 1, 3, 1, 1, 1]), + Box::new([2, 4, 1, 1, 1, 2]), + Box::new([1, 3, 4, 1, 1, 1]), + Box::new([1, 1, 1, 2, 4, 2]), // 80 + Box::new([1, 2, 1, 1, 4, 2]), + Box::new([1, 2, 1, 2, 4, 1]), + Box::new([1, 1, 4, 2, 1, 2]), + Box::new([1, 2, 4, 1, 1, 2]), + Box::new([1, 2, 4, 2, 1, 1]), // 85 + Box::new([4, 1, 1, 2, 1, 2]), + Box::new([4, 2, 1, 1, 1, 2]), + Box::new([4, 2, 1, 2, 1, 1]), + Box::new([2, 1, 2, 1, 4, 1]), + Box::new([2, 1, 4, 1, 2, 1]), // 90 + Box::new([4, 1, 2, 1, 2, 1]), + Box::new([1, 1, 1, 1, 4, 3]), + Box::new([1, 1, 1, 3, 4, 1]), + Box::new([1, 3, 1, 1, 4, 1]), + Box::new([1, 1, 4, 1, 1, 3]), // 95 + Box::new([1, 1, 4, 3, 1, 1]), + Box::new([4, 1, 1, 1, 1, 3]), + Box::new([4, 1, 1, 3, 1, 1]), + Box::new([1, 1, 3, 1, 4, 1]), + Box::new([1, 1, 4, 1, 3, 1]), // 100 + Box::new([3, 1, 1, 1, 4, 1]), + Box::new([4, 1, 1, 1, 3, 1]), + Box::new([2, 1, 1, 4, 1, 2]), + Box::new([2, 1, 1, 2, 1, 4]), + Box::new([2, 1, 1, 2, 3, 2]), // 105 + Box::new([2, 3, 3, 1, 1, 1, 2]), ] }); diff --git a/src/oned/cpp/dxfilm_edge_reader.rs b/src/oned/cpp/dxfilm_edge_reader.rs index 02294e7..b292032 100644 --- a/src/oned/cpp/dxfilm_edge_reader.rs +++ b/src/oned/cpp/dxfilm_edge_reader.rs @@ -265,7 +265,7 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> { for _i in 0..modules { dataBits.appendBits( if next.index() % 2 == 0 { - 0xFFFFFFFF + 0xFFFFFFFF_u32 } else { 0x0 }, diff --git a/src/oned/ean_manufacturer_org_support.rs b/src/oned/ean_manufacturer_org_support.rs index 205a833..506af4b 100644 --- a/src/oned/ean_manufacturer_org_support.rs +++ b/src/oned/ean_manufacturer_org_support.rs @@ -25,15 +25,15 @@ */ pub struct EANManufacturerOrgSupport { - ranges: Vec>, //= new ArrayList<>(); - countryIdentifiers: Vec, // = new ArrayList<>(); + ranges: Vec<[u32; 2]>, //= new ArrayList<>(); + countryIdentifiers: Vec<&'static str>, // = new ArrayList<>(); } impl Default for EANManufacturerOrgSupport { fn default() -> Self { let mut slf = Self { - ranges: Default::default(), - countryIdentifiers: Default::default(), + ranges: Vec::with_capacity(150), + countryIdentifiers: Vec::with_capacity(150), }; slf.initIfNeeded(); slf @@ -42,14 +42,14 @@ impl Default for EANManufacturerOrgSupport { impl EANManufacturerOrgSupport { pub fn lookupCountryIdentifier(&self, productCode: &str) -> Option<&str> { - let prefix = productCode[0..3].parse::().expect("must parse prefix"); + let prefix = productCode[0..3].parse::().ok()?; let max = self.ranges.len(); for (i, range) in self.ranges.iter().enumerate().take(max) { let start = range[0]; if prefix < start { return None; } - let end = if range.len() == 1 { start } else { range[1] }; + let end = if range[1] == 0 { start } else { range[1] }; if prefix <= end { return Some(self.countryIdentifiers.get(i)?); } @@ -58,7 +58,7 @@ impl EANManufacturerOrgSupport { None } - fn add(&mut self, range: Vec, id: String) { + fn add(&mut self, range: [u32; 2], id: &'static str) { self.ranges.push(range); self.countryIdentifiers.push(id); } @@ -67,112 +67,112 @@ impl EANManufacturerOrgSupport { if !self.ranges.is_empty() { return; } - self.add(vec![0, 19], "US/CA".to_owned()); - self.add(vec![30, 39], "US".to_owned()); - self.add(vec![60, 139], "US/CA".to_owned()); - self.add(vec![300, 379], "FR".to_owned()); - self.add(vec![380], "BG".to_owned()); - self.add(vec![383], "SI".to_owned()); - self.add(vec![385], "HR".to_owned()); - self.add(vec![387], "BA".to_owned()); - self.add(vec![400, 440], "DE".to_owned()); - self.add(vec![450, 459], "JP".to_owned()); - self.add(vec![460, 469], "RU".to_owned()); - self.add(vec![471], "TW".to_owned()); - self.add(vec![474], "EE".to_owned()); - self.add(vec![475], "LV".to_owned()); - self.add(vec![476], "AZ".to_owned()); - self.add(vec![477], "LT".to_owned()); - self.add(vec![478], "UZ".to_owned()); - self.add(vec![479], "LK".to_owned()); - self.add(vec![480], "PH".to_owned()); - self.add(vec![481], "BY".to_owned()); - self.add(vec![482], "UA".to_owned()); - self.add(vec![484], "MD".to_owned()); - self.add(vec![485], "AM".to_owned()); - self.add(vec![486], "GE".to_owned()); - self.add(vec![487], "KZ".to_owned()); - self.add(vec![489], "HK".to_owned()); - self.add(vec![490, 499], "JP".to_owned()); - self.add(vec![500, 509], "GB".to_owned()); - self.add(vec![520], "GR".to_owned()); - self.add(vec![528], "LB".to_owned()); - self.add(vec![529], "CY".to_owned()); - self.add(vec![531], "MK".to_owned()); - self.add(vec![535], "MT".to_owned()); - self.add(vec![539], "IE".to_owned()); - self.add(vec![540, 549], "BE/LU".to_owned()); - self.add(vec![560], "PT".to_owned()); - self.add(vec![569], "IS".to_owned()); - self.add(vec![570, 579], "DK".to_owned()); - self.add(vec![590], "PL".to_owned()); - self.add(vec![594], "RO".to_owned()); - self.add(vec![599], "HU".to_owned()); - self.add(vec![600, 601], "ZA".to_owned()); - self.add(vec![603], "GH".to_owned()); - self.add(vec![608], "BH".to_owned()); - self.add(vec![609], "MU".to_owned()); - self.add(vec![611], "MA".to_owned()); - self.add(vec![613], "DZ".to_owned()); - self.add(vec![616], "KE".to_owned()); - self.add(vec![618], "CI".to_owned()); - self.add(vec![619], "TN".to_owned()); - self.add(vec![621], "SY".to_owned()); - self.add(vec![622], "EG".to_owned()); - self.add(vec![624], "LY".to_owned()); - self.add(vec![625], "JO".to_owned()); - self.add(vec![626], "IR".to_owned()); - self.add(vec![627], "KW".to_owned()); - self.add(vec![628], "SA".to_owned()); - self.add(vec![629], "AE".to_owned()); - self.add(vec![640, 649], "FI".to_owned()); - self.add(vec![690, 695], "CN".to_owned()); - self.add(vec![700, 709], "NO".to_owned()); - self.add(vec![729], "IL".to_owned()); - self.add(vec![730, 739], "SE".to_owned()); - self.add(vec![740], "GT".to_owned()); - self.add(vec![741], "SV".to_owned()); - self.add(vec![742], "HN".to_owned()); - self.add(vec![743], "NI".to_owned()); - self.add(vec![744], "CR".to_owned()); - self.add(vec![745], "PA".to_owned()); - self.add(vec![746], "DO".to_owned()); - self.add(vec![750], "MX".to_owned()); - self.add(vec![754, 755], "CA".to_owned()); - self.add(vec![759], "VE".to_owned()); - self.add(vec![760, 769], "CH".to_owned()); - self.add(vec![770], "CO".to_owned()); - self.add(vec![773], "UY".to_owned()); - self.add(vec![775], "PE".to_owned()); - self.add(vec![777], "BO".to_owned()); - self.add(vec![779], "AR".to_owned()); - self.add(vec![780], "CL".to_owned()); - self.add(vec![784], "PY".to_owned()); - self.add(vec![785], "PE".to_owned()); - self.add(vec![786], "EC".to_owned()); - self.add(vec![789, 790], "BR".to_owned()); - self.add(vec![800, 839], "IT".to_owned()); - self.add(vec![840, 849], "ES".to_owned()); - self.add(vec![850], "CU".to_owned()); - self.add(vec![858], "SK".to_owned()); - self.add(vec![859], "CZ".to_owned()); - self.add(vec![860], "YU".to_owned()); - self.add(vec![865], "MN".to_owned()); - self.add(vec![867], "KP".to_owned()); - self.add(vec![868, 869], "TR".to_owned()); - self.add(vec![870, 879], "NL".to_owned()); - self.add(vec![880], "KR".to_owned()); - self.add(vec![885], "TH".to_owned()); - self.add(vec![888], "SG".to_owned()); - self.add(vec![890], "IN".to_owned()); - self.add(vec![893], "VN".to_owned()); - self.add(vec![896], "PK".to_owned()); - self.add(vec![899], "ID".to_owned()); - self.add(vec![900, 919], "AT".to_owned()); - self.add(vec![930, 939], "AU".to_owned()); - self.add(vec![940, 949], "AZ".to_owned()); - self.add(vec![955], "MY".to_owned()); - self.add(vec![958], "MO".to_owned()); + self.add([0, 19], "US/CA"); + self.add([30, 39], "US"); + self.add([60, 139], "US/CA"); + self.add([300, 379], "FR"); + self.add([380, 0], "BG"); + self.add([383, 0], "SI"); + self.add([385, 0], "HR"); + self.add([387, 0], "BA"); + self.add([400, 440], "DE"); + self.add([450, 459], "JP"); + self.add([460, 469], "RU"); + self.add([471, 0], "TW"); + self.add([474, 0], "EE"); + self.add([475, 0], "LV"); + self.add([476, 0], "AZ"); + self.add([477, 0], "LT"); + self.add([478, 0], "UZ"); + self.add([479, 0], "LK"); + self.add([480, 0], "PH"); + self.add([481, 0], "BY"); + self.add([482, 0], "UA"); + self.add([484, 0], "MD"); + self.add([485, 0], "AM"); + self.add([486, 0], "GE"); + self.add([487, 0], "KZ"); + self.add([489, 0], "HK"); + self.add([490, 499], "JP"); + self.add([500, 509], "GB"); + self.add([520, 0], "GR"); + self.add([528, 0], "LB"); + self.add([529, 0], "CY"); + self.add([531, 0], "MK"); + self.add([535, 0], "MT"); + self.add([539, 0], "IE"); + self.add([540, 549], "BE/LU"); + self.add([560, 0], "PT"); + self.add([569, 0], "IS"); + self.add([570, 579], "DK"); + self.add([590, 0], "PL"); + self.add([594, 0], "RO"); + self.add([599, 0], "HU"); + self.add([600, 601], "ZA"); + self.add([603, 0], "GH"); + self.add([608, 0], "BH"); + self.add([609, 0], "MU"); + self.add([611, 0], "MA"); + self.add([613, 0], "DZ"); + self.add([616, 0], "KE"); + self.add([618, 0], "CI"); + self.add([619, 0], "TN"); + self.add([621, 0], "SY"); + self.add([622, 0], "EG"); + self.add([624, 0], "LY"); + self.add([625, 0], "JO"); + self.add([626, 0], "IR"); + self.add([627, 0], "KW"); + self.add([628, 0], "SA"); + self.add([629, 0], "AE"); + self.add([640, 649], "FI"); + self.add([690, 695], "CN"); + self.add([700, 709], "NO"); + self.add([729, 0], "IL"); + self.add([730, 739], "SE"); + self.add([740, 0], "GT"); + self.add([741, 0], "SV"); + self.add([742, 0], "HN"); + self.add([743, 0], "NI"); + self.add([744, 0], "CR"); + self.add([745, 0], "PA"); + self.add([746, 0], "DO"); + self.add([750, 0], "MX"); + self.add([754, 755], "CA"); + self.add([759, 0], "VE"); + self.add([760, 769], "CH"); + self.add([770, 0], "CO"); + self.add([773, 0], "UY"); + self.add([775, 0], "PE"); + self.add([777, 0], "BO"); + self.add([779, 0], "AR"); + self.add([780, 0], "CL"); + self.add([784, 0], "PY"); + self.add([785, 0], "PE"); + self.add([786, 0], "EC"); + self.add([789, 790], "BR"); + self.add([800, 839], "IT"); + self.add([840, 849], "ES"); + self.add([850, 0], "CU"); + self.add([858, 0], "SK"); + self.add([859, 0], "CZ"); + self.add([860, 0], "YU"); + self.add([865, 0], "MN"); + self.add([867, 0], "KP"); + self.add([868, 869], "TR"); + self.add([870, 879], "NL"); + self.add([880, 0], "KR"); + self.add([885, 0], "TH"); + self.add([888, 0], "SG"); + self.add([890, 0], "IN"); + self.add([893, 0], "VN"); + self.add([896, 0], "PK"); + self.add([899, 0], "ID"); + self.add([900, 919], "AT"); + self.add([930, 939], "AU"); + self.add([940, 949], "AZ"); + self.add([955, 0], "MY"); + self.add([958, 0], "MO"); } } diff --git a/src/oned/rss/abstract_rss_reader.rs b/src/oned/rss/abstract_rss_reader.rs index be51cc8..c255b35 100644 --- a/src/oned/rss/abstract_rss_reader.rs +++ b/src/oned/rss/abstract_rss_reader.rs @@ -85,19 +85,12 @@ pub trait AbstractRSSReaderTrait: OneDReader { let ratio: f32 = (firstTwoSum as f32) / (sum as f32); if ratio >= Self::MIN_FINDER_PATTERN_RATIO && ratio <= Self::MAX_FINDER_PATTERN_RATIO { // passes ratio test in spec, but see if the counts are unreasonable - // let minCounter = counters.iter().min(); - // let maxCounter = counters.iter().max(); let mut minCounter = u32::MAX; let mut maxCounter = u32::MIN; + for counter in counters { maxCounter = std::cmp::max(*counter, maxCounter); minCounter = std::cmp::min(*counter, minCounter); - // if *counter > maxCounter { - // maxCounter = *counter; - // } - // if *counter < minCounter { - // minCounter = *counter; - // } } return maxCounter < 10 * minCounter; } diff --git a/src/oned/rss/expanded/decoders/abstract_expanded_decoder.rs b/src/oned/rss/expanded/decoders/abstract_expanded_decoder.rs index 1ee6258..175c6d9 100644 --- a/src/oned/rss/expanded/decoders/abstract_expanded_decoder.rs +++ b/src/oned/rss/expanded/decoders/abstract_expanded_decoder.rs @@ -93,62 +93,14 @@ pub fn createDecoder<'a>( let sevenBitEncodationMethod = GeneralAppIdDecoder::extractNumericValueFromBitArrayWithInformation(information, 1, 7); match sevenBitEncodationMethod { - 56 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "310".to_owned(), - "11".to_owned(), - ))) - } - 57 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "320".to_owned(), - "11".to_owned(), - ))) - } - 58 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "310".to_owned(), - "13".to_owned(), - ))) - } - 59 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "320".to_owned(), - "13".to_owned(), - ))) - } - 60 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "310".to_owned(), - "15".to_owned(), - ))) - } - 61 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "320".to_owned(), - "15".to_owned(), - ))) - } - 62 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "310".to_owned(), - "17".to_owned(), - ))) - } - 63 => { - return Ok(Box::new(AI013x0x1xDecoder::new( - information, - "320".to_owned(), - "17".to_owned(), - ))) - } + 56 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "11"))), + 57 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "11"))), + 58 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "13"))), + 59 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "13"))), + 60 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "15"))), + 61 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "15"))), + 62 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "17"))), + 63 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "17"))), _ => {} } diff --git a/src/oned/rss/expanded/decoders/ai_013x0x1x_decoder.rs b/src/oned/rss/expanded/decoders/ai_013x0x1x_decoder.rs index 097f3e3..daac8c4 100644 --- a/src/oned/rss/expanded/decoders/ai_013x0x1x_decoder.rs +++ b/src/oned/rss/expanded/decoders/ai_013x0x1x_decoder.rs @@ -35,8 +35,8 @@ use super::{AI01decoder, AI01weightDecoder, AbstractExpandedDecoder, GeneralAppI pub struct AI013x0x1xDecoder<'a> { information: &'a BitArray, decoder: GeneralAppIdDecoder<'a>, - dateCode: String, - firstAIdigits: String, + dateCode: &'static str, + firstAIdigits: &'static str, } impl AI01weightDecoder for AI013x0x1xDecoder<'_> { @@ -88,8 +88,8 @@ impl<'a> AI013x0x1xDecoder<'_> { pub fn new( information: &'a BitArray, - firstAIdigits: String, - dateCode: String, + firstAIdigits: &'static str, + dateCode: &'static str, ) -> AI013x0x1xDecoder<'a> { AI013x0x1xDecoder { information, diff --git a/src/oned/rss/rss_14_reader.rs b/src/oned/rss/rss_14_reader.rs index 8bbe2ea..85e144c 100644 --- a/src/oned/rss/rss_14_reader.rs +++ b/src/oned/rss/rss_14_reader.rs @@ -57,7 +57,6 @@ impl OneDReader for RSS14Reader { row.reverse(); let rightPair = self.decodePair(&row, true, rowNumber, hints); Self::addOrTally(&mut self.possibleRightPairs, rightPair); - row.reverse(); for left in &self.possibleLeftPairs { if left.getCount() > 1 { for right in &self.possibleRightPairs { @@ -246,35 +245,33 @@ impl RSS14Reader { rowNumber: u32, hints: &DecodingHintDictionary, ) -> Option { - let pos_pair = || -> Result { - let startEnd = self.findFinderPattern(row, right)?; - let pattern = self.parseFoundFinderPattern(row, rowNumber, right, &startEnd)?; + let startEnd = self.findFinderPattern(row, right).ok()?; + let pattern = self + .parseFoundFinderPattern(row, rowNumber, right, &startEnd) + .ok()?; - if let Some(DecodeHintValue::NeedResultPointCallback(cb)) = - hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK) - { - let startEnd = pattern.getStartEnd(); - let mut center: f32 = (startEnd[0] + startEnd[1] - 1) as f32 / 2.0; - if right { - // row is actually reversed - center = row.get_size() as f32 - 1.0 - center; - } - cb(point_f(center, rowNumber as f32)); + if let Some(DecodeHintValue::NeedResultPointCallback(cb)) = + hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK) + { + let startEnd = pattern.getStartEnd(); + let mut center: f32 = (startEnd[0] + startEnd[1] - 1) as f32 / 2.0; + if right { + // row is actually reversed + center = row.get_size() as f32 - 1.0 - center; } + cb(point_f(center, rowNumber as f32)); + } - let outside = self.decodeDataCharacter(row, &pattern, true)?; - let inside = self.decodeDataCharacter(row, &pattern, false)?; + let outside = self.decodeDataCharacter(row, &pattern, true).ok()?; + let inside = self.decodeDataCharacter(row, &pattern, false).ok()?; - // todo!("must add callback"); + // todo!("must add callback"); - Ok(Pair::new( - 1597 * outside.getValue() + inside.getValue(), - outside.getChecksumPortion() + 4 * inside.getChecksumPortion(), - pattern, - )) - }(); - - pos_pair.ok() + Some(Pair::new( + 1597 * outside.getValue() + inside.getValue(), + outside.getChecksumPortion() + 4 * inside.getChecksumPortion(), + pattern, + )) } fn decodeDataCharacter( diff --git a/src/oned/telepen_writer.rs b/src/oned/telepen_writer.rs index a2e8872..424bfe6 100644 --- a/src/oned/telepen_writer.rs +++ b/src/oned/telepen_writer.rs @@ -66,7 +66,7 @@ impl OneDimensionalCodeWriter for TelepenWriter { for c in decodedContents.chars() { if c as u32 > 127 { return Err(Exceptions::illegal_argument_with( - "Telepen only supports ASCII characters.".to_string(), + "Telepen only supports ASCII characters.", )); } @@ -133,7 +133,7 @@ impl OneDimensionalCodeWriter for TelepenWriter { } "0" => { return Err(Exceptions::illegal_argument_with( - "Invalid bit combination!".to_string(), + "Invalid bit combination!", )); } _ => { diff --git a/src/oned/upc_ean_extension_5_support.rs b/src/oned/upc_ean_extension_5_support.rs index d345784..37eb369 100644 --- a/src/oned/upc_ean_extension_5_support.rs +++ b/src/oned/upc_ean_extension_5_support.rs @@ -188,7 +188,7 @@ impl UPCEANExtension5Support { "99991" => // Complementary { - return Some("0.00".to_string()) + return Some("0.00".to_owned()) } "99990" => return Some("Used".to_owned()), _ => {} diff --git a/src/planar_yuv_luminance_source.rs b/src/planar_yuv_luminance_source.rs index 7bdf857..6191d84 100644 --- a/src/planar_yuv_luminance_source.rs +++ b/src/planar_yuv_luminance_source.rs @@ -237,6 +237,9 @@ impl PlanarYUVLuminanceSource { } impl LuminanceSource for PlanarYUVLuminanceSource { + const SUPPORTS_CROP: bool = true; + const SUPPORTS_ROTATION: bool = false; + fn get_row(&self, y: usize) -> Vec { if y >= self.get_height() { // //throw new IllegalArgumentException("Requested row is outside the image: " + y); @@ -310,10 +313,6 @@ impl LuminanceSource for PlanarYUVLuminanceSource { self.height } - fn is_crop_supported(&self) -> bool { - true - } - fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result { PlanarYUVLuminanceSource::new_with_all( self.yuv_data.clone(), @@ -329,10 +328,6 @@ impl LuminanceSource for PlanarYUVLuminanceSource { .map_err(|_| Exceptions::UNSUPPORTED_OPERATION) } - fn is_rotate_supported(&self) -> bool { - false - } - fn invert(&mut self) { self.invert = !self.invert; } diff --git a/src/qrcode/decoder/error_correction_level.rs b/src/qrcode/decoder/error_correction_level.rs index 0dca92f..1f19de0 100644 --- a/src/qrcode/decoder/error_correction_level.rs +++ b/src/qrcode/decoder/error_correction_level.rs @@ -56,7 +56,7 @@ impl ErrorCorrectionLevel { } } - pub fn get_value(&self) -> u8 { + pub const fn get_value(&self) -> u8 { match self { ErrorCorrectionLevel::L => 0x01, ErrorCorrectionLevel::M => 0x00, @@ -66,7 +66,7 @@ impl ErrorCorrectionLevel { } } - pub fn get_ordinal(&self) -> u8 { + pub const fn get_ordinal(&self) -> u8 { match self { ErrorCorrectionLevel::L => 0, ErrorCorrectionLevel::M => 1, diff --git a/src/qrcode/decoder/version.rs b/src/qrcode/decoder/version.rs index 2ff447a..8856859 100755 --- a/src/qrcode/decoder/version.rs +++ b/src/qrcode/decoder/version.rs @@ -28,10 +28,10 @@ use once_cell::sync::Lazy; pub type VersionRef = &'static Version; -pub static VERSIONS: Lazy> = Lazy::new(Version::buildVersions); -pub static MICRO_VERSIONS: Lazy> = Lazy::new(Version::build_micro_versions); -pub static MODEL1_VERSIONS: Lazy> = Lazy::new(Version::build_model1_versions); -pub static RMQR_VERSIONS: Lazy> = Lazy::new(Version::build_rmqr_versions); +pub static VERSIONS: Lazy> = Lazy::new(Version::buildVersions); +pub static MICRO_VERSIONS: Lazy> = Lazy::new(Version::build_micro_versions); +pub static MODEL1_VERSIONS: Lazy> = Lazy::new(Version::build_model1_versions); +pub static RMQR_VERSIONS: Lazy> = Lazy::new(Version::build_rmqr_versions); /** * See ISO 18004:2006 Annex D. @@ -54,15 +54,15 @@ pub const VERSION_DECODE_INFO: [u32; 34] = [ pub struct Version { // private static final Version[] VERSIONS = buildVersions(); versionNumber: u32, - alignmentPatternCenters: Vec, - ecBlocks: Vec, + alignmentPatternCenters: Box<[u32]>, + ecBlocks: Box<[ECBlocks]>, totalCodewords: u32, pub(crate) qr_type: Type, } impl Version { pub(super) fn new( versionNumber: u32, - alignmentPatternCenters: Vec, + alignmentPatternCenters: Box<[u32]>, ecBlocks: [ECBlocks; 4], ) -> Self { let mut total = 0; @@ -78,17 +78,20 @@ impl Version { Self { versionNumber, alignmentPatternCenters, - ecBlocks: ecBlocks.to_vec(), - totalCodewords: total, qr_type: if ecBlocks[0].getECCodewordsPerBlock() != 0 { Type::Model2 } else { Type::RectMicro }, + ecBlocks: Box::new(ecBlocks), + totalCodewords: total, } } - pub(super) fn without_alignment_patterns(versionNumber: u32, ecBlocks: Vec) -> Self { + pub(super) fn without_alignment_patterns( + versionNumber: u32, + ecBlocks: Box<[ECBlocks]>, + ) -> Self { let mut total = 0; let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); let ecbArray = ecBlocks[0].getECBlocks(); @@ -107,7 +110,7 @@ impl Version { Self { versionNumber, - alignmentPatternCenters: Vec::default(), + alignmentPatternCenters: Box::default(), ecBlocks, totalCodewords: total, qr_type: symbol_type, @@ -118,11 +121,11 @@ impl Version { self.versionNumber } - pub fn getAlignmentPatternCenters(&self) -> &[u32] { + pub const fn getAlignmentPatternCenters(&self) -> &[u32] { &self.alignmentPatternCenters } - pub fn getTotalCodewords(&self) -> u32 { + pub const fn getTotalCodewords(&self) -> u32 { self.totalCodewords } @@ -131,7 +134,7 @@ impl Version { // 17 + 4 * self.versionNumber } - pub fn getECBlocksForLevel(&self, ecLevel: ErrorCorrectionLevel) -> &ECBlocks { + pub const fn getECBlocksForLevel(&self, ecLevel: ErrorCorrectionLevel) -> &ECBlocks { if ecLevel.get_ordinal() as usize >= self.ecBlocks.len() { return &self.ecBlocks[ecLevel.get_ordinal() as usize % self.ecBlocks.len()]; } @@ -293,11 +296,11 @@ impl fmt::Display for Version { #[derive(Debug, Clone)] pub struct ECBlocks { ecCodewordsPerBlock: u32, - ecBlocks: Vec, + ecBlocks: Box<[ECB]>, } impl ECBlocks { - pub const fn new(ecCodewordsPerBlock: u32, ecBlocks: Vec) -> Self { + pub const fn new(ecCodewordsPerBlock: u32, ecBlocks: Box<[ECB]>) -> Self { Self { ecCodewordsPerBlock, ecBlocks, @@ -310,7 +313,7 @@ impl ECBlocks { pub fn getNumBlocks(&self) -> u32 { let mut total = 0; - for ecBlock in &self.ecBlocks { + for ecBlock in self.ecBlocks.iter() { total += ecBlock.getCount(); } total diff --git a/src/qrcode/decoder/version_build_versions_arrays.rs b/src/qrcode/decoder/version_build_versions_arrays.rs index 3896001..23b1cea 100644 --- a/src/qrcode/decoder/version_build_versions_arrays.rs +++ b/src/qrcode/decoder/version_build_versions_arrays.rs @@ -13,18 +13,18 @@ macro_rules! qr_version { ),+ } ) => { - vec![ + Box::new([ $( Version::without_alignment_patterns( $version, - vec![ + Box::new([ $( - ECBlocks::new($ec_codewords_per_block, vec![ECB::new($count_1,$data_codewords_1),ECB::new($count_2,$data_codewords_2)]) + ECBlocks::new($ec_codewords_per_block, Box::new([ECB::new($count_1,$data_codewords_1),ECB::new($count_2,$data_codewords_2)])) ),* - ] + ]) ) ),* - ] + ]) }; // Model 2 & rMQR ( @@ -38,27 +38,27 @@ macro_rules! qr_version { ),+ } ) => { - vec![ + Box::new([ $( Version::new($version, - vec![ + Box::new([ $( $alignment_pattern ),* - ], + ]), [ $( - ECBlocks::new($ec_codewords_per_block, vec![ECB::new($count_1,$data_codewords_1),ECB::new($count_2,$data_codewords_2)]) + ECBlocks::new($ec_codewords_per_block, Box::new([ECB::new($count_1,$data_codewords_1),ECB::new($count_2,$data_codewords_2)])) ),* ] ) ),* - ] + ]) }; } impl Version { - pub fn build_micro_versions() -> Vec { + pub fn build_micro_versions() -> Box<[Version]> { qr_version!( { {1, {2, 1, 3, 0, 0}}, @@ -71,7 +71,7 @@ impl Version { /** * See ISO 18004:2006 6.5.1 Table 9 */ - pub fn buildVersions() -> Vec { + pub fn buildVersions() -> Box<[Version]> { qr_version!({ {1, {}, { 7, 1, 19, 0, 0, @@ -316,7 +316,7 @@ impl Version { }) } - pub fn build_model1_versions() -> Vec { + pub fn build_model1_versions() -> Box<[Version]> { qr_version!( { {1, { @@ -407,7 +407,7 @@ impl Version { ) } - pub fn build_rmqr_versions() -> Vec { + pub fn build_rmqr_versions() -> Box<[Version]> { qr_version!( { // Version number, alignment pattern centres, `ECBlocks` diff --git a/src/qrcode/encoder/bit_vector_testcase.rs b/src/qrcode/encoder/bit_vector_testcase.rs index 4270399..fd89213 100644 --- a/src/qrcode/encoder/bit_vector_testcase.rs +++ b/src/qrcode/encoder/bit_vector_testcase.rs @@ -127,7 +127,7 @@ fn testXOR() { let mut v1 = BitArray::new(); v1.appendBits(0x5555aaaa, 32).expect("append"); let mut v2 = BitArray::new(); - v2.appendBits(0xaaaa5555, 32).expect("append"); + v2.appendBits(0xaaaa5555_u32, 32).expect("append"); v1.xor(&v2).expect("xor"); assert_eq!(0xffffffff, getUnsignedInt(&v1)); } diff --git a/src/rgb_luminance_source.rs b/src/rgb_luminance_source.rs index aa95341..7ee00b2 100644 --- a/src/rgb_luminance_source.rs +++ b/src/rgb_luminance_source.rs @@ -39,6 +39,8 @@ pub struct RGBLuminanceSource { } impl LuminanceSource for RGBLuminanceSource { + const SUPPORTS_CROP: bool = true; + /// gets a row, returns an empty row if we are out of bounds. fn get_row(&self, y: usize) -> Vec { if y >= self.get_height() { @@ -111,10 +113,6 @@ impl LuminanceSource for RGBLuminanceSource { self.height } - fn is_crop_supported(&self) -> bool { - true - } - fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result { RGBLuminanceSource::new_complex( &self.luminances, diff --git a/tests/dx_film_edge.rs b/tests/dx_film_edge.rs index 655a5d9..ded2fdd 100644 --- a/tests/dx_film_edge.rs +++ b/tests/dx_film_edge.rs @@ -1,6 +1,6 @@ // dxfilmedge-1 -#![cfg(feature = "image")] +#![cfg(feature = "image, experimental_features")] use rxing::{BarcodeFormat, FilteredImageReader, MultiFormatReader};