stage: moving performance enhancements into main

several incomplete features are gated behind the `experimental_features` flag.
This commit is contained in:
Henry Schimke
2024-02-07 13:22:07 -06:00
parent c554a469cd
commit 76e8998f4b
33 changed files with 684 additions and 548 deletions

View File

@@ -12,3 +12,6 @@ keywords = ["barcode", "2d_barcode", "1d_barcode", "barcode_reader", "barcode_wr
[dependencies] [dependencies]
clap = { version = "4.4.13", features = ["derive"] } clap = { version = "4.4.13", features = ["derive"] }
rxing = {path = "../../", version = "~0.5.7", features = ["image", "svg_read", "svg_write"] } rxing = {path = "../../", version = "~0.5.7", features = ["image", "svg_read", "svg_write"] }
#[profile.release]
#debug = true

View File

@@ -66,6 +66,9 @@ impl BufferedImageLuminanceSource {
} }
impl LuminanceSource for BufferedImageLuminanceSource { impl LuminanceSource for BufferedImageLuminanceSource {
const SUPPORTS_CROP: bool = true;
const SUPPORTS_ROTATION: bool = true;
fn get_row(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
let width = self.get_width(); // - self.left as usize; let width = self.get_width(); // - self.left as usize;
@@ -87,8 +90,6 @@ impl LuminanceSource for BufferedImageLuminanceSource {
} }
fn get_column(&self, x: usize) -> Vec<u8> { fn get_column(&self, x: usize) -> Vec<u8> {
let width = self.get_height(); // - self.left as usize;
let pixels: Vec<u8> = || -> Option<Vec<u8>> { let pixels: Vec<u8> = || -> Option<Vec<u8>> {
Some( Some(
self.image self.image
@@ -153,10 +154,6 @@ impl LuminanceSource for BufferedImageLuminanceSource {
self.height self.height
} }
fn is_crop_supported(&self) -> bool {
true
}
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> { fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
Ok(Self { Ok(Self {
image: self.image.clone(), image: self.image.clone(),
@@ -167,10 +164,6 @@ impl LuminanceSource for BufferedImageLuminanceSource {
}) })
} }
fn is_rotate_supported(&self) -> bool {
true
}
fn invert(&mut self) { fn invert(&mut self) {
let mut img = (*self.image).clone(); let mut img = (*self.image).clone();
img.invert(); img.invert();

View File

@@ -136,7 +136,7 @@ fn test_get_next_set5() {
#[test] #[test]
fn test_set_bulk() { fn test_set_bulk() {
let mut array = BitArray::with_size(64); let mut array = BitArray::with_size(64);
array.setBulk(32, 0xFFFF0000); array.setBulk(32, 0b11111111111111110000000000000000);
for i in 0..48 { for i in 0..48 {
// for (int i = 0; i < 48; i++) { // for (int i = 0; i < 48; i++) {
assert!(!array.get(i)); assert!(!array.get(i));
@@ -150,7 +150,7 @@ fn test_set_bulk() {
#[test] #[test]
fn test_append_bit() { fn test_append_bit() {
let mut array = BitArray::new(); 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(); let mut array_2 = BitArray::new();
array_2.appendBit(false); array_2.appendBit(false);
array_2.appendBit(true); array_2.appendBit(true);
@@ -159,7 +159,9 @@ fn test_append_bit() {
array_2.appendBit(true); array_2.appendBit(true);
array_2.appendBit(false); 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] #[test]
@@ -234,18 +236,37 @@ fn test_is_range() {
#[test] #[test]
fn reverse_algorithm_test() { fn reverse_algorithm_test() {
let oldBits: Vec<u32> = vec![128, 256, 512, 6453324, 50934953]; let oldBits: Vec<super::BitFieldBaseType> = vec![128, 256, 512, 6453324, 50934953];
for size in 1..160 { for size in 1..160 {
// for (int size = 1; size < 160; size++) { // for (int size = 1; size < 160; size++) {
let newBitsOriginal = reverse_original(&oldBits.clone(), size); let newBitsOriginal = reverse_original(&oldBits.clone(), size);
let mut newBitArray = BitArray::with_initial_values(oldBits.clone(), size); let mut newBitArray = BitArray::with_initial_values(oldBits.clone(), size);
newBitArray.reverse(); newBitArray.reverse();
let newBitsNew = newBitArray.getBitArray(); let newBitsNew = newBitArray.getBitArray();
assert!(arrays_are_equal( assert!(
&newBitsOriginal, arrays_are_equal(&newBitsOriginal, newBitsNew, size / 32 + 1),
newBitsNew, "size: ({}) : {:?}/{:?}",
size / 32 + 1 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()); // assert_eq!(a.hash(), b.hash());
} }
fn reverse_original(oldBits: &[u32], size: usize) -> Vec<u32> { #[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<super::BitFieldBaseType> {
let mut newBits = vec![0; oldBits.len()]; let mut newBits = vec![0; oldBits.len()];
for i in 0..size { for i in 0..size {
// for (int i = 0; i < size; i++) { // for (int i = 0; i < size; i++) {
@@ -282,13 +344,12 @@ fn reverse_original(oldBits: &[u32], size: usize) -> Vec<u32> {
newBits 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 (bits[i / 32] & (1 << (i & 0x1F))) != 0
} }
fn arrays_are_equal(left: &[u32], right: &[u32], size: usize) -> bool { fn arrays_are_equal<T: Eq + Default>(left: &[T], right: &[T], size: usize) -> bool {
for i in 0..size { for i in 0..size {
// for (int i = 0; i < size; i++) {
if left[i] != right[i] { if left[i] != right[i] {
return false; return false;
} }

View File

@@ -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<LS: LuminanceSource> {
source: LS,
matrix: OnceCell<BitMatrix>,
radius: u32,
}
impl<LS: LuminanceSource> AdaptiveThresholdBinarizer<LS> {
pub fn new(source: LS, radius: u32) -> Self {
Self {
source,
radius,
matrix: OnceCell::new(),
}
}
}
impl<LS: LuminanceSource> AdaptiveThresholdBinarizer<LS> {
fn buildMatrix(&self) -> Result<BitMatrix> {
let image_buffer = {
let Some(buff): Option<ImageBuffer<Luma<u8>, Vec<u8>>> = 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<LS: LuminanceSource> Binarizer for AdaptiveThresholdBinarizer<LS> {
type Source = LS;
fn get_luminance_source(&self) -> &Self::Source {
&self.source
}
fn get_black_row(&self, y: usize) -> Result<Cow<BitArray>> {
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<Cow<BitArray>> {
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()
}
}

View File

@@ -18,13 +18,15 @@
// import java.util.Arrays; // import java.util.Arrays;
use std::ops::Index;
use std::{cmp, fmt}; use std::{cmp, fmt};
use crate::common::Result; use crate::common::Result;
use crate::Exceptions; 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;
/** /**
* <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p> * <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>
@@ -33,7 +35,7 @@ static LOAD_FACTOR: f32 = 0.75;
*/ */
#[derive(Debug, PartialEq, Eq, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct BitArray { pub struct BitArray {
bits: Vec<u32>, bits: Vec<BaseType>,
size: usize, size: usize,
} }
@@ -47,14 +49,14 @@ impl BitArray {
pub fn with_size(size: usize) -> Self { pub fn with_size(size: usize) -> Self {
Self { Self {
bits: BitArray::makeArray(size), bits: makeArray(size),
size, size,
} }
} }
/// For testing only /// For testing only
#[cfg(test)] #[cfg(test)]
pub fn with_initial_values(bits: Vec<u32>, size: usize) -> Self { pub fn with_initial_values(bits: Vec<BaseType>, size: usize) -> Self {
Self { bits, size } Self { bits, size }
} }
@@ -66,12 +68,14 @@ impl BitArray {
(self.size + 7) / 8 (self.size + 7) / 8
} }
#[inline]
fn ensure_capacity(&mut self, newSize: usize) { fn ensure_capacity(&mut self, newSize: usize) {
if newSize > self.bits.len() * 32 { let target_size = (newSize as f32 / LOAD_FACTOR).ceil() as usize;
let mut newBits = BitArray::makeArray((newSize as f32 / LOAD_FACTOR).ceil() as usize); let array_desired_length = (target_size + BASE_BITS - 1) / BASE_BITS;
//System.arraycopy(bits, 0, newBits, 0, bits.length);
newBits[0..self.bits.len()].clone_from_slice(&self.bits[0..self.bits.len()]); if self.bits.len() < array_desired_length {
self.bits = newBits; 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 * @return true iff bit i is set
*/ */
pub fn get(&self, i: usize) -> bool { 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<bool> { pub fn try_get(&self, i: usize) -> Option<bool> {
if (i / 32) >= self.bits.len() { if (i / BASE_BITS) >= self.bits.len() {
None None
} else { } else {
Some(self.get(i)) Some(self.get(i))
@@ -97,7 +101,7 @@ impl BitArray {
* @param i bit to set * @param i bit to set
*/ */
pub fn set(&mut self, i: usize) { 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 * @param i bit to set
*/ */
pub fn flip(&mut self, i: usize) { 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 { if from >= self.size {
return self.size; return self.size;
} }
let mut bitsOffset = from / 32; let mut bitsOffset = from / BASE_BITS;
let mut currentBits = self.bits[bitsOffset] as i64; let mut currentBits = self.bits[bitsOffset] as i64;
// mask off lesser bits first // mask off lesser bits first
currentBits &= -(1 << (from & 0x1F)); currentBits &= -(1 << (from & 0x1F));
@@ -130,7 +134,7 @@ impl BitArray {
} }
currentBits = self.bits[bitsOffset] as i64; 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) cmp::min(result, self.size)
} }
@@ -143,7 +147,7 @@ impl BitArray {
if from >= self.size { if from >= self.size {
return self.size; return self.size;
} }
let mut bitsOffset = from / 32; let mut bitsOffset = from / BASE_BITS;
let mut currentBits = !self.bits[bitsOffset] as i64; let mut currentBits = !self.bits[bitsOffset] as i64;
// mask off lesser bits first // mask off lesser bits first
currentBits &= -(1 << (from & 0x1F)); currentBits &= -(1 << (from & 0x1F));
@@ -154,7 +158,7 @@ impl BitArray {
} }
currentBits = !self.bits[bitsOffset] as i64; 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) 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 * @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. * corresponds to bit i, the next-least-significant to i+1, and so on.
*/ */
pub fn setBulk(&mut self, i: usize, newBits: u32) { pub fn setBulk(&mut self, i: usize, newBits: BaseType) {
self.bits[i / 32] = newBits; self.bits[i / BASE_BITS] = newBits;
} }
/** /**
@@ -184,15 +188,15 @@ impl BitArray {
return Ok(()); return Ok(());
} }
end -= 1; // will be easier to treat this as the last actually set bit -- inclusive end -= 1; // will be easier to treat this as the last actually set bit -- inclusive
let firstInt = start / 32; let firstInt = start / BASE_BITS;
let lastInt = end / 32; let lastInt = end / BASE_BITS;
for i in firstInt..=lastInt { for i in firstInt..=lastInt {
//for (int i = firstInt; i <= lastInt; i++) { //for (int i = firstInt; i <= lastInt; i++) {
let firstBit = if i > firstInt { 0 } else { start & 0x1F }; let firstBit = if i > firstInt { 0 } else { start & 0x1F };
let lastBit = if i < lastInt { 31 } else { end & 0x1F }; let lastBit = if i < lastInt { 31 } else { end & 0x1F };
// Ones from firstBit to lastBit, inclusive // Ones from firstBit to lastBit, inclusive
let mask: u64 = (2 << lastBit) - (1 << firstBit); let mask: u64 = (2 << lastBit) - (1 << firstBit);
self.bits[i] |= mask as u32; self.bits[i] |= mask as BaseType;
} }
Ok(()) Ok(())
} }
@@ -201,11 +205,6 @@ impl BitArray {
* Clears all bits (sets to false). * Clears all bits (sets to false).
*/ */
pub fn clear(&mut self) { 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); self.bits.fill(0);
} }
@@ -227,8 +226,8 @@ impl BitArray {
return Ok(true); // empty range matches return Ok(true); // empty range matches
} }
end -= 1; // will be easier to treat this as the last actually set bit -- inclusive end -= 1; // will be easier to treat this as the last actually set bit -- inclusive
let firstInt = start / 32; let firstInt = start / BASE_BITS;
let lastInt = end / 32; let lastInt = end / BASE_BITS;
for i in firstInt..=lastInt { for i in firstInt..=lastInt {
//for (int i = firstInt; i <= lastInt; i++) { //for (int i = firstInt; i <= lastInt; i++) {
let firstBit = if i > firstInt { 0 } else { start & 0x1F }; 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, // 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 // 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); return Ok(false);
} }
} }
@@ -248,7 +247,7 @@ impl BitArray {
pub fn appendBit(&mut self, bit: bool) { pub fn appendBit(&mut self, bit: bool) {
self.ensure_capacity(self.size + 1); self.ensure_capacity(self.size + 1);
if bit { if bit {
self.bits[self.size / 32] |= 1 << (self.size & 0x1F); self.bits[self.size / BASE_BITS] |= 1 << (self.size & 0x1F);
} }
self.size += 1; self.size += 1;
} }
@@ -261,11 +260,12 @@ impl BitArray {
* @param value {@code int} containing bits to append * @param value {@code int} containing bits to append
* @param numBits bits from value to append * @param numBits bits from value to append
*/ */
pub fn appendBits(&mut self, value: u32, num_bits: usize) -> Result<()> { pub fn appendBits(&mut self, value: BaseType, num_bits: usize) -> Result<()> {
if num_bits > 32 { if num_bits > BASE_BITS {
return Err(Exceptions::illegal_argument_with( return Err(Exceptions::illegal_argument_with(format!(
"num bits must be between 0 and 32", "num bits must be between 0 and {}",
)); BaseType::BITS
)));
} }
if num_bits == 0 { if num_bits == 0 {
@@ -277,7 +277,7 @@ impl BitArray {
for numBitsLeft in (0..num_bits).rev() { for numBitsLeft in (0..num_bits).rev() {
//for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) { //for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) {
if (value & (1 << numBitsLeft)) != 0 { if (value & (1 << numBitsLeft)) != 0 {
self.bits[next_size / 32] |= 1 << (next_size & 0x1F); self.bits[next_size / BASE_BITS] |= 1 << (next_size & 0x1F);
} }
next_size += 1; next_size += 1;
} }
@@ -298,11 +298,11 @@ impl BitArray {
if self.size != other.size { if self.size != other.size {
return Err(Exceptions::illegal_argument_with("Sizes don't match")); 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++) { //for (int i = 0; i < bits.length; i++) {
// The last int could be incomplete (i.e. not have 32 bits in // The last int could be incomplete (i.e. not have 32 bits in
// it) but there is no problem since 0 XOR 0 == 0. // it) but there is no problem since 0 XOR 0 == 0.
self.bits[i] ^= other.bits[i]; *lhs ^= rhs;
} }
Ok(()) Ok(())
} }
@@ -335,7 +335,7 @@ impl BitArray {
* @return underlying array of ints. The first element holds the first 32 bits, and the least * @return underlying array of ints. The first element holds the first 32 bits, and the least
* significant bit is bit 0. * significant bit is bit 0.
*/ */
pub fn getBitArray(&self) -> &[u32] { pub fn getBitArray(&self) -> &[BaseType] {
&self.bits &self.bits
} }
@@ -343,52 +343,35 @@ impl BitArray {
* Reverses all bits in the array. * Reverses all bits in the array.
*/ */
pub fn reverse(&mut self) { 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 // reverse all int's first
let len = (self.size - 1) / 32; let len = (self.size - 1) / 32;
let oldBitsLen = len + 1; let oldBitsLen = len + 1;
for i in 0..oldBitsLen { // let array_size = self.size.div_ceil(BASE_TYPE::BITS as usize);
//for (int i = 0; i < oldBitsLen; i++) {
newBits[len - i] = self.bits[i].reverse_bits(); // 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 // now correct the int's if the bit size isn't a multiple of 32
if self.size != oldBitsLen * 32 { if self.size != oldBitsLen * BASE_BITS {
let leftOffset = oldBitsLen * 32 - self.size; let leftOffset = oldBitsLen * BASE_BITS - self.size;
let mut currentInt = newBits[0] >> leftOffset; let mut currentInt = self.bits[0] >> leftOffset;
for i in 1..oldBitsLen { for i in 1..oldBitsLen {
//for (int i = 1; i < oldBitsLen; i++) { //for (int i = 1; i < oldBitsLen; i++) {
let nextInt = newBits[i]; let nextInt = self.bits[i];
currentInt |= nextInt << (32 - leftOffset); currentInt |= nextInt << (BASE_BITS - leftOffset);
newBits[i - 1] = currentInt; self.bits[i - 1] = currentInt;
currentInt = nextInt >> leftOffset; currentInt = nextInt >> leftOffset;
} }
newBits[oldBitsLen - 1] = currentInt; self.bits[oldBitsLen - 1] = currentInt;
} }
self.bits = newBits;
} }
fn makeArray(size: usize) -> Vec<u32> {
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 { impl fmt::Display for BitArray {
@@ -427,13 +410,6 @@ impl From<&BitArray> for Vec<u8> {
impl From<BitArray> for Vec<bool> { impl From<BitArray> for Vec<bool> {
fn from(value: BitArray) -> Self { 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) Self::from(&value)
} }
} }
@@ -449,3 +425,7 @@ impl From<&BitArray> for Vec<bool> {
array array
} }
} }
fn makeArray(size: usize) -> Vec<BaseType> {
vec![0; (size + BASE_BITS - 1) / BASE_BITS]
}

View File

@@ -25,6 +25,9 @@ use crate::{point_f, point_i, Exceptions, Point};
use super::BitArray; use super::BitArray;
type BaseType = super::BitFieldBaseType;
const BASE_BITS: usize = super::BIT_FIELD_BASE_BITS;
/** /**
* <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common * <p>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. * 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, width: u32,
height: u32, height: u32,
row_size: usize, row_size: usize,
bits: Vec<u32>, bits: Vec<BaseType>,
} }
impl BitMatrix { impl BitMatrix {
@@ -73,8 +76,11 @@ impl BitMatrix {
Ok(Self { Ok(Self {
width, width,
height, height,
row_size: ((width + 31) / 32) as usize, row_size: ((width as usize + BASE_BITS - 1) / BASE_BITS) as usize,
bits: vec![0; (((width + 31) / 32) * height) as usize], bits: vec![
0;
(((width as usize + BASE_BITS - 1) / BASE_BITS) * height as usize) as usize
],
}) })
// this.width = width; // this.width = width;
// this.height = height; // this.height = height;
@@ -83,7 +89,7 @@ impl BitMatrix {
} }
#[allow(dead_code)] #[allow(dead_code)]
fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec<u32>) -> Self { fn with_all_data(&self, width: u32, height: u32, rowSize: usize, bits: Vec<BaseType>) -> Self {
Self { Self {
width, width,
height, height,
@@ -235,7 +241,7 @@ impl BitMatrix {
#[inline(always)] #[inline(always)]
fn get_offset(&self, y: u32, x: u32) -> usize { 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<bool> { pub fn try_get(&self, x: u32, y: u32) -> Option<bool> {
@@ -387,7 +393,7 @@ impl BitMatrix {
let offset = y as usize * self.row_size; let offset = y as usize * self.row_size;
for x in left..right { for x in left..right {
//for (int x = left; x < right; x++) { //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(()) Ok(())
@@ -407,7 +413,7 @@ impl BitMatrix {
let offset = y as usize * self.row_size; let offset = y as usize * self.row_size;
for x in 0..self.row_size { for x in 0..self.row_size {
//for (int x = 0; x < rowSize; x++) { //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 rw
} }
@@ -489,7 +495,7 @@ impl BitMatrix {
pub fn rotate90(&mut self) { pub fn rotate90(&mut self) {
let newWidth = self.height; let newWidth = self.height;
let newHeight = self.width; 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]; let mut newBits = vec![0; (newRowSize * newHeight) as usize];
for y in 0..self.height { for y in 0..self.height {
@@ -498,7 +504,8 @@ impl BitMatrix {
//for (int x = 0; x < width; x++) { //for (int x = 0; x < width; x++) {
let offset = self.get_offset(y, x); let offset = self.get_offset(y, x);
if ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 { 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); newBits[newOffset] |= 1 << (y & 0x1f);
} }
} }
@@ -531,22 +538,22 @@ impl BitMatrix {
top = top.min(y); top = top.min(y);
bottom = bottom.max(y); bottom = bottom.max(y);
if x32 * 32 < left as usize { if x32 * BASE_BITS < left as usize {
let mut bit = 0; let mut bit = 0;
while (theBits << (31 - bit)) == 0 { while (theBits << (BASE_BITS - 1 - bit)) == 0 {
bit += 1; bit += 1;
} }
if (x32 * 32 + bit) < left as usize { if (x32 * BASE_BITS + bit) < left as usize {
left = (x32 * 32 + bit) as u32; left = (x32 * BASE_BITS + bit) as u32;
} }
} }
if x32 * 32 + 31 > right as usize { if x32 * BASE_BITS + BASE_BITS - 1 > right as usize {
let mut bit = 31; let mut bit = BASE_BITS - 1;
while (theBits >> bit) == 0 { while (theBits >> bit) == 0 {
bit -= 1; bit -= 1;
} }
if (x32 * 32 + bit) > right as usize { if (x32 * BASE_BITS + bit) > right as usize {
right = (x32 * 32 + bit) as u32; right = (x32 * BASE_BITS + bit) as u32;
} }
} }
} }
@@ -574,7 +581,7 @@ impl BitMatrix {
return None; return None;
} }
let y = bitsOffset / self.row_size; 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 theBits = self.bits[bitsOffset];
let mut bit = 0; let mut bit = 0;
@@ -595,10 +602,10 @@ impl BitMatrix {
} }
let y = bitsOffset as usize / self.row_size; 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 theBits = self.bits[bitsOffset as usize];
let mut bit = 31; let mut bit = BASE_BITS - 1;
while (theBits >> bit) == 0 { while (theBits >> bit) == 0 {
bit -= 1; bit -= 1;
} }

View File

@@ -31,7 +31,7 @@ use crate::point_f;
use super::BitMatrix; 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] #[test]
fn test_get_set() { fn test_get_set() {

View File

@@ -17,6 +17,7 @@
//package com.google.zxing.common; //package com.google.zxing.common;
use std::cmp; use std::cmp;
use std::io::{ErrorKind, Read};
use crate::common::Result; use crate::common::Result;
use crate::Exceptions; use crate::Exceptions;
@@ -173,3 +174,28 @@ impl BitSource {
8 * (self.bytes.len() - self.byte_offset) - self.bit_offset 8 * (self.bytes.len() - self.byte_offset) - self.bit_offset
} }
} }
impl Read for BitSource {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
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)
}
}

View File

@@ -18,6 +18,8 @@
// import java.io.ByteArrayOutputStream; // import java.io.ByteArrayOutputStream;
use std::io::Write;
/** /**
* Class that lets one easily build an array of bytes by appending bits at a time. * 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() Self::new()
} }
} }
impl Write for BitSourceBuilder {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
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(())
}
}

View File

@@ -349,3 +349,18 @@ impl Default for SymbologyIdentifier {
} }
} }
} }
impl std::io::Write for ECIStringBuilder {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
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(())
}
}

View File

@@ -175,12 +175,12 @@ impl<LS: LuminanceSource> HybridBinarizer<LS> {
// for (int y = 0; y < subHeight; y++) { // for (int y = 0; y < subHeight; y++) {
let yoffset = u32::min(y << BLOCK_SIZE_POWER, maxYOffset); 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 x in 0..sub_width {
// for (int x = 0; x < subWidth; x++) { // for (int x = 0; x < subWidth; x++) {
let xoffset = u32::min(x << BLOCK_SIZE_POWER, maxXOffset); 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; let mut sum = 0;
for z in -2..=2 { for z in -2..=2 {
// for (int z = -2; z <= 2; z++) { // for (int z = -2; z <= 2; z++) {
@@ -197,11 +197,6 @@ impl<LS: LuminanceSource> HybridBinarizer<LS> {
} }
} }
#[inline(always)]
fn cap(value: u32, max: u32) -> u32 {
u32::clamp(value, 2, max)
}
/** /**
* Applies a single threshold to a block of pixels. * Applies a single threshold to a block of pixels.
*/ */

View File

@@ -121,3 +121,11 @@ pub use line_orientation::LineOrientation;
mod otsu_level_binarizer; mod otsu_level_binarizer;
#[cfg(feature = "otsu_level")] #[cfg(feature = "otsu_level")]
pub use otsu_level_binarizer::*; 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;

View File

@@ -20,7 +20,7 @@ use once_cell::sync::Lazy;
use crate::common::Result; use crate::common::Result;
use crate::Exceptions; use crate::Exceptions;
static VERSIONS: Lazy<Vec<Version>> = Lazy::new(Version::buildVersions); static VERSIONS: Lazy<Box<[Version]>> = Lazy::new(Version::buildVersions);
pub type VersionRef = &'static Version; pub type VersionRef = &'static Version;
@@ -118,8 +118,8 @@ impl Version {
/** /**
* See ISO 16022:2006 5.5.1 Table 7 * See ISO 16022:2006 5.5.1 Table 7
*/ */
fn buildVersions() -> Vec<Version> { fn buildVersions() -> Box<[Version]> {
vec![ Box::new([
Version::new(1, 10, 10, 8, 8, ECBlocks::new(5, ECB::new(1, 3))), 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(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))), 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(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(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))), 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 { pub struct ECBlocks {
ecCodewords: u32, ecCodewords: u32,
ecBlocks: Vec<ECB>, ecBlocks: Box<[ECB]>,
} }
impl ECBlocks { impl ECBlocks {
pub fn new(ecCodewords: u32, ecBlocks: ECB) -> Self { pub fn new(ecCodewords: u32, ecBlocks: ECB) -> Self {
Self { Self {
ecCodewords, ecCodewords,
ecBlocks: vec![ecBlocks], ecBlocks: Box::new([ecBlocks]),
} }
} }
pub fn new2(ecCodewords: u32, ecBlocks1: ECB, ecBlocks2: ECB) -> Self { pub fn new2(ecCodewords: u32, ecBlocks1: ECB, ecBlocks2: ECB) -> Self {
Self { Self {
ecCodewords, ecCodewords,
ecBlocks: vec![ecBlocks1, ecBlocks2], ecBlocks: Box::new([ecBlocks1, ecBlocks2]),
} }
} }
@@ -231,18 +231,18 @@ pub struct ECB {
dataCodewords: u32, dataCodewords: u32,
} }
impl ECB { impl ECB {
pub fn new(count: u32, dataCodewords: u32) -> Self { pub const fn new(count: u32, dataCodewords: u32) -> Self {
Self { Self {
count, count,
dataCodewords, dataCodewords,
} }
} }
pub fn getCount(&self) -> u32 { pub const fn getCount(&self) -> u32 {
self.count self.count
} }
pub fn getDataCodewords(&self) -> u32 { pub const fn getDataCodewords(&self) -> u32 {
self.dataCodewords self.dataCodewords
} }
} }

View File

@@ -104,7 +104,9 @@ pub mod helpers;
mod luma_luma_source; mod luma_luma_source;
pub use luma_luma_source::*; pub use luma_luma_source::*;
#[cfg(feature = "experimental_features")]
mod filtered_image_reader; mod filtered_image_reader;
#[cfg(feature = "experimental_features")]
pub use filtered_image_reader::*; pub use filtered_image_reader::*;
#[cfg(feature = "svg_read")] #[cfg(feature = "svg_read")]

View File

@@ -9,13 +9,16 @@ pub struct Luma8LuminanceSource {
/// image origin in the form (x,y) /// image origin in the form (x,y)
origin: (u32, u32), origin: (u32, u32),
/// raw data for luma 8 /// raw data for luma 8
data: Vec<u8>, data: Box<[u8]>,
/// flag indicating if the underlying data needs to be inverted for use /// flag indicating if the underlying data needs to be inverted for use
inverted: bool, inverted: bool,
/// original dimensions of the data, used to manage crop /// original dimensions of the data, used to manage crop
original_dimension: (u32, u32), original_dimension: (u32, u32),
} }
impl LuminanceSource for Luma8LuminanceSource { impl LuminanceSource for Luma8LuminanceSource {
const SUPPORTS_CROP: bool = true;
const SUPPORTS_ROTATION: bool = true;
fn get_row(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
let chunk_size = self.original_dimension.0 as usize; let chunk_size = self.original_dimension.0 as usize;
let row_skip = y + self.origin.1 as usize; let row_skip = y + self.origin.1 as usize;
@@ -30,16 +33,6 @@ impl LuminanceSource for Luma8LuminanceSource {
} else { } else {
Vec::from(&self.data[data_start..data_end]) 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<u8> { fn get_column(&self, x: usize) -> Vec<u8> {
@@ -85,10 +78,6 @@ impl LuminanceSource for Luma8LuminanceSource {
self.inverted = !self.inverted; self.inverted = !self.inverted;
} }
fn is_crop_supported(&self) -> bool {
true
}
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> { fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
Ok(Self { Ok(Self {
dimensions: (width as u32, height as u32), 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<Self> { fn rotate_counter_clockwise(&self) -> Result<Self> {
let mut new_matrix = Self { let mut new_matrix = Self {
dimensions: self.dimensions, dimensions: self.dimensions,
@@ -123,7 +108,14 @@ impl LuminanceSource for Luma8LuminanceSource {
} }
fn get_luma8_point(&self, column: usize, row: usize) -> u8 { 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]; new_data[offset_b] = self.data[offset_a];
} }
} }
self.data = new_data; self.data = new_data.into_boxed_slice();
self.dimensions = new_dim; self.dimensions = new_dim;
self.original_dimension = (self.original_dimension.1, self.original_dimension.0); self.original_dimension = (self.original_dimension.1, self.original_dimension.0);
self.origin = (self.origin.1, self.origin.0); self.origin = (self.origin.1, self.origin.0);
@@ -184,7 +176,7 @@ impl Luma8LuminanceSource {
Self { Self {
dimensions: (width, height), dimensions: (width, height),
origin: (0, 0), origin: (0, 0),
data: source, data: source.into_boxed_slice(),
inverted: false, inverted: false,
original_dimension: (width, height), original_dimension: (width, height),
} }
@@ -194,13 +186,13 @@ impl Luma8LuminanceSource {
Self { Self {
dimensions: (width as u32, height as u32), dimensions: (width as u32, height as u32),
origin: (0, 0), origin: (0, 0),
data: vec![0u8; width * height], data: vec![0u8; width * height].into_boxed_slice(),
inverted: false, inverted: false,
original_dimension: (width as u32, height as u32), original_dimension: (width as u32, height as u32),
} }
} }
pub fn get_matrix_mut(&mut self) -> &mut Vec<u8> { pub fn get_matrix_mut(&mut self) -> &mut Box<[u8]> {
&mut self.data &mut self.data
} }
@@ -244,16 +236,19 @@ mod tests {
(rect_wide.dimensions.1, rect_wide.dimensions.0) (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!( assert_eq!(
rotated_wide_rect.data, 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!( assert_eq!(
rotated_tall_rect.data, 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()
); );
} }
} }

View File

@@ -29,8 +29,8 @@ use crate::Exceptions;
* @author dswitkin@google.com (Daniel Switkin) * @author dswitkin@google.com (Daniel Switkin)
*/ */
pub trait LuminanceSource { pub trait LuminanceSource {
//private final int width; const SUPPORTS_ROTATION: bool = false;
//private final int height; const SUPPORTS_CROP: bool = false;
//fn new( width:usize, height:usize) -> Self; //fn new( width:usize, height:usize) -> Self;
@@ -75,7 +75,14 @@ pub trait LuminanceSource {
* @return Whether this subclass supports cropping. * @return Whether this subclass supports cropping.
*/ */
fn is_crop_supported(&self) -> bool { 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 * @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). * white and vice versa, and each value becomes (255-value).

View File

@@ -1143,7 +1143,7 @@ mod detector_test {
.read_to_string(&mut expected_result) .read_to_string(&mut expected_result)
.unwrap(); .unwrap();
let detection = super::detect(bitmatrix, true).unwrap(); let detection = super::detect(&bitmatrix, true).unwrap();
// let i: image::DynamicImage = detection.getBits().into(); // let i: image::DynamicImage = detection.getBits().into();
// i.save("dbgfle-transformed.png") // i.save("dbgfle-transformed.png")

View File

@@ -433,115 +433,115 @@ impl Code128Reader {
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
pub static CODE_PATTERNS: Lazy<[Vec<u32>; 107]> = Lazy::new(|| { pub static CODE_PATTERNS: Lazy<[Box<[u32]>; 107]> = Lazy::new(|| {
[ [
vec![2, 1, 2, 2, 2, 2], // 0 Box::new([2, 1, 2, 2, 2, 2]), // 0
vec![2, 2, 2, 1, 2, 2], Box::new([2, 2, 2, 1, 2, 2]),
vec![2, 2, 2, 2, 2, 1], Box::new([2, 2, 2, 2, 2, 1]),
vec![1, 2, 1, 2, 2, 3], Box::new([1, 2, 1, 2, 2, 3]),
vec![1, 2, 1, 3, 2, 2], Box::new([1, 2, 1, 3, 2, 2]),
vec![1, 3, 1, 2, 2, 2], // 5 Box::new([1, 3, 1, 2, 2, 2]), // 5
vec![1, 2, 2, 2, 1, 3], Box::new([1, 2, 2, 2, 1, 3]),
vec![1, 2, 2, 3, 1, 2], Box::new([1, 2, 2, 3, 1, 2]),
vec![1, 3, 2, 2, 1, 2], Box::new([1, 3, 2, 2, 1, 2]),
vec![2, 2, 1, 2, 1, 3], Box::new([2, 2, 1, 2, 1, 3]),
vec![2, 2, 1, 3, 1, 2], // 10 Box::new([2, 2, 1, 3, 1, 2]), // 10
vec![2, 3, 1, 2, 1, 2], Box::new([2, 3, 1, 2, 1, 2]),
vec![1, 1, 2, 2, 3, 2], Box::new([1, 1, 2, 2, 3, 2]),
vec![1, 2, 2, 1, 3, 2], Box::new([1, 2, 2, 1, 3, 2]),
vec![1, 2, 2, 2, 3, 1], Box::new([1, 2, 2, 2, 3, 1]),
vec![1, 1, 3, 2, 2, 2], // 15 Box::new([1, 1, 3, 2, 2, 2]), // 15
vec![1, 2, 3, 1, 2, 2], Box::new([1, 2, 3, 1, 2, 2]),
vec![1, 2, 3, 2, 2, 1], Box::new([1, 2, 3, 2, 2, 1]),
vec![2, 2, 3, 2, 1, 1], Box::new([2, 2, 3, 2, 1, 1]),
vec![2, 2, 1, 1, 3, 2], Box::new([2, 2, 1, 1, 3, 2]),
vec![2, 2, 1, 2, 3, 1], // 20 Box::new([2, 2, 1, 2, 3, 1]), // 20
vec![2, 1, 3, 2, 1, 2], Box::new([2, 1, 3, 2, 1, 2]),
vec![2, 2, 3, 1, 1, 2], Box::new([2, 2, 3, 1, 1, 2]),
vec![3, 1, 2, 1, 3, 1], Box::new([3, 1, 2, 1, 3, 1]),
vec![3, 1, 1, 2, 2, 2], Box::new([3, 1, 1, 2, 2, 2]),
vec![3, 2, 1, 1, 2, 2], // 25 Box::new([3, 2, 1, 1, 2, 2]), // 25
vec![3, 2, 1, 2, 2, 1], Box::new([3, 2, 1, 2, 2, 1]),
vec![3, 1, 2, 2, 1, 2], Box::new([3, 1, 2, 2, 1, 2]),
vec![3, 2, 2, 1, 1, 2], Box::new([3, 2, 2, 1, 1, 2]),
vec![3, 2, 2, 2, 1, 1], Box::new([3, 2, 2, 2, 1, 1]),
vec![2, 1, 2, 1, 2, 3], // 30 Box::new([2, 1, 2, 1, 2, 3]), // 30
vec![2, 1, 2, 3, 2, 1], Box::new([2, 1, 2, 3, 2, 1]),
vec![2, 3, 2, 1, 2, 1], Box::new([2, 3, 2, 1, 2, 1]),
vec![1, 1, 1, 3, 2, 3], Box::new([1, 1, 1, 3, 2, 3]),
vec![1, 3, 1, 1, 2, 3], Box::new([1, 3, 1, 1, 2, 3]),
vec![1, 3, 1, 3, 2, 1], // 35 Box::new([1, 3, 1, 3, 2, 1]), // 35
vec![1, 1, 2, 3, 1, 3], Box::new([1, 1, 2, 3, 1, 3]),
vec![1, 3, 2, 1, 1, 3], Box::new([1, 3, 2, 1, 1, 3]),
vec![1, 3, 2, 3, 1, 1], Box::new([1, 3, 2, 3, 1, 1]),
vec![2, 1, 1, 3, 1, 3], Box::new([2, 1, 1, 3, 1, 3]),
vec![2, 3, 1, 1, 1, 3], // 40 Box::new([2, 3, 1, 1, 1, 3]), // 40
vec![2, 3, 1, 3, 1, 1], Box::new([2, 3, 1, 3, 1, 1]),
vec![1, 1, 2, 1, 3, 3], Box::new([1, 1, 2, 1, 3, 3]),
vec![1, 1, 2, 3, 3, 1], Box::new([1, 1, 2, 3, 3, 1]),
vec![1, 3, 2, 1, 3, 1], Box::new([1, 3, 2, 1, 3, 1]),
vec![1, 1, 3, 1, 2, 3], // 45 Box::new([1, 1, 3, 1, 2, 3]), // 45
vec![1, 1, 3, 3, 2, 1], Box::new([1, 1, 3, 3, 2, 1]),
vec![1, 3, 3, 1, 2, 1], Box::new([1, 3, 3, 1, 2, 1]),
vec![3, 1, 3, 1, 2, 1], Box::new([3, 1, 3, 1, 2, 1]),
vec![2, 1, 1, 3, 3, 1], Box::new([2, 1, 1, 3, 3, 1]),
vec![2, 3, 1, 1, 3, 1], // 50 Box::new([2, 3, 1, 1, 3, 1]), // 50
vec![2, 1, 3, 1, 1, 3], Box::new([2, 1, 3, 1, 1, 3]),
vec![2, 1, 3, 3, 1, 1], Box::new([2, 1, 3, 3, 1, 1]),
vec![2, 1, 3, 1, 3, 1], Box::new([2, 1, 3, 1, 3, 1]),
vec![3, 1, 1, 1, 2, 3], Box::new([3, 1, 1, 1, 2, 3]),
vec![3, 1, 1, 3, 2, 1], // 55 Box::new([3, 1, 1, 3, 2, 1]), // 55
vec![3, 3, 1, 1, 2, 1], Box::new([3, 3, 1, 1, 2, 1]),
vec![3, 1, 2, 1, 1, 3], Box::new([3, 1, 2, 1, 1, 3]),
vec![3, 1, 2, 3, 1, 1], Box::new([3, 1, 2, 3, 1, 1]),
vec![3, 3, 2, 1, 1, 1], Box::new([3, 3, 2, 1, 1, 1]),
vec![3, 1, 4, 1, 1, 1], // 60 Box::new([3, 1, 4, 1, 1, 1]), // 60
vec![2, 2, 1, 4, 1, 1], Box::new([2, 2, 1, 4, 1, 1]),
vec![4, 3, 1, 1, 1, 1], Box::new([4, 3, 1, 1, 1, 1]),
vec![1, 1, 1, 2, 2, 4], Box::new([1, 1, 1, 2, 2, 4]),
vec![1, 1, 1, 4, 2, 2], Box::new([1, 1, 1, 4, 2, 2]),
vec![1, 2, 1, 1, 2, 4], // 65 Box::new([1, 2, 1, 1, 2, 4]), // 65
vec![1, 2, 1, 4, 2, 1], Box::new([1, 2, 1, 4, 2, 1]),
vec![1, 4, 1, 1, 2, 2], Box::new([1, 4, 1, 1, 2, 2]),
vec![1, 4, 1, 2, 2, 1], Box::new([1, 4, 1, 2, 2, 1]),
vec![1, 1, 2, 2, 1, 4], Box::new([1, 1, 2, 2, 1, 4]),
vec![1, 1, 2, 4, 1, 2], // 70 Box::new([1, 1, 2, 4, 1, 2]), // 70
vec![1, 2, 2, 1, 1, 4], Box::new([1, 2, 2, 1, 1, 4]),
vec![1, 2, 2, 4, 1, 1], Box::new([1, 2, 2, 4, 1, 1]),
vec![1, 4, 2, 1, 1, 2], Box::new([1, 4, 2, 1, 1, 2]),
vec![1, 4, 2, 2, 1, 1], Box::new([1, 4, 2, 2, 1, 1]),
vec![2, 4, 1, 2, 1, 1], // 75 Box::new([2, 4, 1, 2, 1, 1]), // 75
vec![2, 2, 1, 1, 1, 4], Box::new([2, 2, 1, 1, 1, 4]),
vec![4, 1, 3, 1, 1, 1], Box::new([4, 1, 3, 1, 1, 1]),
vec![2, 4, 1, 1, 1, 2], Box::new([2, 4, 1, 1, 1, 2]),
vec![1, 3, 4, 1, 1, 1], Box::new([1, 3, 4, 1, 1, 1]),
vec![1, 1, 1, 2, 4, 2], // 80 Box::new([1, 1, 1, 2, 4, 2]), // 80
vec![1, 2, 1, 1, 4, 2], Box::new([1, 2, 1, 1, 4, 2]),
vec![1, 2, 1, 2, 4, 1], Box::new([1, 2, 1, 2, 4, 1]),
vec![1, 1, 4, 2, 1, 2], Box::new([1, 1, 4, 2, 1, 2]),
vec![1, 2, 4, 1, 1, 2], Box::new([1, 2, 4, 1, 1, 2]),
vec![1, 2, 4, 2, 1, 1], // 85 Box::new([1, 2, 4, 2, 1, 1]), // 85
vec![4, 1, 1, 2, 1, 2], Box::new([4, 1, 1, 2, 1, 2]),
vec![4, 2, 1, 1, 1, 2], Box::new([4, 2, 1, 1, 1, 2]),
vec![4, 2, 1, 2, 1, 1], Box::new([4, 2, 1, 2, 1, 1]),
vec![2, 1, 2, 1, 4, 1], Box::new([2, 1, 2, 1, 4, 1]),
vec![2, 1, 4, 1, 2, 1], // 90 Box::new([2, 1, 4, 1, 2, 1]), // 90
vec![4, 1, 2, 1, 2, 1], Box::new([4, 1, 2, 1, 2, 1]),
vec![1, 1, 1, 1, 4, 3], Box::new([1, 1, 1, 1, 4, 3]),
vec![1, 1, 1, 3, 4, 1], Box::new([1, 1, 1, 3, 4, 1]),
vec![1, 3, 1, 1, 4, 1], Box::new([1, 3, 1, 1, 4, 1]),
vec![1, 1, 4, 1, 1, 3], // 95 Box::new([1, 1, 4, 1, 1, 3]), // 95
vec![1, 1, 4, 3, 1, 1], Box::new([1, 1, 4, 3, 1, 1]),
vec![4, 1, 1, 1, 1, 3], Box::new([4, 1, 1, 1, 1, 3]),
vec![4, 1, 1, 3, 1, 1], Box::new([4, 1, 1, 3, 1, 1]),
vec![1, 1, 3, 1, 4, 1], Box::new([1, 1, 3, 1, 4, 1]),
vec![1, 1, 4, 1, 3, 1], // 100 Box::new([1, 1, 4, 1, 3, 1]), // 100
vec![3, 1, 1, 1, 4, 1], Box::new([3, 1, 1, 1, 4, 1]),
vec![4, 1, 1, 1, 3, 1], Box::new([4, 1, 1, 1, 3, 1]),
vec![2, 1, 1, 4, 1, 2], Box::new([2, 1, 1, 4, 1, 2]),
vec![2, 1, 1, 2, 1, 4], Box::new([2, 1, 1, 2, 1, 4]),
vec![2, 1, 1, 2, 3, 2], // 105 Box::new([2, 1, 1, 2, 3, 2]), // 105
vec![2, 3, 3, 1, 1, 1, 2], Box::new([2, 3, 3, 1, 1, 1, 2]),
] ]
}); });

View File

@@ -265,7 +265,7 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
for _i in 0..modules { for _i in 0..modules {
dataBits.appendBits( dataBits.appendBits(
if next.index() % 2 == 0 { if next.index() % 2 == 0 {
0xFFFFFFFF 0xFFFFFFFF_u32
} else { } else {
0x0 0x0
}, },

View File

@@ -25,15 +25,15 @@
*/ */
pub struct EANManufacturerOrgSupport { pub struct EANManufacturerOrgSupport {
ranges: Vec<Vec<u32>>, //= new ArrayList<>(); ranges: Vec<[u32; 2]>, //= new ArrayList<>();
countryIdentifiers: Vec<String>, // = new ArrayList<>(); countryIdentifiers: Vec<&'static str>, // = new ArrayList<>();
} }
impl Default for EANManufacturerOrgSupport { impl Default for EANManufacturerOrgSupport {
fn default() -> Self { fn default() -> Self {
let mut slf = Self { let mut slf = Self {
ranges: Default::default(), ranges: Vec::with_capacity(150),
countryIdentifiers: Default::default(), countryIdentifiers: Vec::with_capacity(150),
}; };
slf.initIfNeeded(); slf.initIfNeeded();
slf slf
@@ -42,14 +42,14 @@ impl Default for EANManufacturerOrgSupport {
impl EANManufacturerOrgSupport { impl EANManufacturerOrgSupport {
pub fn lookupCountryIdentifier(&self, productCode: &str) -> Option<&str> { pub fn lookupCountryIdentifier(&self, productCode: &str) -> Option<&str> {
let prefix = productCode[0..3].parse::<u32>().expect("must parse prefix"); let prefix = productCode[0..3].parse::<u32>().ok()?;
let max = self.ranges.len(); let max = self.ranges.len();
for (i, range) in self.ranges.iter().enumerate().take(max) { for (i, range) in self.ranges.iter().enumerate().take(max) {
let start = range[0]; let start = range[0];
if prefix < start { if prefix < start {
return None; 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 { if prefix <= end {
return Some(self.countryIdentifiers.get(i)?); return Some(self.countryIdentifiers.get(i)?);
} }
@@ -58,7 +58,7 @@ impl EANManufacturerOrgSupport {
None None
} }
fn add(&mut self, range: Vec<u32>, id: String) { fn add(&mut self, range: [u32; 2], id: &'static str) {
self.ranges.push(range); self.ranges.push(range);
self.countryIdentifiers.push(id); self.countryIdentifiers.push(id);
} }
@@ -67,112 +67,112 @@ impl EANManufacturerOrgSupport {
if !self.ranges.is_empty() { if !self.ranges.is_empty() {
return; return;
} }
self.add(vec![0, 19], "US/CA".to_owned()); self.add([0, 19], "US/CA");
self.add(vec![30, 39], "US".to_owned()); self.add([30, 39], "US");
self.add(vec![60, 139], "US/CA".to_owned()); self.add([60, 139], "US/CA");
self.add(vec![300, 379], "FR".to_owned()); self.add([300, 379], "FR");
self.add(vec![380], "BG".to_owned()); self.add([380, 0], "BG");
self.add(vec![383], "SI".to_owned()); self.add([383, 0], "SI");
self.add(vec![385], "HR".to_owned()); self.add([385, 0], "HR");
self.add(vec![387], "BA".to_owned()); self.add([387, 0], "BA");
self.add(vec![400, 440], "DE".to_owned()); self.add([400, 440], "DE");
self.add(vec![450, 459], "JP".to_owned()); self.add([450, 459], "JP");
self.add(vec![460, 469], "RU".to_owned()); self.add([460, 469], "RU");
self.add(vec![471], "TW".to_owned()); self.add([471, 0], "TW");
self.add(vec![474], "EE".to_owned()); self.add([474, 0], "EE");
self.add(vec![475], "LV".to_owned()); self.add([475, 0], "LV");
self.add(vec![476], "AZ".to_owned()); self.add([476, 0], "AZ");
self.add(vec![477], "LT".to_owned()); self.add([477, 0], "LT");
self.add(vec![478], "UZ".to_owned()); self.add([478, 0], "UZ");
self.add(vec![479], "LK".to_owned()); self.add([479, 0], "LK");
self.add(vec![480], "PH".to_owned()); self.add([480, 0], "PH");
self.add(vec![481], "BY".to_owned()); self.add([481, 0], "BY");
self.add(vec![482], "UA".to_owned()); self.add([482, 0], "UA");
self.add(vec![484], "MD".to_owned()); self.add([484, 0], "MD");
self.add(vec![485], "AM".to_owned()); self.add([485, 0], "AM");
self.add(vec![486], "GE".to_owned()); self.add([486, 0], "GE");
self.add(vec![487], "KZ".to_owned()); self.add([487, 0], "KZ");
self.add(vec![489], "HK".to_owned()); self.add([489, 0], "HK");
self.add(vec![490, 499], "JP".to_owned()); self.add([490, 499], "JP");
self.add(vec![500, 509], "GB".to_owned()); self.add([500, 509], "GB");
self.add(vec![520], "GR".to_owned()); self.add([520, 0], "GR");
self.add(vec![528], "LB".to_owned()); self.add([528, 0], "LB");
self.add(vec![529], "CY".to_owned()); self.add([529, 0], "CY");
self.add(vec![531], "MK".to_owned()); self.add([531, 0], "MK");
self.add(vec![535], "MT".to_owned()); self.add([535, 0], "MT");
self.add(vec![539], "IE".to_owned()); self.add([539, 0], "IE");
self.add(vec![540, 549], "BE/LU".to_owned()); self.add([540, 549], "BE/LU");
self.add(vec![560], "PT".to_owned()); self.add([560, 0], "PT");
self.add(vec![569], "IS".to_owned()); self.add([569, 0], "IS");
self.add(vec![570, 579], "DK".to_owned()); self.add([570, 579], "DK");
self.add(vec![590], "PL".to_owned()); self.add([590, 0], "PL");
self.add(vec![594], "RO".to_owned()); self.add([594, 0], "RO");
self.add(vec![599], "HU".to_owned()); self.add([599, 0], "HU");
self.add(vec![600, 601], "ZA".to_owned()); self.add([600, 601], "ZA");
self.add(vec![603], "GH".to_owned()); self.add([603, 0], "GH");
self.add(vec![608], "BH".to_owned()); self.add([608, 0], "BH");
self.add(vec![609], "MU".to_owned()); self.add([609, 0], "MU");
self.add(vec![611], "MA".to_owned()); self.add([611, 0], "MA");
self.add(vec![613], "DZ".to_owned()); self.add([613, 0], "DZ");
self.add(vec![616], "KE".to_owned()); self.add([616, 0], "KE");
self.add(vec![618], "CI".to_owned()); self.add([618, 0], "CI");
self.add(vec![619], "TN".to_owned()); self.add([619, 0], "TN");
self.add(vec![621], "SY".to_owned()); self.add([621, 0], "SY");
self.add(vec![622], "EG".to_owned()); self.add([622, 0], "EG");
self.add(vec![624], "LY".to_owned()); self.add([624, 0], "LY");
self.add(vec![625], "JO".to_owned()); self.add([625, 0], "JO");
self.add(vec![626], "IR".to_owned()); self.add([626, 0], "IR");
self.add(vec![627], "KW".to_owned()); self.add([627, 0], "KW");
self.add(vec![628], "SA".to_owned()); self.add([628, 0], "SA");
self.add(vec![629], "AE".to_owned()); self.add([629, 0], "AE");
self.add(vec![640, 649], "FI".to_owned()); self.add([640, 649], "FI");
self.add(vec![690, 695], "CN".to_owned()); self.add([690, 695], "CN");
self.add(vec![700, 709], "NO".to_owned()); self.add([700, 709], "NO");
self.add(vec![729], "IL".to_owned()); self.add([729, 0], "IL");
self.add(vec![730, 739], "SE".to_owned()); self.add([730, 739], "SE");
self.add(vec![740], "GT".to_owned()); self.add([740, 0], "GT");
self.add(vec![741], "SV".to_owned()); self.add([741, 0], "SV");
self.add(vec![742], "HN".to_owned()); self.add([742, 0], "HN");
self.add(vec![743], "NI".to_owned()); self.add([743, 0], "NI");
self.add(vec![744], "CR".to_owned()); self.add([744, 0], "CR");
self.add(vec![745], "PA".to_owned()); self.add([745, 0], "PA");
self.add(vec![746], "DO".to_owned()); self.add([746, 0], "DO");
self.add(vec![750], "MX".to_owned()); self.add([750, 0], "MX");
self.add(vec![754, 755], "CA".to_owned()); self.add([754, 755], "CA");
self.add(vec![759], "VE".to_owned()); self.add([759, 0], "VE");
self.add(vec![760, 769], "CH".to_owned()); self.add([760, 769], "CH");
self.add(vec![770], "CO".to_owned()); self.add([770, 0], "CO");
self.add(vec![773], "UY".to_owned()); self.add([773, 0], "UY");
self.add(vec![775], "PE".to_owned()); self.add([775, 0], "PE");
self.add(vec![777], "BO".to_owned()); self.add([777, 0], "BO");
self.add(vec![779], "AR".to_owned()); self.add([779, 0], "AR");
self.add(vec![780], "CL".to_owned()); self.add([780, 0], "CL");
self.add(vec![784], "PY".to_owned()); self.add([784, 0], "PY");
self.add(vec![785], "PE".to_owned()); self.add([785, 0], "PE");
self.add(vec![786], "EC".to_owned()); self.add([786, 0], "EC");
self.add(vec![789, 790], "BR".to_owned()); self.add([789, 790], "BR");
self.add(vec![800, 839], "IT".to_owned()); self.add([800, 839], "IT");
self.add(vec![840, 849], "ES".to_owned()); self.add([840, 849], "ES");
self.add(vec![850], "CU".to_owned()); self.add([850, 0], "CU");
self.add(vec![858], "SK".to_owned()); self.add([858, 0], "SK");
self.add(vec![859], "CZ".to_owned()); self.add([859, 0], "CZ");
self.add(vec![860], "YU".to_owned()); self.add([860, 0], "YU");
self.add(vec![865], "MN".to_owned()); self.add([865, 0], "MN");
self.add(vec![867], "KP".to_owned()); self.add([867, 0], "KP");
self.add(vec![868, 869], "TR".to_owned()); self.add([868, 869], "TR");
self.add(vec![870, 879], "NL".to_owned()); self.add([870, 879], "NL");
self.add(vec![880], "KR".to_owned()); self.add([880, 0], "KR");
self.add(vec![885], "TH".to_owned()); self.add([885, 0], "TH");
self.add(vec![888], "SG".to_owned()); self.add([888, 0], "SG");
self.add(vec![890], "IN".to_owned()); self.add([890, 0], "IN");
self.add(vec![893], "VN".to_owned()); self.add([893, 0], "VN");
self.add(vec![896], "PK".to_owned()); self.add([896, 0], "PK");
self.add(vec![899], "ID".to_owned()); self.add([899, 0], "ID");
self.add(vec![900, 919], "AT".to_owned()); self.add([900, 919], "AT");
self.add(vec![930, 939], "AU".to_owned()); self.add([930, 939], "AU");
self.add(vec![940, 949], "AZ".to_owned()); self.add([940, 949], "AZ");
self.add(vec![955], "MY".to_owned()); self.add([955, 0], "MY");
self.add(vec![958], "MO".to_owned()); self.add([958, 0], "MO");
} }
} }

View File

@@ -85,19 +85,12 @@ pub trait AbstractRSSReaderTrait: OneDReader {
let ratio: f32 = (firstTwoSum as f32) / (sum as f32); let ratio: f32 = (firstTwoSum as f32) / (sum as f32);
if ratio >= Self::MIN_FINDER_PATTERN_RATIO && ratio <= Self::MAX_FINDER_PATTERN_RATIO { 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 // 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 minCounter = u32::MAX;
let mut maxCounter = u32::MIN; let mut maxCounter = u32::MIN;
for counter in counters { for counter in counters {
maxCounter = std::cmp::max(*counter, maxCounter); maxCounter = std::cmp::max(*counter, maxCounter);
minCounter = std::cmp::min(*counter, minCounter); minCounter = std::cmp::min(*counter, minCounter);
// if *counter > maxCounter {
// maxCounter = *counter;
// }
// if *counter < minCounter {
// minCounter = *counter;
// }
} }
return maxCounter < 10 * minCounter; return maxCounter < 10 * minCounter;
} }

View File

@@ -93,62 +93,14 @@ pub fn createDecoder<'a>(
let sevenBitEncodationMethod = let sevenBitEncodationMethod =
GeneralAppIdDecoder::extractNumericValueFromBitArrayWithInformation(information, 1, 7); GeneralAppIdDecoder::extractNumericValueFromBitArrayWithInformation(information, 1, 7);
match sevenBitEncodationMethod { match sevenBitEncodationMethod {
56 => { 56 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "11"))),
return Ok(Box::new(AI013x0x1xDecoder::new( 57 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "11"))),
information, 58 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "310", "13"))),
"310".to_owned(), 59 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "13"))),
"11".to_owned(), 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"))),
57 => { 63 => return Ok(Box::new(AI013x0x1xDecoder::new(information, "320", "17"))),
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(),
)))
}
_ => {} _ => {}
} }

View File

@@ -35,8 +35,8 @@ use super::{AI01decoder, AI01weightDecoder, AbstractExpandedDecoder, GeneralAppI
pub struct AI013x0x1xDecoder<'a> { pub struct AI013x0x1xDecoder<'a> {
information: &'a BitArray, information: &'a BitArray,
decoder: GeneralAppIdDecoder<'a>, decoder: GeneralAppIdDecoder<'a>,
dateCode: String, dateCode: &'static str,
firstAIdigits: String, firstAIdigits: &'static str,
} }
impl AI01weightDecoder for AI013x0x1xDecoder<'_> { impl AI01weightDecoder for AI013x0x1xDecoder<'_> {
@@ -88,8 +88,8 @@ impl<'a> AI013x0x1xDecoder<'_> {
pub fn new( pub fn new(
information: &'a BitArray, information: &'a BitArray,
firstAIdigits: String, firstAIdigits: &'static str,
dateCode: String, dateCode: &'static str,
) -> AI013x0x1xDecoder<'a> { ) -> AI013x0x1xDecoder<'a> {
AI013x0x1xDecoder { AI013x0x1xDecoder {
information, information,

View File

@@ -57,7 +57,6 @@ impl OneDReader for RSS14Reader {
row.reverse(); row.reverse();
let rightPair = self.decodePair(&row, true, rowNumber, hints); let rightPair = self.decodePair(&row, true, rowNumber, hints);
Self::addOrTally(&mut self.possibleRightPairs, rightPair); Self::addOrTally(&mut self.possibleRightPairs, rightPair);
row.reverse();
for left in &self.possibleLeftPairs { for left in &self.possibleLeftPairs {
if left.getCount() > 1 { if left.getCount() > 1 {
for right in &self.possibleRightPairs { for right in &self.possibleRightPairs {
@@ -246,9 +245,10 @@ impl RSS14Reader {
rowNumber: u32, rowNumber: u32,
hints: &DecodingHintDictionary, hints: &DecodingHintDictionary,
) -> Option<Pair> { ) -> Option<Pair> {
let pos_pair = || -> Result<Pair> { let startEnd = self.findFinderPattern(row, right).ok()?;
let startEnd = self.findFinderPattern(row, right)?; let pattern = self
let pattern = self.parseFoundFinderPattern(row, rowNumber, right, &startEnd)?; .parseFoundFinderPattern(row, rowNumber, right, &startEnd)
.ok()?;
if let Some(DecodeHintValue::NeedResultPointCallback(cb)) = if let Some(DecodeHintValue::NeedResultPointCallback(cb)) =
hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK) hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK)
@@ -262,19 +262,16 @@ impl RSS14Reader {
cb(point_f(center, rowNumber as f32)); cb(point_f(center, rowNumber as f32));
} }
let outside = self.decodeDataCharacter(row, &pattern, true)?; let outside = self.decodeDataCharacter(row, &pattern, true).ok()?;
let inside = self.decodeDataCharacter(row, &pattern, false)?; let inside = self.decodeDataCharacter(row, &pattern, false).ok()?;
// todo!("must add callback"); // todo!("must add callback");
Ok(Pair::new( Some(Pair::new(
1597 * outside.getValue() + inside.getValue(), 1597 * outside.getValue() + inside.getValue(),
outside.getChecksumPortion() + 4 * inside.getChecksumPortion(), outside.getChecksumPortion() + 4 * inside.getChecksumPortion(),
pattern, pattern,
)) ))
}();
pos_pair.ok()
} }
fn decodeDataCharacter( fn decodeDataCharacter(

View File

@@ -66,7 +66,7 @@ impl OneDimensionalCodeWriter for TelepenWriter {
for c in decodedContents.chars() { for c in decodedContents.chars() {
if c as u32 > 127 { if c as u32 > 127 {
return Err(Exceptions::illegal_argument_with( 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" => { "0" => {
return Err(Exceptions::illegal_argument_with( return Err(Exceptions::illegal_argument_with(
"Invalid bit combination!".to_string(), "Invalid bit combination!",
)); ));
} }
_ => { _ => {

View File

@@ -188,7 +188,7 @@ impl UPCEANExtension5Support {
"99991" => "99991" =>
// Complementary // Complementary
{ {
return Some("0.00".to_string()) return Some("0.00".to_owned())
} }
"99990" => return Some("Used".to_owned()), "99990" => return Some("Used".to_owned()),
_ => {} _ => {}

View File

@@ -237,6 +237,9 @@ impl PlanarYUVLuminanceSource {
} }
impl LuminanceSource for PlanarYUVLuminanceSource { impl LuminanceSource for PlanarYUVLuminanceSource {
const SUPPORTS_CROP: bool = true;
const SUPPORTS_ROTATION: bool = false;
fn get_row(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
if y >= self.get_height() { if y >= self.get_height() {
// //throw new IllegalArgumentException("Requested row is outside the image: " + y); // //throw new IllegalArgumentException("Requested row is outside the image: " + y);
@@ -310,10 +313,6 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
self.height self.height
} }
fn is_crop_supported(&self) -> bool {
true
}
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> { fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
PlanarYUVLuminanceSource::new_with_all( PlanarYUVLuminanceSource::new_with_all(
self.yuv_data.clone(), self.yuv_data.clone(),
@@ -329,10 +328,6 @@ impl LuminanceSource for PlanarYUVLuminanceSource {
.map_err(|_| Exceptions::UNSUPPORTED_OPERATION) .map_err(|_| Exceptions::UNSUPPORTED_OPERATION)
} }
fn is_rotate_supported(&self) -> bool {
false
}
fn invert(&mut self) { fn invert(&mut self) {
self.invert = !self.invert; self.invert = !self.invert;
} }

View File

@@ -56,7 +56,7 @@ impl ErrorCorrectionLevel {
} }
} }
pub fn get_value(&self) -> u8 { pub const fn get_value(&self) -> u8 {
match self { match self {
ErrorCorrectionLevel::L => 0x01, ErrorCorrectionLevel::L => 0x01,
ErrorCorrectionLevel::M => 0x00, ErrorCorrectionLevel::M => 0x00,
@@ -66,7 +66,7 @@ impl ErrorCorrectionLevel {
} }
} }
pub fn get_ordinal(&self) -> u8 { pub const fn get_ordinal(&self) -> u8 {
match self { match self {
ErrorCorrectionLevel::L => 0, ErrorCorrectionLevel::L => 0,
ErrorCorrectionLevel::M => 1, ErrorCorrectionLevel::M => 1,

View File

@@ -28,10 +28,10 @@ use once_cell::sync::Lazy;
pub type VersionRef = &'static Version; pub type VersionRef = &'static Version;
pub static VERSIONS: Lazy<Vec<Version>> = Lazy::new(Version::buildVersions); pub static VERSIONS: Lazy<Box<[Version]>> = Lazy::new(Version::buildVersions);
pub static MICRO_VERSIONS: Lazy<Vec<Version>> = Lazy::new(Version::build_micro_versions); pub static MICRO_VERSIONS: Lazy<Box<[Version]>> = Lazy::new(Version::build_micro_versions);
pub static MODEL1_VERSIONS: Lazy<Vec<Version>> = Lazy::new(Version::build_model1_versions); pub static MODEL1_VERSIONS: Lazy<Box<[Version]>> = Lazy::new(Version::build_model1_versions);
pub static RMQR_VERSIONS: Lazy<Vec<Version>> = Lazy::new(Version::build_rmqr_versions); pub static RMQR_VERSIONS: Lazy<Box<[Version]>> = Lazy::new(Version::build_rmqr_versions);
/** /**
* See ISO 18004:2006 Annex D. * See ISO 18004:2006 Annex D.
@@ -54,15 +54,15 @@ pub const VERSION_DECODE_INFO: [u32; 34] = [
pub struct Version { pub struct Version {
// private static final Version[] VERSIONS = buildVersions(); // private static final Version[] VERSIONS = buildVersions();
versionNumber: u32, versionNumber: u32,
alignmentPatternCenters: Vec<u32>, alignmentPatternCenters: Box<[u32]>,
ecBlocks: Vec<ECBlocks>, ecBlocks: Box<[ECBlocks]>,
totalCodewords: u32, totalCodewords: u32,
pub(crate) qr_type: Type, pub(crate) qr_type: Type,
} }
impl Version { impl Version {
pub(super) fn new( pub(super) fn new(
versionNumber: u32, versionNumber: u32,
alignmentPatternCenters: Vec<u32>, alignmentPatternCenters: Box<[u32]>,
ecBlocks: [ECBlocks; 4], ecBlocks: [ECBlocks; 4],
) -> Self { ) -> Self {
let mut total = 0; let mut total = 0;
@@ -78,17 +78,20 @@ impl Version {
Self { Self {
versionNumber, versionNumber,
alignmentPatternCenters, alignmentPatternCenters,
ecBlocks: ecBlocks.to_vec(),
totalCodewords: total,
qr_type: if ecBlocks[0].getECCodewordsPerBlock() != 0 { qr_type: if ecBlocks[0].getECCodewordsPerBlock() != 0 {
Type::Model2 Type::Model2
} else { } else {
Type::RectMicro Type::RectMicro
}, },
ecBlocks: Box::new(ecBlocks),
totalCodewords: total,
} }
} }
pub(super) fn without_alignment_patterns(versionNumber: u32, ecBlocks: Vec<ECBlocks>) -> Self { pub(super) fn without_alignment_patterns(
versionNumber: u32,
ecBlocks: Box<[ECBlocks]>,
) -> Self {
let mut total = 0; let mut total = 0;
let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); let ecCodewords = ecBlocks[0].getECCodewordsPerBlock();
let ecbArray = ecBlocks[0].getECBlocks(); let ecbArray = ecBlocks[0].getECBlocks();
@@ -107,7 +110,7 @@ impl Version {
Self { Self {
versionNumber, versionNumber,
alignmentPatternCenters: Vec::default(), alignmentPatternCenters: Box::default(),
ecBlocks, ecBlocks,
totalCodewords: total, totalCodewords: total,
qr_type: symbol_type, qr_type: symbol_type,
@@ -118,11 +121,11 @@ impl Version {
self.versionNumber self.versionNumber
} }
pub fn getAlignmentPatternCenters(&self) -> &[u32] { pub const fn getAlignmentPatternCenters(&self) -> &[u32] {
&self.alignmentPatternCenters &self.alignmentPatternCenters
} }
pub fn getTotalCodewords(&self) -> u32 { pub const fn getTotalCodewords(&self) -> u32 {
self.totalCodewords self.totalCodewords
} }
@@ -131,7 +134,7 @@ impl Version {
// 17 + 4 * self.versionNumber // 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() { if ecLevel.get_ordinal() as usize >= self.ecBlocks.len() {
return &self.ecBlocks[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)] #[derive(Debug, Clone)]
pub struct ECBlocks { pub struct ECBlocks {
ecCodewordsPerBlock: u32, ecCodewordsPerBlock: u32,
ecBlocks: Vec<ECB>, ecBlocks: Box<[ECB]>,
} }
impl ECBlocks { impl ECBlocks {
pub const fn new(ecCodewordsPerBlock: u32, ecBlocks: Vec<ECB>) -> Self { pub const fn new(ecCodewordsPerBlock: u32, ecBlocks: Box<[ECB]>) -> Self {
Self { Self {
ecCodewordsPerBlock, ecCodewordsPerBlock,
ecBlocks, ecBlocks,
@@ -310,7 +313,7 @@ impl ECBlocks {
pub fn getNumBlocks(&self) -> u32 { pub fn getNumBlocks(&self) -> u32 {
let mut total = 0; let mut total = 0;
for ecBlock in &self.ecBlocks { for ecBlock in self.ecBlocks.iter() {
total += ecBlock.getCount(); total += ecBlock.getCount();
} }
total total

View File

@@ -13,18 +13,18 @@ macro_rules! qr_version {
),+ ),+
} }
) => { ) => {
vec![ Box::new([
$( $(
Version::without_alignment_patterns( Version::without_alignment_patterns(
$version, $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 // Model 2 & rMQR
( (
@@ -38,27 +38,27 @@ macro_rules! qr_version {
),+ ),+
} }
) => { ) => {
vec![ Box::new([
$( $(
Version::new($version, Version::new($version,
vec![ Box::new([
$( $(
$alignment_pattern $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 { impl Version {
pub fn build_micro_versions() -> Vec<Version> { pub fn build_micro_versions() -> Box<[Version]> {
qr_version!( qr_version!(
{ {
{1, {2, 1, 3, 0, 0}}, {1, {2, 1, 3, 0, 0}},
@@ -71,7 +71,7 @@ impl Version {
/** /**
* See ISO 18004:2006 6.5.1 Table 9 * See ISO 18004:2006 6.5.1 Table 9
*/ */
pub fn buildVersions() -> Vec<Version> { pub fn buildVersions() -> Box<[Version]> {
qr_version!({ qr_version!({
{1, {}, { {1, {}, {
7, 1, 19, 0, 0, 7, 1, 19, 0, 0,
@@ -316,7 +316,7 @@ impl Version {
}) })
} }
pub fn build_model1_versions() -> Vec<Version> { pub fn build_model1_versions() -> Box<[Version]> {
qr_version!( qr_version!(
{ {
{1, { {1, {
@@ -407,7 +407,7 @@ impl Version {
) )
} }
pub fn build_rmqr_versions() -> Vec<Version> { pub fn build_rmqr_versions() -> Box<[Version]> {
qr_version!( qr_version!(
{ {
// Version number, alignment pattern centres, `ECBlocks` // Version number, alignment pattern centres, `ECBlocks`

View File

@@ -127,7 +127,7 @@ fn testXOR() {
let mut v1 = BitArray::new(); let mut v1 = BitArray::new();
v1.appendBits(0x5555aaaa, 32).expect("append"); v1.appendBits(0x5555aaaa, 32).expect("append");
let mut v2 = BitArray::new(); let mut v2 = BitArray::new();
v2.appendBits(0xaaaa5555, 32).expect("append"); v2.appendBits(0xaaaa5555_u32, 32).expect("append");
v1.xor(&v2).expect("xor"); v1.xor(&v2).expect("xor");
assert_eq!(0xffffffff, getUnsignedInt(&v1)); assert_eq!(0xffffffff, getUnsignedInt(&v1));
} }

View File

@@ -39,6 +39,8 @@ pub struct RGBLuminanceSource {
} }
impl LuminanceSource for RGBLuminanceSource { impl LuminanceSource for RGBLuminanceSource {
const SUPPORTS_CROP: bool = true;
/// gets a row, returns an empty row if we are out of bounds. /// gets a row, returns an empty row if we are out of bounds.
fn get_row(&self, y: usize) -> Vec<u8> { fn get_row(&self, y: usize) -> Vec<u8> {
if y >= self.get_height() { if y >= self.get_height() {
@@ -111,10 +113,6 @@ impl LuminanceSource for RGBLuminanceSource {
self.height self.height
} }
fn is_crop_supported(&self) -> bool {
true
}
fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> { fn crop(&self, left: usize, top: usize, width: usize, height: usize) -> Result<Self> {
RGBLuminanceSource::new_complex( RGBLuminanceSource::new_complex(
&self.luminances, &self.luminances,

View File

@@ -1,6 +1,6 @@
// dxfilmedge-1 // dxfilmedge-1
#![cfg(feature = "image")] #![cfg(feature = "image, experimental_features")]
use rxing::{BarcodeFormat, FilteredImageReader, MultiFormatReader}; use rxing::{BarcodeFormat, FilteredImageReader, MultiFormatReader};