From a6b9c3efc00b5b70c8b3d6c225896927a91ac168 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Tue, 20 Dec 2022 17:43:22 -0600 Subject: [PATCH] likely fix to row indicator problem now a trait --- src/pdf417/decoder/detection_result.rs | 23 +- src/pdf417/decoder/detection_result_column.rs | 22 +- .../detection_result_row_indicator_column.rs | 281 +++++++++--------- src/pdf417/decoder/mod.rs | 2 +- 4 files changed, 179 insertions(+), 149 deletions(-) diff --git a/src/pdf417/decoder/detection_result.rs b/src/pdf417/decoder/detection_result.rs index bbef729..800724c 100644 --- a/src/pdf417/decoder/detection_result.rs +++ b/src/pdf417/decoder/detection_result.rs @@ -18,7 +18,10 @@ use std::fmt::Display; use crate::pdf417::pdf_417_common; -use super::{BarcodeMetadata, BoundingBox, Codeword, DetectionRXingResultColumn}; +use super::{ + BarcodeMetadata, BoundingBox, Codeword, DetectionRXingResultColumn, + DetectionRXingResultRowIndicatorColumn, +}; const ADJUST_ROW_NUMBER_SKIP: u32 = 2; @@ -50,10 +53,9 @@ impl<'a> DetectionRXingResult<'_> { } pub fn getDetectionRXingResultColumns(&mut self) -> &Vec> { - self.adjustIndicatorColumnRowNumbers(&self.detectionRXingResultColumns[0]); - self.adjustIndicatorColumnRowNumbers( - &self.detectionRXingResultColumns[self.barcodeColumnCount + 1], - ); + self.adjustIndicatorColumnRowNumbers(0); + let pos = self.barcodeColumnCount + 1; + self.adjustIndicatorColumnRowNumbers(pos); let mut unadjustedCodewordCount = pdf_417_common::MAX_CODEWORDS_IN_BARCODE; let mut previousUnadjustedCount; loop { @@ -67,15 +69,18 @@ impl<'a> DetectionRXingResult<'_> { } fn adjustIndicatorColumnRowNumbers( - &self, - detectionRXingResultColumn: &Option, + &mut self, + pos: usize, + // detectionRXingResultColumn: &mut Option, ) { - if let Some(col) = detectionRXingResultColumn { + if self.detectionRXingResultColumns[pos].is_some() { // if (detectionRXingResultColumn != null) { // ((DetectionRXingResultRowIndicatorColumn) detectionRXingResultColumn) // .adjustCompleteIndicatorColumnRowNumbers(barcodeMetadata); // } - col.as_row_indicator() + self.detectionRXingResultColumns[pos] + .as_mut() + .unwrap() .adjustCompleteIndicatorColumnRowNumbers(&self.barcodeMetadata); } } diff --git a/src/pdf417/decoder/detection_result_column.rs b/src/pdf417/decoder/detection_result_column.rs index 5aa71bf..56057bb 100644 --- a/src/pdf417/decoder/detection_result_column.rs +++ b/src/pdf417/decoder/detection_result_column.rs @@ -27,6 +27,7 @@ const MAX_NEARBY_DISTANCE: u32 = 5; pub struct DetectionRXingResultColumn<'a> { boundingBox: BoundingBox<'a>, codewords: Vec>, + pub(super) isLeft: Option, } impl<'a> DetectionRXingResultColumn<'_> { @@ -34,11 +35,23 @@ impl<'a> DetectionRXingResultColumn<'_> { DetectionRXingResultColumn { boundingBox: BoundingBox::from_other(boundingBox), codewords: vec![None; (boundingBox.getMaxY() - boundingBox.getMinY() + 1) as usize], + isLeft: None, } // this.boundingBox = new BoundingBox(boundingBox); // codewords = new Codeword[boundingBox.getMaxY() - boundingBox.getMinY() + 1]; } + pub fn new_with_is_left( + boundingBox: &'a BoundingBox, + isLeft: bool, + ) -> DetectionRXingResultColumn<'a> { + DetectionRXingResultColumn { + boundingBox: BoundingBox::from_other(boundingBox), + codewords: vec![None; (boundingBox.getMaxY() - boundingBox.getMinY() + 1) as usize], + isLeft: Some(isLeft), + } + } + pub fn getCodewordNearby(&self, imageRow: u32) -> &Option { let mut codeword = self.getCodeword(imageRow); if codeword.is_some() { @@ -87,13 +100,16 @@ impl<'a> DetectionRXingResultColumn<'_> { pub(super) fn getCodewordsMut(&mut self) -> &mut [Option] { &mut self.codewords } - pub fn as_row_indicator(&self) -> DetectionRXingResultRowIndicatorColumn { - DetectionRXingResultRowIndicatorColumn::new(&self.boundingBox, false) - } + // pub fn as_row_indicator(&self) -> DetectionRXingResultRowIndicatorColumn { + // DetectionRXingResultRowIndicatorColumn::new(&self.boundingBox, false) + // } } impl Display for DetectionRXingResultColumn<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.isLeft.is_some() { + write!(f, "IsLeft: {} \n", self.isLeft.as_ref().unwrap()); + } todo!() } diff --git a/src/pdf417/decoder/detection_result_row_indicator_column.rs b/src/pdf417/decoder/detection_result_row_indicator_column.rs index 93437dd..dfe09f9 100644 --- a/src/pdf417/decoder/detection_result_row_indicator_column.rs +++ b/src/pdf417/decoder/detection_result_row_indicator_column.rs @@ -23,48 +23,42 @@ use super::{BarcodeMetadata, BarcodeValue, BoundingBox, Codeword, DetectionRXing /** * @author Guenther Grau */ -pub struct DetectionRXingResultRowIndicatorColumn<'a>(DetectionRXingResultColumn<'a>, bool); -impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { +pub trait DetectionRXingResultRowIndicatorColumn { + // TODO implement properly + // TODO maybe we should add missing codewords to store the correct row number to make + // finding row numbers for other columns easier + // use row height count to make detection of invalid row numbers more reliable + fn adjustCompleteIndicatorColumnRowNumbers(&mut self, barcodeMetadata: &BarcodeMetadata); + fn getRowHeights(&mut self) -> Option>; + fn getBarcodeMetadata(&mut self) -> Option; + fn isLeft(&self) -> bool; +} + +impl<'a> DetectionRXingResultRowIndicatorColumn for DetectionRXingResultColumn<'_> { // private final boolean isLeft; - pub fn new( - boundingBox: &'a BoundingBox, - isLeft: bool, - ) -> DetectionRXingResultRowIndicatorColumn<'a> { - DetectionRXingResultRowIndicatorColumn(DetectionRXingResultColumn::new(boundingBox), isLeft) - } - - fn setRowNumbers(&mut self) { - for codeword_opt in self.0.getCodewordsMut() { - // for (Codeword codeword : getCodewords()) { - if let Some(codeword) = codeword_opt { - // if (codeword != null) { - codeword.setRowNumberAsRowIndicatorColumn(); - } - } - } - // TODO implement properly // TODO maybe we should add missing codewords to store the correct row number to make // finding row numbers for other columns easier // use row height count to make detection of invalid row numbers more reliable - pub fn adjustCompleteIndicatorColumnRowNumbers(&mut self, barcodeMetadata: &BarcodeMetadata) { + fn adjustCompleteIndicatorColumnRowNumbers(&mut self, barcodeMetadata: &BarcodeMetadata) { // let codewords = self.0.getCodewordsMut(); - self.setRowNumbers(); - Self::removeIncorrectCodewords(self.0.getCodewordsMut(), barcodeMetadata, self.1); - let boundingBox = self.0.getBoundingBox(); - let top = if self.1 { + setRowNumbers(self.getCodewordsMut()); + let isLeft = self.isLeft.unwrap(); + removeIncorrectCodewords(self.getCodewordsMut(), barcodeMetadata, isLeft); + let boundingBox = self.getBoundingBox(); + let top = if self.isLeft() { boundingBox.getTopLeft() } else { boundingBox.getTopRight() }; - let bottom = if self.1 { + let bottom = if self.isLeft() { boundingBox.getBottomLeft() } else { boundingBox.getBottomRight() }; - let firstRow = self.0.imageRowToCodewordIndex(top.getY() as u32); - let lastRow = self.0.imageRowToCodewordIndex(bottom.getY() as u32); + let firstRow = self.imageRowToCodewordIndex(top.getY() as u32); + let lastRow = self.imageRowToCodewordIndex(bottom.getY() as u32); // We need to be careful using the average row height. Barcode could be skewed so that we have smaller and // taller rows //float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount(); @@ -73,7 +67,7 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { let mut currentRowHeight = 0; for codewordsRow in firstRow..lastRow { // for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { - if let Some(codeword) = self.0.getCodewordsMut()[codewordsRow] { + if let Some(codeword) = self.getCodewordsMut()[codewordsRow] { // if (codewords[codewordsRow] == null) { // continue; // } @@ -93,7 +87,7 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { || codeword.getRowNumber() >= barcodeMetadata.getRowCount() as i32 || rowDifference > codewordsRow as i32 { - self.0.getCodewordsMut()[codewordsRow] = None; + self.getCodewordsMut()[codewordsRow] = None; } else { let checkedRows; if maxRowHeight > 2 { @@ -108,12 +102,12 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { // there must be (height * rowDifference) number of codewords missing. For now we assume height = 1. // This should hopefully get rid of most problems already. closePreviousCodewordFound = - self.0.getCodewords()[codewordsRow as usize - i as usize].is_some(); + self.getCodewords()[codewordsRow as usize - i as usize].is_some(); i += 1; } if closePreviousCodewordFound { - self.0.getCodewordsMut()[codewordsRow] = None; + self.getCodewordsMut()[codewordsRow] = None; } else { barcodeRow = codeword.getRowNumber(); currentRowHeight = 1; @@ -126,11 +120,11 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { //return (int) (averageRowHeight + 0.5); } - pub fn getRowHeights(&mut self) -> Option> { + fn getRowHeights(&mut self) -> Option> { if let Some(barcodeMetadata) = self.getBarcodeMetadata() { - self.adjustIncompleteIndicatorColumnRowNumbers(&barcodeMetadata); + adjustIncompleteIndicatorColumnRowNumbers(self, &barcodeMetadata); let mut result = vec![0; barcodeMetadata.getRowCount() as usize]; - for codeword_opt in self.0.getCodewords() { + for codeword_opt in self.getCodewords() { // for (Codeword codeword : getCodewords()) { if let Some(codeword) = codeword_opt { let rowNumber = codeword.getRowNumber(); @@ -151,59 +145,9 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { } } - // TODO maybe we should add missing codewords to store the correct row number to make - // finding row numbers for other columns easier - // use row height count to make detection of invalid row numbers more reliable - fn adjustIncompleteIndicatorColumnRowNumbers(&mut self, barcodeMetadata: &BarcodeMetadata) { - let boundingBox = self.0.getBoundingBox(); - let top = if self.1 { - boundingBox.getTopLeft() - } else { - boundingBox.getTopRight() - }; - let bottom = if self.1 { - boundingBox.getBottomLeft() - } else { - boundingBox.getBottomRight() - }; - let firstRow = self.0.imageRowToCodewordIndex(top.getY() as u32); - let lastRow = self.0.imageRowToCodewordIndex(bottom.getY() as u32); - //float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount(); - let codewords = self.0.getCodewordsMut(); - let mut barcodeRow = -1; - let mut maxRowHeight = 1; - let mut currentRowHeight = 0; - for codewordsRow in firstRow..lastRow { - // for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { - - if let Some(codeword) = &mut codewords[codewordsRow] { - codeword.setRowNumberAsRowIndicatorColumn(); - - let rowDifference = codeword.getRowNumber() - barcodeRow; - - // TODO improve handling with case where first row indicator doesn't start with 0 - - if rowDifference == 0 { - currentRowHeight += 1; - } else if rowDifference == 1 { - maxRowHeight = maxRowHeight.max(currentRowHeight); - currentRowHeight = 1; - barcodeRow = codeword.getRowNumber(); - } else if codeword.getRowNumber() >= barcodeMetadata.getRowCount() as i32 { - codewords[codewordsRow] = None; - } else { - barcodeRow = codeword.getRowNumber(); - currentRowHeight = 1; - } - } else { - continue; - } - } - //return (int) (averageRowHeight + 0.5); - } - - pub fn getBarcodeMetadata(&mut self) -> Option { - let codewords = self.0.getCodewordsMut(); + fn getBarcodeMetadata(&mut self) -> Option { + let isLeft = self.isLeft.unwrap(); + let codewords = self.getCodewordsMut(); let mut barcodeColumnCount = BarcodeValue::new(); let mut barcodeRowCountUpperPart = BarcodeValue::new(); let mut barcodeRowCountLowerPart = BarcodeValue::new(); @@ -214,7 +158,7 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { codeword.setRowNumberAsRowIndicatorColumn(); let rowIndicatorValue = codeword.getValue() % 30; let mut codewordRowNumber = codeword.getRowNumber(); - if !self.1 { + if !isLeft { codewordRowNumber += 2; } match codewordRowNumber % 3 { @@ -249,63 +193,128 @@ impl<'a> DetectionRXingResultRowIndicatorColumn<'_> { barcodeRowCountLowerPart.getValue()[0], barcodeECLevel.getValue()[0], ); - Self::removeIncorrectCodewords(codewords, &barcodeMetadata, self.1); + removeIncorrectCodewords(codewords, &barcodeMetadata, isLeft); Some(barcodeMetadata) } - fn removeIncorrectCodewords( - codewords: &mut [Option], - barcodeMetadata: &BarcodeMetadata, - isLeft: bool, - ) { - // Remove codewords which do not match the metadata - // TODO Maybe we should keep the incorrect codewords for the start and end positions? - for codewordRow in 0..codewords.len() { - // for (int codewordRow = 0; codewordRow < codewords.length; codewordRow++) { - if let Some(codeword) = codewords[codewordRow] { - let rowIndicatorValue = codeword.getValue() % 30; - let mut codewordRowNumber = codeword.getRowNumber(); - if codewordRowNumber > barcodeMetadata.getRowCount() as i32 { - codewords[codewordRow] = None; - continue; - } - if !isLeft { - codewordRowNumber += 2; - } - match codewordRowNumber % 3 { - 0 => { - if rowIndicatorValue * 3 + 1 != barcodeMetadata.getRowCountUpperPart() { - codewords[codewordRow] = None; - } - } - 1 => { - if rowIndicatorValue / 3 != barcodeMetadata.getErrorCorrectionLevel() - || rowIndicatorValue % 3 != barcodeMetadata.getRowCountLowerPart() - { - codewords[codewordRow] = None; - } - } - 2 => { - if rowIndicatorValue + 1 != barcodeMetadata.getColumnCount() { - codewords[codewordRow] = None; - } - } - _ => {} - } - } else { - continue; - } + fn isLeft(&self) -> bool { + self.isLeft.unwrap() + } +} + +// impl Display for DetectionRXingResultRowIndicatorColumn { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// write!(f, "IsLeft: {} \n {}", self.1, self.0) +// } +// } + +fn setRowNumbers(code_words: &mut [Option]) { + for codeword_opt in code_words { + //self.0.getCodewordsMut() { + // for (Codeword codeword : getCodewords()) { + if let Some(codeword) = codeword_opt { + // if (codeword != null) { + codeword.setRowNumberAsRowIndicatorColumn(); } } +} - pub fn isLeft(&self) -> bool { - self.1 +fn removeIncorrectCodewords( + codewords: &mut [Option], + barcodeMetadata: &BarcodeMetadata, + isLeft: bool, +) { + // Remove codewords which do not match the metadata + // TODO Maybe we should keep the incorrect codewords for the start and end positions? + for codewordRow in 0..codewords.len() { + // for (int codewordRow = 0; codewordRow < codewords.length; codewordRow++) { + if let Some(codeword) = codewords[codewordRow] { + let rowIndicatorValue = codeword.getValue() % 30; + let mut codewordRowNumber = codeword.getRowNumber(); + if codewordRowNumber > barcodeMetadata.getRowCount() as i32 { + codewords[codewordRow] = None; + continue; + } + if !isLeft { + codewordRowNumber += 2; + } + match codewordRowNumber % 3 { + 0 => { + if rowIndicatorValue * 3 + 1 != barcodeMetadata.getRowCountUpperPart() { + codewords[codewordRow] = None; + } + } + 1 => { + if rowIndicatorValue / 3 != barcodeMetadata.getErrorCorrectionLevel() + || rowIndicatorValue % 3 != barcodeMetadata.getRowCountLowerPart() + { + codewords[codewordRow] = None; + } + } + 2 => { + if rowIndicatorValue + 1 != barcodeMetadata.getColumnCount() { + codewords[codewordRow] = None; + } + } + _ => {} + } + } else { + continue; + } } } -impl Display for DetectionRXingResultRowIndicatorColumn<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "IsLeft: {} \n {}", self.1, self.0) +// TODO maybe we should add missing codewords to store the correct row number to make +// finding row numbers for other columns easier +// use row height count to make detection of invalid row numbers more reliable +fn adjustIncompleteIndicatorColumnRowNumbers( + col: &mut DetectionRXingResultColumn, + barcodeMetadata: &BarcodeMetadata, +) { + let boundingBox = col.getBoundingBox(); + let top = if col.isLeft() { + boundingBox.getTopLeft() + } else { + boundingBox.getTopRight() + }; + let bottom = if col.isLeft() { + boundingBox.getBottomLeft() + } else { + boundingBox.getBottomRight() + }; + let firstRow = col.imageRowToCodewordIndex(top.getY() as u32); + let lastRow = col.imageRowToCodewordIndex(bottom.getY() as u32); + //float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.getRowCount(); + let codewords = col.getCodewordsMut(); + let mut barcodeRow = -1; + let mut maxRowHeight = 1; + let mut currentRowHeight = 0; + for codewordsRow in firstRow..lastRow { + // for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { + + if let Some(codeword) = &mut codewords[codewordsRow] { + codeword.setRowNumberAsRowIndicatorColumn(); + + let rowDifference = codeword.getRowNumber() - barcodeRow; + + // TODO improve handling with case where first row indicator doesn't start with 0 + + if rowDifference == 0 { + currentRowHeight += 1; + } else if rowDifference == 1 { + maxRowHeight = maxRowHeight.max(currentRowHeight); + currentRowHeight = 1; + barcodeRow = codeword.getRowNumber(); + } else if codeword.getRowNumber() >= barcodeMetadata.getRowCount() as i32 { + codewords[codewordsRow] = None; + } else { + barcodeRow = codeword.getRowNumber(); + currentRowHeight = 1; + } + } else { + continue; + } } + //return (int) (averageRowHeight + 0.5); } diff --git a/src/pdf417/decoder/mod.rs b/src/pdf417/decoder/mod.rs index 8292a2d..a7b1595 100644 --- a/src/pdf417/decoder/mod.rs +++ b/src/pdf417/decoder/mod.rs @@ -23,4 +23,4 @@ pub use detection_result_row_indicator_column::*; mod detection_result; pub use detection_result::*; -// pub mod pdf_417_scanning_decoder; \ No newline at end of file +// pub mod pdf_417_scanning_decoder;