mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
wip: incomplete port checking
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{BitArray, BitMatrix, Result},
|
common::{BitArray, BitMatrix, LineOrientation, Result},
|
||||||
LuminanceSource,
|
LuminanceSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,6 +66,9 @@ pub trait Binarizer {
|
|||||||
*/
|
*/
|
||||||
fn get_black_matrix(&self) -> Result<&BitMatrix>;
|
fn get_black_matrix(&self) -> Result<&BitMatrix>;
|
||||||
|
|
||||||
|
/// Get a row or column of the image
|
||||||
|
fn get_black_line(&self, l: usize, lt: LineOrientation) -> Result<Cow<BitArray>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
* Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||||
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
* state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use std::{borrow::Cow, fmt};
|
use std::{borrow::Cow, fmt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{BitArray, BitMatrix, Result},
|
common::{BitArray, BitMatrix, LineOrientation, Result},
|
||||||
Binarizer, LuminanceSource,
|
Binarizer, LuminanceSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +72,11 @@ impl<B: Binarizer> BinaryBitmap<B> {
|
|||||||
self.binarizer.get_black_row(y)
|
self.binarizer.get_black_row(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a row or column of the image
|
||||||
|
pub fn get_black_line(&self, l: usize, lt: LineOrientation) -> Result<Cow<BitArray>> {
|
||||||
|
self.binarizer.get_black_line(l, lt)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
* Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
||||||
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
* and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
// 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;
|
||||||
@@ -420,6 +421,19 @@ 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&BitArray> for Vec<bool> {
|
||||||
|
fn from(value: &BitArray) -> Self {
|
||||||
let mut array = vec![false; value.size];
|
let mut array = vec![false; value.size];
|
||||||
|
|
||||||
for (pixel, element) in array.iter_mut().enumerate().take(value.size) {
|
for (pixel, element) in array.iter_mut().enumerate().take(value.size) {
|
||||||
@@ -429,3 +443,11 @@ impl From<BitArray> for Vec<bool> {
|
|||||||
array
|
array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for BitArray {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.get(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::common::cpp_essentials::PatternRow;
|
||||||
use crate::common::BitMatrix;
|
use crate::common::BitMatrix;
|
||||||
use crate::common::Result;
|
use crate::common::Result;
|
||||||
use crate::point_f;
|
use crate::point_f;
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ impl PatternRow {
|
|||||||
pub fn sum(&self) -> PatternType {
|
pub fn sum(&self) -> PatternType {
|
||||||
self.0.iter().sum()
|
self.0.iter().sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rev(&mut self) {
|
||||||
|
self.0.reverse()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for PatternRow {
|
impl IntoIterator for PatternRow {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ pub struct GlobalHistogramBinarizer<LS: LuminanceSource> {
|
|||||||
source: LS,
|
source: LS,
|
||||||
black_matrix: OnceCell<BitMatrix>,
|
black_matrix: OnceCell<BitMatrix>,
|
||||||
black_row_cache: Vec<OnceCell<BitArray>>,
|
black_row_cache: Vec<OnceCell<BitArray>>,
|
||||||
|
black_column_cache: Vec<OnceCell<BitArray>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
||||||
@@ -106,6 +107,10 @@ impl<LS: LuminanceSource> Binarizer for GlobalHistogramBinarizer<LS> {
|
|||||||
Ok(Cow::Borrowed(row))
|
Ok(Cow::Borrowed(row))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_black_line(&self, l: usize, lt: super::LineOrientation) -> Result<Cow<BitArray>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
|
||||||
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
fn get_black_matrix(&self) -> Result<&BitMatrix> {
|
||||||
let matrix = self
|
let matrix = self
|
||||||
@@ -137,6 +142,7 @@ impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
|
|||||||
height: source.get_height(),
|
height: source.get_height(),
|
||||||
black_matrix: OnceCell::new(),
|
black_matrix: OnceCell::new(),
|
||||||
black_row_cache: vec![OnceCell::default(); source.get_height()],
|
black_row_cache: vec![OnceCell::default(); source.get_height()],
|
||||||
|
black_column_cache: vec![OnceCell::default(); source.get_width()],
|
||||||
source,
|
source,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ impl<LS: LuminanceSource> Binarizer for HybridBinarizer<LS> {
|
|||||||
self.ghb.get_black_row(y)
|
self.ghb.get_black_row(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_black_line(&self, l: usize, lt: super::LineOrientation) -> Result<Cow<BitArray>> {
|
||||||
|
self.ghb.get_black_line(l, lt)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the final BitMatrix once for all requests. This could be called once from the
|
* Calculates the final BitMatrix once for all requests. This could be called once from the
|
||||||
* constructor instead, but there are some advantages to doing it lazily, such as making
|
* constructor instead, but there are some advantages to doing it lazily, such as making
|
||||||
|
|||||||
5
src/common/line_orientation.rs
Normal file
5
src/common/line_orientation.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum LineOrientation {
|
||||||
|
Row,
|
||||||
|
Column,
|
||||||
|
}
|
||||||
@@ -114,6 +114,9 @@ pub use quad::*;
|
|||||||
|
|
||||||
pub mod cpp_essentials;
|
pub mod cpp_essentials;
|
||||||
|
|
||||||
|
mod line_orientation;
|
||||||
|
pub use line_orientation::LineOrientation;
|
||||||
|
|
||||||
#[cfg(feature = "otsu_level")]
|
#[cfg(feature = "otsu_level")]
|
||||||
mod otsu_level_binarizer;
|
mod otsu_level_binarizer;
|
||||||
#[cfg(feature = "otsu_level")]
|
#[cfg(feature = "otsu_level")]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{point_f, Point};
|
use crate::{point_f, Exceptions, Point};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Quadrilateral(pub [Point; 4]);
|
pub struct Quadrilateral(pub [Point; 4]);
|
||||||
@@ -272,3 +272,19 @@ impl From<[Point; 4]> for Quadrilateral {
|
|||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&Vec<Point>> for Quadrilateral {
|
||||||
|
type Error = Exceptions;
|
||||||
|
|
||||||
|
fn try_from(value: &Vec<Point>) -> Result<Self, Self::Error> {
|
||||||
|
if value.len() == 4 {
|
||||||
|
Ok(
|
||||||
|
Self(
|
||||||
|
[value[0], value[1], value[2], value[3]]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
Err(Exceptions::INDEX_OUT_OF_BOUNDS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,12 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::cpp_essentials::{
|
common::{
|
||||||
|
cpp_essentials::{
|
||||||
FindLeftGuardBy, FixedPattern, IsRightGuard, PatternView, ToInt, ToIntPos,
|
FindLeftGuardBy, FixedPattern, IsRightGuard, PatternView, ToInt, ToIntPos,
|
||||||
},
|
},
|
||||||
|
BitArray,
|
||||||
|
},
|
||||||
point, point_i, BarcodeFormat, DecodeHintValue, DecodingHintDictionary, Exceptions, PointI,
|
point, point_i, BarcodeFormat, DecodeHintValue, DecodingHintDictionary, Exceptions, PointI,
|
||||||
RXingResult,
|
RXingResult,
|
||||||
};
|
};
|
||||||
@@ -251,13 +254,20 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
|
|||||||
next.skipSymbol();
|
next.skipSymbol();
|
||||||
|
|
||||||
// Read the data bits
|
// Read the data bits
|
||||||
let mut dataBits: Vec<u8> = Vec::default();
|
let mut dataBits = BitArray::default();
|
||||||
while (next.isValidWithN(1) && dataBits.len() < clock.dataLength() as usize) {
|
while (next.isValidWithN(1) && dataBits.get_size() < clock.dataLength() as usize) {
|
||||||
let modules = (next[0] as f32 / clock.moduleSize() + 0.5) as u32;
|
let modules = (next[0] as f32 / clock.moduleSize() + 0.5) as u32;
|
||||||
// even index means we are at a bar, otherwise at a space
|
// even index means we are at a bar, otherwise at a space
|
||||||
// dataBits.appendBits(if next.index() % 2 == 0 {0xFFFFFFFF} else {0x0}, modules);
|
// dataBits.appendBits(if next.index() % 2 == 0 {0xFFFFFFFF} else {0x0}, modules);
|
||||||
for i in 0..modules {
|
for i in 0..modules {
|
||||||
dataBits.push((if next.index() % 2 == 0 { 0xFF } else { 0x0 } >> (i - 1)) & 1);
|
dataBits.appendBits(
|
||||||
|
if next.index() % 2 == 0 {
|
||||||
|
0xFFFFFFFF
|
||||||
|
} else {
|
||||||
|
0x0
|
||||||
|
},
|
||||||
|
modules as usize,
|
||||||
|
);
|
||||||
// should it be 0xFFFFFFFF
|
// should it be 0xFFFFFFFF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +275,7 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the data track length
|
// Check the data track length
|
||||||
if (dataBits.len() != clock.dataLength() as usize) {
|
if (dataBits.get_size() != clock.dataLength() as usize) {
|
||||||
return Err(Exceptions::NOT_FOUND);
|
return Err(Exceptions::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,31 +287,36 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The following bits are always white (=false), they are separators.
|
// The following bits are always white (=false), they are separators.
|
||||||
if (dataBits[0] != 0
|
if (dataBits[0] != false //0
|
||||||
|| dataBits[8] != 0
|
|| dataBits[8] != false //0
|
||||||
|| (if clock.hasFrameNr {
|
|| (if clock.hasFrameNr {
|
||||||
(dataBits[20] != 0 || dataBits[22] != 0)
|
(dataBits[20] != false/*0*/ || dataBits[22] != false/*0*/)
|
||||||
} else {
|
} else {
|
||||||
dataBits[14] != 0
|
dataBits[14] != false//0
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
return Err(Exceptions::NOT_FOUND);
|
return Err(Exceptions::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the parity bit
|
// Check the parity bit
|
||||||
let signalSum = dataBits.iter().rev().skip(2).sum::<u8>(); //Reduce(dataBits.begin(), dataBits.end() - 2, 0);
|
let db_hld = Into::<Vec<bool>>::into(dataBits); //.iter().rev().skip(2).fold(0, |acc, e| acc + u8::from(*e));
|
||||||
let parityBit = *(dataBits.last().unwrap_or(&0));
|
let signalSum = db_hld
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.skip(2)
|
||||||
|
.fold(0, |acc, e| acc + u8::from(*e)); //dataBits.iter().rev().skip(2).sum::<u8>(); //Reduce(dataBits.begin(), dataBits.end() - 2, 0);
|
||||||
|
let parityBit = u8::from(*(db_hld.last().unwrap_or(&false)));
|
||||||
if (signalSum % 2 != parityBit) {
|
if (signalSum % 2 != parityBit) {
|
||||||
return Err(Exceptions::NOT_FOUND);
|
return Err(Exceptions::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the DX 1 number (product number)
|
// Compute the DX 1 number (product number)
|
||||||
let Some(productNumber) = ToIntPos(&dataBits, 1, 7) else {
|
let Some(productNumber) = ToIntPos(&Into::<Vec<u8>>::into(dataBits), 1, 7) else {
|
||||||
return Err(Exceptions::NOT_FOUND);
|
return Err(Exceptions::NOT_FOUND);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compute the DX 2 number (generation number)
|
// Compute the DX 2 number (generation number)
|
||||||
let Some(generationNumber) = ToIntPos(&dataBits, 9, 4) else {
|
let Some(generationNumber) = ToIntPos(&Into::<Vec<u8>>::into(dataBits), 9, 4) else {
|
||||||
return Err(Exceptions::NOT_FOUND);
|
return Err(Exceptions::NOT_FOUND);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -311,9 +326,9 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
|
|||||||
// txt.reserve(10);
|
// txt.reserve(10);
|
||||||
txt = (productNumber.to_string()) + "-" + (&generationNumber.to_string());
|
txt = (productNumber.to_string()) + "-" + (&generationNumber.to_string());
|
||||||
if (clock.hasFrameNr) {
|
if (clock.hasFrameNr) {
|
||||||
let frameNr = ToIntPos(&dataBits, 13, 6).unwrap_or(0);
|
let frameNr = ToIntPos(&Into::<Vec<u8>>::into(dataBits), 13, 6).unwrap_or(0);
|
||||||
txt += &("/".to_owned() + &(frameNr.to_string()));
|
txt += &("/".to_owned() + &(frameNr.to_string()));
|
||||||
if (dataBits[19] != 0) {
|
if (dataBits[19] != false/*0*/) {
|
||||||
txt += "A";
|
txt += "A";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +347,7 @@ impl<'a> RowReader for DXFilmEdgeReader<'_> {
|
|||||||
|
|
||||||
Ok(RXingResult::new(
|
Ok(RXingResult::new(
|
||||||
&txt,
|
&txt,
|
||||||
dataBits,
|
dataBits.into(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
BarcodeFormat::DXFilmEdge,
|
BarcodeFormat::DXFilmEdge,
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::common::cpp_essentials::{PatternRow, PatternView};
|
use crate::common::cpp_essentials::{GetPatternRow, PatternRow, PatternView};
|
||||||
use crate::Binarizer;
|
use crate::Binarizer;
|
||||||
use crate::{multi::MultipleBarcodeReader, RXingResult, Reader};
|
use crate::{multi::MultipleBarcodeReader, RXingResult, Reader};
|
||||||
use crate::{
|
use crate::{
|
||||||
point, BarcodeFormat, BinaryBitmap, DecodingHintDictionary, Exceptions, PointT, ResultPoint,
|
point, BarcodeFormat, BinaryBitmap, DecodingHintDictionary, Exceptions, PointT, ResultPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::common::Result;
|
use crate::common::{LineOrientation, Quadrilateral, Result};
|
||||||
|
|
||||||
use super::dxfilm_edge_reader::DXFilmEdgeReader;
|
use super::dxfilm_edge_reader::DXFilmEdgeReader;
|
||||||
use super::row_reader::RowReader;
|
use super::row_reader::RowReader;
|
||||||
@@ -50,13 +50,15 @@ impl<'a> ODReader<'_> {
|
|||||||
minLineCount: u32,
|
minLineCount: u32,
|
||||||
returnErrors: bool,
|
returnErrors: bool,
|
||||||
) -> Vec<RXingResult> {
|
) -> Vec<RXingResult> {
|
||||||
let res: Vec<RXingResult> = Vec::new();
|
let mut res: Vec<Option<RXingResult>> = Vec::new();
|
||||||
|
|
||||||
let decodingState = Vec::new();
|
let mut decodingState: Vec<&mut Option<super::row_reader::DecodingState>> = Vec::new();
|
||||||
// std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());
|
// std::vector<std::unique_ptr<RowReader::DecodingState>> decodingState(readers.size());
|
||||||
|
|
||||||
let width: i32 = image.get_width() as i32;
|
let mut minLineCount = minLineCount;
|
||||||
let height: i32 = image.get_height() as i32;
|
|
||||||
|
let mut width: i32 = image.get_width() as i32;
|
||||||
|
let mut height: i32 = image.get_height() as i32;
|
||||||
|
|
||||||
if (rotate) {
|
if (rotate) {
|
||||||
std::mem::swap(&mut width, &mut height);
|
std::mem::swap(&mut width, &mut height);
|
||||||
@@ -73,36 +75,39 @@ impl<'a> ODReader<'_> {
|
|||||||
32
|
32
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
let maxLines: i32 = if tryHarder
|
let maxLines: i32 = if tryHarder {
|
||||||
{height} else // Look at the whole image, not just the center
|
height // Look at the whole image, not just the center
|
||||||
{15}; // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
} else {
|
||||||
|
15 // 15 rows spaced 1/32 apart is roughly the middle half of the image
|
||||||
|
};
|
||||||
|
|
||||||
if (isPure) {
|
if (isPure) {
|
||||||
minLineCount = 1;
|
minLineCount = 1;
|
||||||
}
|
}
|
||||||
let checkRows = Vec::new();
|
let mut checkRows = Vec::new();
|
||||||
|
|
||||||
let bars: PatternRow = PatternRow::new(vec![0; 128]); // e.g. EAN-13 has 59 bars/spaces
|
let mut bars: PatternRow = PatternRow::new(vec![0; 128]); // e.g. EAN-13 has 59 bars/spaces
|
||||||
// bars.reserve(128); // e.g. EAN-13 has 59 bars/spaces
|
// bars.reserve(128); // e.g. EAN-13 has 59 bars/spaces
|
||||||
|
|
||||||
// #ifdef PRINT_DEBUG
|
// #ifdef PRINT_DEBUG
|
||||||
// BitMatrix dbg(width, height);
|
// BitMatrix dbg(width, height);
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
'outer: for i in 0..maxLines {
|
let mut i = 0;
|
||||||
|
'outer: while i < maxLines {
|
||||||
// for (int i = 0; i < maxLines; i++) {
|
// for (int i = 0; i < maxLines; i++) {
|
||||||
|
|
||||||
// Scanning from the middle out. Determine which row we're looking at next:
|
// Scanning from the middle out. Determine which row we're looking at next:
|
||||||
let rowStepsAboveOrBelow: i32 = (i + 1) / 2;
|
let rowStepsAboveOrBelow: i32 = (i + 1) / 2;
|
||||||
let isAbove: bool = (i & 0x01) == 0; // i.e. is x even?
|
let isAbove: bool = (i & 0x01) == 0; // i.e. is x even?
|
||||||
let rowNumber: i32 = middle
|
let mut rowNumber: i32 = middle
|
||||||
+ rowStep
|
+ rowStep
|
||||||
* (if isAbove {
|
* (if isAbove {
|
||||||
rowStepsAboveOrBelow
|
rowStepsAboveOrBelow
|
||||||
} else {
|
} else {
|
||||||
-rowStepsAboveOrBelow
|
-rowStepsAboveOrBelow
|
||||||
});
|
});
|
||||||
let isCheckRow: bool = false;
|
let mut isCheckRow: bool = false;
|
||||||
if (rowNumber < 0 || rowNumber >= height) {
|
if (rowNumber < 0 || rowNumber >= height) {
|
||||||
// Oops, if we run off the top or bottom, stop
|
// Oops, if we run off the top or bottom, stop
|
||||||
break;
|
break;
|
||||||
@@ -110,18 +115,36 @@ impl<'a> ODReader<'_> {
|
|||||||
|
|
||||||
// See if we have additional check rows (see below) to process
|
// See if we have additional check rows (see below) to process
|
||||||
if (!checkRows.is_empty()) {
|
if (!checkRows.is_empty()) {
|
||||||
--i;
|
//--i;
|
||||||
rowNumber = checkRows.back();
|
i -= 1;
|
||||||
checkRows.pop_back();
|
rowNumber = *checkRows.last().unwrap_or(&0);
|
||||||
|
checkRows.pop();
|
||||||
isCheckRow = true;
|
isCheckRow = true;
|
||||||
if (rowNumber < 0 || rowNumber >= height) {
|
if (rowNumber < 0 || rowNumber >= height) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!image.getPatternRow(rowNumber, if rotate { 90 } else { 0 }, bars)) {
|
let br: Vec<bool> = if let Ok(r) = image.get_black_line(
|
||||||
|
rowNumber as usize,
|
||||||
|
if rotate {
|
||||||
|
LineOrientation::Column
|
||||||
|
} else {
|
||||||
|
LineOrientation::Row
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
r.as_ref().into()
|
||||||
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
};
|
||||||
|
// let img = if rotate {let a = image.rotate_counter_clockwise(); &a} else {image};
|
||||||
|
// let Ok(black_row ) = img.get_black_row(rowNumber as usize) else {continue;};
|
||||||
|
// let br : Vec<bool> = black_row.as_ref().into();
|
||||||
|
GetPatternRow(&br, &mut bars);
|
||||||
|
|
||||||
|
// if (!image.getPatternRow(rowNumber, if rotate { 90 } else { 0 }, bars)) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
// #ifdef PRINT_DEBUG
|
// #ifdef PRINT_DEBUG
|
||||||
// bool val = false;
|
// bool val = false;
|
||||||
@@ -145,7 +168,7 @@ impl<'a> ODReader<'_> {
|
|||||||
if (upsideDown) {
|
if (upsideDown) {
|
||||||
// reverse the row and continue
|
// reverse the row and continue
|
||||||
// std::reverse(bars.begin(), bars.end());
|
// std::reverse(bars.begin(), bars.end());
|
||||||
bars.reverse();
|
bars.rev();
|
||||||
}
|
}
|
||||||
let readers = vec![reader];
|
let readers = vec![reader];
|
||||||
// Look for a barcode
|
// Look for a barcode
|
||||||
@@ -153,73 +176,75 @@ impl<'a> ODReader<'_> {
|
|||||||
// for (size_t r = 0; r < readers.size(); ++r) {
|
// for (size_t r = 0; r < readers.size(); ++r) {
|
||||||
// If this is a pure symbol, then checking a single non-empty line is sufficient for all but the stacked
|
// If this is a pure symbol, then checking a single non-empty line is sufficient for all but the stacked
|
||||||
// DataBar codes. They are the only ones using the decodingState, which we can use as a flag here.
|
// DataBar codes. They are the only ones using the decodingState, which we can use as a flag here.
|
||||||
if (isPure && i && !decodingState[r]) {
|
if (isPure && i > 0 && decodingState[r].is_none()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = PatternView::from(bars);
|
let mut next = PatternView::new(&bars);
|
||||||
loop {
|
loop {
|
||||||
let result = readers[r]
|
let mut result_hld = readers[r]
|
||||||
.decodePattern(rowNumber, &mut next, decodingState[r])
|
.decodePattern(rowNumber as u32, &mut next, decodingState[r])
|
||||||
.ok();
|
.ok();
|
||||||
if (result.isValid() || (returnErrors && result.error())) {
|
if result_hld.is_some() /*|| (returnErrors && result.is_none())*/ {
|
||||||
IncrementLineCount(&result);
|
let mut result = result_hld.as_mut().unwrap();
|
||||||
|
IncrementLineCount(&mut result);
|
||||||
if (upsideDown) {
|
if (upsideDown) {
|
||||||
// update position (flip horizontally).
|
// update position (flip horizontally).
|
||||||
let points = result.position();
|
let points = result.getPointsMut();
|
||||||
for p in points {
|
for p in points {
|
||||||
// for (auto& p : points) {
|
// for (auto& p : points) {
|
||||||
p = point(width - p.getX() - 1, p.getY());
|
*p = point(width as f32 - p.getX() - 1.0, p.getY());
|
||||||
}
|
}
|
||||||
result.addPoints(points);
|
// result.addPoints(points);
|
||||||
// result.setPosition(std::move(points));
|
// result.setPosition(std::move(points));
|
||||||
}
|
}
|
||||||
if (rotate) {
|
if (rotate) {
|
||||||
let points = result.position();
|
let points = result.getPointsMut();
|
||||||
for p in points {
|
for p in points {
|
||||||
// for (auto& p : points) {
|
// for (auto& p : points) {
|
||||||
p = point(p.getY(), width - p.getX() - 1);
|
*p = point(p.getY(), width as f32- p.getX() - 1.0);
|
||||||
}
|
}
|
||||||
result.addPoints(points);
|
// result.addPoints(points);
|
||||||
// result.setPosition(std::move(points));
|
// result.setPosition(std::move(points));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we know this code already
|
// check if we know this code already
|
||||||
for other in res {
|
for other_hld in res.iter_mut() {
|
||||||
|
let Some(mut other) = other_hld else{ continue;};
|
||||||
// for (auto& other : res) {
|
// for (auto& other : res) {
|
||||||
if (result == other) {
|
if (result == &other) {
|
||||||
// merge the position information
|
// merge the position information
|
||||||
let dTop = PointT::maxAbsComponent(
|
let dTop = PointT::maxAbsComponent(
|
||||||
other.position().topLeft() - result.position().topLeft(),
|
other.getPoints()[0] - result.getPoints()[0],
|
||||||
);
|
);
|
||||||
let dBot = PointT::maxAbsComponent(
|
let dBot = PointT::maxAbsComponent(
|
||||||
other.position().bottomLeft() - result.position().topLeft(),
|
other.getPoints()[2] - result.getPoints()[0],
|
||||||
);
|
);
|
||||||
let points = other.position();
|
let mut points = other.getPoints().clone();
|
||||||
if (dTop < dBot
|
if (dTop < dBot
|
||||||
|| (dTop == dBot
|
|| (dTop == dBot
|
||||||
&& rotate
|
&& rotate
|
||||||
^ (PointT::sumAbsComponent(points[0])
|
^ (PointT::sumAbsComponent(points[0])
|
||||||
> PointT::sumAbsComponent(
|
> PointT::sumAbsComponent(
|
||||||
result.position()[0],
|
result.getPoints()[0],
|
||||||
))))
|
))))
|
||||||
{
|
{
|
||||||
points[0] = result.position()[0];
|
points[0] = result.getPoints()[0];
|
||||||
points[1] = result.position()[1];
|
points[1] = result.getPoints()[1];
|
||||||
} else {
|
} else {
|
||||||
points[2] = result.position()[2];
|
points[2] = result.getPoints()[2];
|
||||||
points[3] = result.position()[3];
|
points[3] = result.getPoints()[3];
|
||||||
}
|
}
|
||||||
other.setPosition(points);
|
other.replace_points(points);
|
||||||
IncrementLineCount(&other);
|
IncrementLineCount(&mut other);
|
||||||
// clear the result, so we don't insert it again below
|
// clear the result, so we don't insert it again below
|
||||||
result = None; //Result();
|
result_hld = None; //Result();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.format() != BarcodeFormat::UNSUPORTED_FORMAT) {
|
if (result.getBarcodeFormat() != &BarcodeFormat::UNSUPORTED_FORMAT) {
|
||||||
res.push(result);
|
res.push(Some(result.clone()));
|
||||||
// res.push_back(std::move(result));
|
// res.push_back(std::move(result));
|
||||||
|
|
||||||
// if we found a valid code we have not seen before but a minLineCount > 1,
|
// if we found a valid code we have not seen before but a minLineCount > 1,
|
||||||
@@ -234,10 +259,14 @@ impl<'a> ODReader<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxSymbols
|
if (maxSymbols > 0
|
||||||
&& res.iter().fold(0, |acc, e| {
|
&& res.iter().fold(0, |acc, e| {
|
||||||
acc + i32::from((r.lineCount() >= minLineCount))
|
if let Some(itm) = &res[r] {
|
||||||
}) == maxSymbols)
|
acc + i32::from((itm.line_count() >= minLineCount as usize))
|
||||||
|
}else {
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}) == maxSymbols as i32)
|
||||||
{
|
{
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
@@ -245,43 +274,53 @@ impl<'a> ODReader<'_> {
|
|||||||
// make sure we make progress and we start the next try on a bar
|
// make sure we make progress and we start the next try on a bar
|
||||||
next.shift(2 - (next.index() % 2));
|
next.shift(2 - (next.index() % 2));
|
||||||
next.extend();
|
next.extend();
|
||||||
if !(tryHarder && next.size()) {
|
if !(tryHarder && next.size() > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} //while (tryHarder && next.size());
|
} //while (tryHarder && next.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// out:
|
// out:
|
||||||
// remove all symbols with insufficient line count
|
// remove all symbols with insufficient line count
|
||||||
let it = res.iter().filter(|e| e.lineCount() < minLineCount);
|
res.retain(|e| if let Some(itm) = e {itm.line_count() < minLineCount as usize} else {false});
|
||||||
// let it = std::remove_if(res.begin(), res.end(), [&](auto&& r) { return r.lineCount() < minLineCount; });
|
// let it = std::remove_if(res.begin(), res.end(), [&](auto&& r) { return r.lineCount() < minLineCount; });
|
||||||
res.erase(it, res.end());
|
// res.erase(it, res.end());
|
||||||
|
|
||||||
// if symbols overlap, remove the one with a lower line count
|
// if symbols overlap, remove the one with a lower line count
|
||||||
for (i, a) in res.iter().enumerate() {
|
for (i, a_hld) in res.iter().enumerate() {
|
||||||
|
let a = a_hld.as_ref().unwrap();
|
||||||
// for (auto a = res.begin(); a != res.end(); ++a){
|
// for (auto a = res.begin(); a != res.end(); ++a){
|
||||||
for b in res.iter().skip(i) {
|
for b_hld in res.iter().skip(i) {
|
||||||
|
let b = b_hld.as_ref().unwrap();
|
||||||
// for (auto b = std::next(a); b != res.end(); ++b){
|
// for (auto b = std::next(a); b != res.end(); ++b){
|
||||||
if (PointT::HaveIntersectingBoundingBoxes(a.position(), b.position())) {
|
let Ok(q1) =Quadrilateral::try_from(a.getPoints()) else {continue;};
|
||||||
*(if a.lineCount() < b.lineCount() { a } else { b }) = None;
|
let Ok(q2) = Quadrilateral::try_from(b.getPoints()) else {continue;};
|
||||||
|
if (Quadrilateral::have_intersecting_bounding_boxes(&q1, &q2)) {
|
||||||
|
*(if a.line_count() < b.line_count() {
|
||||||
|
a_hld
|
||||||
|
} else {
|
||||||
|
b_hld
|
||||||
|
}) = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: C++20 res.erase_if()
|
//TODO: C++20 res.erase_if()
|
||||||
it = res
|
res
|
||||||
.iter()
|
|
||||||
.filter(|r| r.getBarcodeFormat() == BarcodeFormat::None);
|
.retain(|r| if let Some(itm) = r {
|
||||||
|
itm.getBarcodeFormat() == &BarcodeFormat::UNSUPORTED_FORMAT } else { false });
|
||||||
// it = std::remove_if(res.begin(), res.end(), [](auto&& r) { return r.format() == BarcodeFormat::None; });
|
// it = std::remove_if(res.begin(), res.end(), [](auto&& r) { return r.format() == BarcodeFormat::None; });
|
||||||
res.erase(it, res.end());
|
// res.erase(it, res.end());
|
||||||
|
|
||||||
// #ifdef PRINT_DEBUG
|
// #ifdef PRINT_DEBUG
|
||||||
// SaveAsPBM(dbg, rotate ? "od-log-r.pnm" : "od-log.pnm");
|
// SaveAsPBM(dbg, rotate ? "od-log-r.pnm" : "od-log.pnm");
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
res
|
res.iter().cloned().filter_map(|e| e).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +330,7 @@ impl<'a> ODReader<'_> {
|
|||||||
hints: &DecodingHintDictionary,
|
hints: &DecodingHintDictionary,
|
||||||
image: &BinaryBitmap<B>,
|
image: &BinaryBitmap<B>,
|
||||||
) -> Result<RXingResult> {
|
) -> Result<RXingResult> {
|
||||||
let result = Self::DoDecode(
|
let mut result = Self::DoDecode(
|
||||||
&self.reader,
|
&self.reader,
|
||||||
image,
|
image,
|
||||||
self.try_harder,
|
self.try_harder,
|
||||||
@@ -315,7 +354,7 @@ impl<'a> ODReader<'_> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.first().ok_or(Exceptions::NOT_FOUND)
|
result.first().cloned().ok_or(Exceptions::NOT_FOUND)
|
||||||
// return FirstOrDefault(std::move(result));
|
// return FirstOrDefault(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +364,7 @@ impl<'a> ODReader<'_> {
|
|||||||
image: &BinaryBitmap<B>,
|
image: &BinaryBitmap<B>,
|
||||||
maxSymbols: u32,
|
maxSymbols: u32,
|
||||||
) -> Result<Vec<RXingResult>> {
|
) -> Result<Vec<RXingResult>> {
|
||||||
let resH = Self::DoDecode(
|
let mut resH = Self::DoDecode(
|
||||||
&self.reader,
|
&self.reader,
|
||||||
image,
|
image,
|
||||||
self.try_harder,
|
self.try_harder,
|
||||||
@@ -335,8 +374,8 @@ impl<'a> ODReader<'_> {
|
|||||||
self.min_line_count,
|
self.min_line_count,
|
||||||
self.return_errors,
|
self.return_errors,
|
||||||
);
|
);
|
||||||
if ((!maxSymbols || (resH) < maxSymbols) && self.try_rotate) {
|
if ((!(maxSymbols != 0) || (resH.len()) < maxSymbols as usize) && self.try_rotate) {
|
||||||
let resV = Self::DoDecode(
|
let mut resV = Self::DoDecode(
|
||||||
&self.reader,
|
&self.reader,
|
||||||
image,
|
image,
|
||||||
self.try_harder,
|
self.try_harder,
|
||||||
@@ -397,7 +436,6 @@ impl<'a> ODReader<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn IncrementLineCount(r: &RXingResult) {
|
fn IncrementLineCount(r: &mut RXingResult) {
|
||||||
unimplemented!()
|
r.set_line_count(r.line_count() + 1)
|
||||||
// ++r._lineCount;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
* @author Sean Owen
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct RXingResult {
|
pub struct RXingResult {
|
||||||
text: String,
|
text: String,
|
||||||
rawBytes: Vec<u8>,
|
rawBytes: Vec<u8>,
|
||||||
@@ -39,6 +39,7 @@ pub struct RXingResult {
|
|||||||
format: BarcodeFormat,
|
format: BarcodeFormat,
|
||||||
resultMetadata: HashMap<RXingResultMetadataType, RXingResultMetadataValue>,
|
resultMetadata: HashMap<RXingResultMetadataType, RXingResultMetadataValue>,
|
||||||
timestamp: u128,
|
timestamp: u128,
|
||||||
|
line_count: usize,
|
||||||
}
|
}
|
||||||
impl RXingResult {
|
impl RXingResult {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -83,6 +84,7 @@ impl RXingResult {
|
|||||||
format,
|
format,
|
||||||
resultMetadata: HashMap::new(),
|
resultMetadata: HashMap::new(),
|
||||||
timestamp,
|
timestamp,
|
||||||
|
line_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ impl RXingResult {
|
|||||||
format: prev.format,
|
format: prev.format,
|
||||||
resultMetadata: prev.resultMetadata,
|
resultMetadata: prev.resultMetadata,
|
||||||
timestamp: prev.timestamp,
|
timestamp: prev.timestamp,
|
||||||
|
line_count: prev.line_count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +232,18 @@ impl RXingResult {
|
|||||||
pub fn getTimestamp(&self) -> u128 {
|
pub fn getTimestamp(&self) -> u128 {
|
||||||
self.timestamp
|
self.timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn line_count(&self) -> usize {
|
||||||
|
self.line_count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_line_count(&mut self, lc: usize) {
|
||||||
|
self.line_count = lc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_points(&mut self, points: Vec<Point>) {
|
||||||
|
self.resultPoints = points
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RXingResult {
|
impl fmt::Display for RXingResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user