diff --git a/Cargo.toml b/Cargo.toml index e5286d9..17aa603 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -regex = "1.7.1" +regex = "1.8.0" fancy-regex = "0.11" once_cell = "1.17.1" encoding = "0.2" diff --git a/src/common/bit_array.rs b/src/common/bit_array.rs index 1587a85..b992bbb 100644 --- a/src/common/bit_array.rs +++ b/src/common/bit_array.rs @@ -83,6 +83,14 @@ impl BitArray { (self.bits[i / 32] & (1 << (i & 0x1F))) != 0 } + pub fn try_get(&self, i:usize) -> Option { + if (i / 32) >= self.bits.len() { + None + }else { +Some(self.get(i)) + } + } + /** * Sets bit i. * diff --git a/src/common/bit_matrix.rs b/src/common/bit_matrix.rs index d01ce76..f73d5d1 100644 --- a/src/common/bit_matrix.rs +++ b/src/common/bit_matrix.rs @@ -222,6 +222,10 @@ impl BitMatrix { // ((self.bits[offset] >> (x & 0x1f)) & 1) != 0 } + pub fn get_index>(&self, index: T) -> bool { + todo!() + } + #[inline(always)] fn get_offset(&self, y: u32, x: u32) -> usize { y as usize * self.row_size + (x as usize / 32) @@ -748,6 +752,19 @@ impl fmt::Display for BitMatrix { } } +impl From<&BitMatrix> for Vec { + fn from(value: &BitMatrix) -> Self { + let mut arr = vec![false;(value.width * value.height) as usize]; + for x in 0..value.width { + for y in 0..value.height { + let insert_pos = ((y * value.width) + x )as usize; + arr[insert_pos] = value.get(x, y); + } + } + arr + } +} + #[cfg(feature = "image")] /// This should only be used if you *know* that the `DynamicImage` is binary. impl TryFrom for BitMatrix { diff --git a/src/common/cpp_essentials/concentric_finder.rs b/src/common/cpp_essentials/concentric_finder.rs index b207141..13a9afe 100644 --- a/src/common/cpp_essentials/concentric_finder.rs +++ b/src/common/cpp_essentials/concentric_finder.rs @@ -68,7 +68,7 @@ pub fn ReadSymmetricPattern( for i in 0..=s_2 { // for (int i = 0; i <= s_2; ++i) { - if !next(cur, i) != 0 || !next(&mut cuo, -i) != 0 { + if !next(cur, i) == 0 || !next(&mut cuo, -i) == 0 { return None; } } @@ -124,14 +124,14 @@ pub fn CheckSymmetricPattern< } } - if !(IsPattern( + if IsPattern( &PatternView::new(&res), &FixedPattern::::with_reference(pattern), None, 0.0, 0.0, Some(RELAXED_THRESHOLD), - ) != 0.0) + ) == 0.0 { return 0; } @@ -220,9 +220,9 @@ pub fn CenterOfRing( n += 1; // find out if we come full circle around the center. 8 bits have to be set in the end. - neighbourMask |= 1 - << (4.0 + Point::dot(Point::bresenhamDirection(cur.p() - center), point(1.0, 3.0))) - as u32; + neighbourMask |= (1 + << (4.0 + Point::dot(Point::round(Point::bresenhamDirection(cur.p() - center)), point(1.0, 3.0))) + as u32); if !cur.stepAlongEdge(edgeDir, None) { return None; diff --git a/src/common/cpp_essentials/edge_tracer.rs b/src/common/cpp_essentials/edge_tracer.rs index 88a8a3c..309d7c7 100644 --- a/src/common/cpp_essentials/edge_tracer.rs +++ b/src/common/cpp_essentials/edge_tracer.rs @@ -182,7 +182,7 @@ impl<'a> EdgeTracer<'_> { EdgeTracer { img: image, p, - d, + d: Point::bresenhamDirection(d), //d, history: None, state: 0, } diff --git a/src/common/cpp_essentials/fast_edge_to_edge_counter.rs b/src/common/cpp_essentials/fast_edge_to_edge_counter.rs index 88ea88c..d1226c5 100644 --- a/src/common/cpp_essentials/fast_edge_to_edge_counter.rs +++ b/src/common/cpp_essentials/fast_edge_to_edge_counter.rs @@ -1,5 +1,3 @@ -use crate::common::BitArray; - use super::BitMatrixCursorTrait; pub struct FastEdgeToEdgeCounter { @@ -7,66 +5,77 @@ pub struct FastEdgeToEdgeCounter { // int stride = 0; // int stepsToBorder = 0; p: u32, // = nullptr; - stride: u32, // = 0; - stepsToBorder: u32, // = 0; - arr: BitArray, + stride: isize, // = 0; + stepsToBorder: i32, // = 0; + //arr: BitArray, + _arr: isize, + under_arry: Vec, } impl FastEdgeToEdgeCounter { pub fn new(cur: &T) -> Self { - let stride = cur.d().y as u32 * cur.img().width() as u32 + cur.d().x as u32; - let p = /*cur.img().getRow(cur.p().y).begin()*/ 0 + cur.p().x as u32; + let stride = cur.d().y as isize * cur.img().width() as isize + cur.d().x as isize; + let p = ((cur.p().y as isize * cur.img().width() as isize).abs() as i32 + cur.p().x as i32) as u32; // P IS SET WRONG IN REVERSE let maxStepsX = if cur.d().x != 0.0 { - (if cur.d().x > 0.0 { + if cur.d().x > 0.0 { cur.img().width() - 1 - cur.p().x as u32 } else { cur.p().x as u32 - }) + } } else { u32::MAX }; let maxStepsY = if cur.d().y != 0.0 { - (if cur.d().y > 0.0 { + if cur.d().y > 0.0 { cur.img().height() - 1 - cur.p().y as u32 } else { cur.p().y as u32 - }) + } } else { u32::MAX }; - let stepsToBorder = std::cmp::min(maxStepsX, maxStepsY); + let stepsToBorder = std::cmp::min(maxStepsX, maxStepsY) as i32; Self { p, stride, stepsToBorder, - arr: cur.img().getRow(cur.p().y as u32), + _arr: cur.p().y as isize * stride as isize, //cur.img().getRow(cur.p().y as u32), + under_arry: cur.img().into(), } } pub fn stepToNextEdge(&mut self, range: u32) -> u32 { - let maxSteps = std::cmp::min(self.stepsToBorder, range); + let maxSteps = std::cmp::min(self.stepsToBorder, range as i32); let mut steps = 0; loop { steps += 1; - if (steps > maxSteps) { - if (maxSteps == self.stepsToBorder) { - break; + if steps > maxSteps { + if maxSteps == self.stepsToBorder { + break false; } else { return 0; } } - if !(self.arr.get((self.p + steps * self.stride) as usize) - == self.arr.get((self.p + 0) as usize)) - { - break; - } - } // while (p[steps * stride] == p[0]); - self.p += steps * self.stride; + let idx_pt = self.get_array_check_index(steps); + + if !(self.under_arry[idx_pt] + == self.under_arry[self.p as usize]) + { + break true; + } + }; // while (p[steps * stride] == p[0]); + + self.p = (self.p as isize + (steps as isize * self.stride)).abs() as u32; self.stepsToBorder -= steps; - return steps; + return steps as u32; } -} + + #[inline(always)] + fn get_array_check_index(&self, steps: i32) -> usize { + (self.p as isize + (steps as isize * self.stride)) as usize + } +} \ No newline at end of file diff --git a/src/common/cpp_essentials/pattern.rs b/src/common/cpp_essentials/pattern.rs index 6cb699e..583b30c 100644 --- a/src/common/cpp_essentials/pattern.rs +++ b/src/common/cpp_essentials/pattern.rs @@ -60,17 +60,22 @@ impl From> for PatternRow { } } -impl<'a> Iterator for PatternView<'_> { +pub struct PatternViewIterator<'a> { + pattern_view: &'a PatternView<'a>, + current_position: usize, +} + +impl<'a> Iterator for PatternViewIterator<'_> { type Item = PatternType; fn next(&mut self) -> Option { - if self.current + 1 > self.count { + if self.current_position + 1 > self.pattern_view.count { return None; } - self.current += 1; + self.current_position += 1; - Some(*self.data.0.get(self.current + self.start)?) + Some(*self.pattern_view.data.0.get(self.current_position - 1 + self.pattern_view.start + self.pattern_view.current)?) } } @@ -82,7 +87,7 @@ pub struct PatternView<'a> { current: usize, } -impl<'a> PatternView<'_> { +impl<'a> PatternView<'a> { // A PatternRow always starts with the width of whitespace in front of the first black bar. // The first element of the PatternView is the first bar. pub fn new(bars: &'a PatternRow) -> PatternView<'a> { @@ -126,6 +131,10 @@ impl<'a> PatternView<'_> { // int sum(int n = 0) const { return std::accumulate(_data, _data + (n == 0 ? _size : n), 0); } pub fn sum(&self, n: Option) -> PatternType { + if self.count == self.data.len() { + return self.data.0.iter().sum::(); + } + let n = n.unwrap_or(self.count); self.data @@ -137,6 +146,10 @@ impl<'a> PatternView<'_> { .sum::() } + pub fn iter(&'a self) -> PatternViewIterator<'a> { + PatternViewIterator { pattern_view: self, current_position: 0 } + } + pub fn size(&self) -> usize { self.count } @@ -149,8 +162,7 @@ impl<'a> PatternView<'_> { self.data .0 .iter() - .skip(self.start) - .take(self.current) + .take(self.start + self.current) .copied() .sum::() /*return std::accumulate(_base, _data, 0);*/ } @@ -170,8 +182,8 @@ impl<'a> PatternView<'_> { } pub fn isValidWithN(&self, n: usize) -> bool { !self.data.0.is_empty() - && self.start <= self.current - && self.start + n <= (self.start + self.count) + && self.start <= self.current + self.start + && self.current + n <= (self.data.0.len()) /*return _data && _data >= _base && _data + n <= _end;*/ } pub fn isValid(&self) -> bool { @@ -201,7 +213,7 @@ impl<'a> PatternView<'_> { // return (acceptIfAtLastBar && isAtLastBar()) || _data[_size] >= sum() * scale; // } - pub fn subView(&'a self, offset: usize, size: Option) -> PatternView<'a> { + pub fn subView(&self, offset: usize, size: Option) -> PatternView<'a> { let mut size = size.unwrap_or(0); if size == 0 { size = self.count - offset; @@ -252,7 +264,7 @@ impl<'a> PatternView<'_> { } pub fn extend(&mut self) { - self.count = std::cmp::max(0, self.count - self.start) + self.count = std::cmp::max(0, self.data.len() - (self.current + self.start)) } fn try_get_index(&self, index: isize) -> Option { @@ -275,6 +287,10 @@ impl<'a> std::ops::Index for PatternView<'_> { type Output = PatternType; fn index(&self, index: isize) -> &Self::Output { + if self.count == self.data.len() { + return &self.data[index.abs() as usize] + } + if index > self.data.0.len() as isize { panic!("array index out of bounds") } @@ -294,6 +310,10 @@ impl<'a> std::ops::Index for PatternView<'_> { type Output = PatternType; fn index(&self, index: usize) -> &Self::Output { + if self.count == self.data.len() { + return &self.data[index] + } + if index > self.data.0.len() { panic!("array index out of bounds") } @@ -442,7 +462,7 @@ pub fn IsPattern( return 0.0; } - if (module_size_ref == 0.0) { + if module_size_ref == 0.0 { module_size_ref = module_size; } @@ -485,7 +505,7 @@ pub fn IsRightGuard( } pub fn FindLeftGuardBy<'a, const LEN: usize, Pred: Fn(&PatternView, Option) -> bool>( - view: &'a PatternView, + view: PatternView<'a>, minSize: usize, isGuard: Pred, ) -> Result> { @@ -517,7 +537,7 @@ pub fn FindLeftGuardBy<'a, const LEN: usize, Pred: Fn(&PatternView, Option) } pub fn FindLeftGuard<'a, const LEN: usize, const SUM: usize, const IS_SPARCE: bool>( - view: &'a PatternView, + view: PatternView<'a>, minSize: usize, pattern: &FixedPattern, minQuietZone: f32, @@ -526,8 +546,8 @@ pub fn FindLeftGuard<'a, const LEN: usize, const SUM: usize, const IS_SPARCE: bo // perform a fast plausability test for 1:1:3:1:1 pattern // dbg!(window[2], 2 as PatternType * std::cmp::max(window[0], window[4])); // dbg!(window[2] < std::cmp::max(window[1], window[3])); - if (window[2] < 2 as PatternType * std::cmp::max(window[0], window[4]) - || window[2] < std::cmp::max(window[1], window[3])) + if window[2] < 2 as PatternType * std::cmp::max(window[0], window[4]) + || window[2] < std::cmp::max(window[1], window[3]) { return false; } diff --git a/src/common/default_grid_sampler.rs b/src/common/default_grid_sampler.rs index 556642f..d9bc061 100644 --- a/src/common/default_grid_sampler.rs +++ b/src/common/default_grid_sampler.rs @@ -36,7 +36,7 @@ impl GridSampler for DefaultGridSampler { dimensionX: u32, dimensionY: u32, controls: &[SamplerControl], - ) -> Result { + ) -> Result<(BitMatrix,[Point;4])> { if dimensionX <= 0 || dimensionY <= 0 { return Err(Exceptions::NOT_FOUND); } @@ -89,11 +89,11 @@ impl GridSampler for DefaultGridSampler { Point::default() }; - let _tl = projectCorner(point(0.0, 0.0)); - let _tr = projectCorner(Point::from((dimensionX, 0))); - let _bl = projectCorner(Point::from((dimensionX, dimensionY))); - let _br = projectCorner(Point::from((0, dimensionX))); + let tl = projectCorner(point(0.0, 0.0)); + let tr = projectCorner(Point::from((dimensionX, 0))); + let bl = projectCorner(Point::from((dimensionX, dimensionY))); + let br = projectCorner(Point::from((0, dimensionX))); - Ok(bits) + Ok((bits, [tl,tr,bl,br])) } } diff --git a/src/common/grid_sampler.rs b/src/common/grid_sampler.rs index d368f47..2d69b24 100644 --- a/src/common/grid_sampler.rs +++ b/src/common/grid_sampler.rs @@ -95,7 +95,7 @@ pub trait GridSampler { dimensionY: u32, dst: Quadrilateral, src: Quadrilateral, - ) -> Result { + ) -> Result<(BitMatrix,[Point;4])> { let transform = PerspectiveTransform::quadrilateralToQuadrilateral(dst, src)?; self.sample_grid( @@ -112,7 +112,7 @@ pub trait GridSampler { dimensionX: u32, dimensionY: u32, controls: &[SamplerControl], - ) -> Result { + ) -> Result<(BitMatrix,[Point;4])> { if dimensionX == 0 || dimensionY == 0 { return Err(Exceptions::NOT_FOUND); } @@ -172,7 +172,7 @@ pub trait GridSampler { } // dbg!(bits.to_string()); - Ok(bits) + Ok((bits, [Point::default(), Point::default(), Point::default(), Point::default()])) } /** diff --git a/src/qrcode/cpp_port/detector.rs b/src/qrcode/cpp_port/detector.rs index 718791b..4324283 100644 --- a/src/qrcode/cpp_port/detector.rs +++ b/src/qrcode/cpp_port/detector.rs @@ -37,6 +37,8 @@ pub type FinderPatternSets = Vec; const PATTERN: FixedPattern<5, 7, false> = FixedPattern::new([1, 1, 3, 1, 1]); +/// Locate the finder patterns for the symbol. +/// This function can panic pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns { const MIN_SKIP: u32 = 3; // 1 pixel/module times 3 modules/center const MAX_MODULES_FAST: u32 = 20 * 4 + 17; // support up to version 20 for mobile clients @@ -61,15 +63,12 @@ pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns let mut next: PatternView = PatternView::new(&row); while { - if let Ok(next) = FindLeftGuard(&next, 0, &PATTERN, 0.5) { + if let Ok(up_next) = FindLeftGuard(next, 0, &PATTERN, 0.5) { + next = up_next; next.isValid() } else { false } - // let Ok(next) = FindLeftGuard(&next, 0, &PATTERN, 0.5) else { - // break; - // }; - // next.isValid() } { let p = point( next.pixelsInFront() as f32 @@ -90,7 +89,7 @@ pub fn FindFinderPatterns(image: &BitMatrix, tryHarder: bool) -> FinderPatterns image, &PATTERN.into(), p, - next.sum::() as i32 * 3, + next.iter().sum::() as i32 * 3, ); // 3 for very skewed samples // Reduce(next) * 3); // 3 for very skewed samples if (pattern.is_some()) { @@ -336,12 +335,13 @@ pub fn TraceLine(image: &BitMatrix, p: Point, d: Point, edge: i32) -> impl Regre for dir in [Direction::Left, Direction::Right] { // for (auto dir : {Direction::LEFT, Direction::RIGHT}) { let mut c = EdgeTracer::new(image, curI.p, curI.direction(dir)); - let stepCount = (Point::maxAbsComponent(cur.p - p)) as i32; + let mut stepCount = (Point::maxAbsComponent(cur.p - p)) as i32; loop { line.add(Point::centered(c.p)) .expect("could not add point on line"); - if !(--stepCount > 0 && c.stepAlongEdge(dir, Some(true))) { +stepCount -= 1; + if !(stepCount > 0 && c.stepAlongEdge(dir, Some(true))) { break; } } //while (--stepCount > 0 && c.stepAlongEdge(dir, true)); @@ -731,9 +731,10 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result Result Result