mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-25 20:02:34 +00:00
fix: correct error related to GenericMultipleBarcodeReader
This error occured in some cases during decode for an image with many barcodes spread througout.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rxing"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
description="A rust port of the zxing barcode library."
|
||||
license="Apache-2.0"
|
||||
repository="https://github.com/rxing-core/rxing"
|
||||
|
||||
@@ -113,7 +113,13 @@ impl<B: Binarizer> BinaryBitmap<B> {
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if self.matrix.is_none() {
|
||||
self.matrix = Some(self.binarizer.get_black_matrix().unwrap().clone())
|
||||
self.matrix = Some(match self.binarizer.get_black_matrix() {
|
||||
Ok(a) => a.clone(),
|
||||
Err(_) => {
|
||||
BitMatrix::new(self.get_width() as u32, self.get_height() as u32).unwrap()
|
||||
}
|
||||
})
|
||||
// self.binarizer.get_black_matrix().unwrap_or_else( |_| BitMatrix::new(self.get_width() as u32, self.get_height() as u32).unwrap()).clone())
|
||||
}
|
||||
self.matrix.as_ref().unwrap()
|
||||
}
|
||||
|
||||
@@ -227,14 +227,16 @@ impl<LS: LuminanceSource> GlobalHistogramBinarizer<LS> {
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak.
|
||||
let mut bestValley = secondPeak - 1;
|
||||
let mut bestValley = secondPeak as isize - 1;
|
||||
let mut bestValleyScore = -1;
|
||||
let mut x = secondPeak;
|
||||
while x > firstPeak {
|
||||
let mut x = secondPeak as isize;
|
||||
while x > firstPeak as isize {
|
||||
// for (int x = secondPeak - 1; x > firstPeak; x--) {
|
||||
let fromFirst = x - firstPeak;
|
||||
let score =
|
||||
fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]) as usize;
|
||||
let fromFirst = x - firstPeak as isize;
|
||||
let score = fromFirst
|
||||
* fromFirst
|
||||
* (secondPeak as isize - x)
|
||||
* (maxBucketCount - buckets[x as usize]) as isize;
|
||||
if score as i32 > bestValleyScore {
|
||||
bestValley = x;
|
||||
bestValleyScore = score as i32;
|
||||
|
||||
@@ -57,14 +57,60 @@ impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> {
|
||||
let mut results = Vec::new();
|
||||
self.do_decode_multiple(image, hints, &mut results, 0, 0, 0);
|
||||
|
||||
if results.is_empty() {
|
||||
let unique_results: Vec<RXingResult> = results
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, r)| {
|
||||
let already_found = if r.getPoints().len() >= 4 {
|
||||
let q1 = Quadrilateral::new(
|
||||
r.getPoints()[0],
|
||||
r.getPoints()[1],
|
||||
r.getPoints()[2],
|
||||
r.getPoints()[3],
|
||||
);
|
||||
results.iter().skip(*i + 1).any(|e| {
|
||||
if e.getPoints().len() >= 4 {
|
||||
let q2 = Quadrilateral::new(
|
||||
e.getPoints()[0],
|
||||
e.getPoints()[1],
|
||||
e.getPoints()[2],
|
||||
e.getPoints()[3],
|
||||
);
|
||||
Quadrilateral::have_intersecting_bounding_boxes(&q1, &q2)
|
||||
} else {
|
||||
e.getPoints().iter().any(|p| q1.is_inside(*p))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
results.iter().skip(*i + 1).any(|e| {
|
||||
if e.getPoints().len() >= 4 {
|
||||
let q2 = Quadrilateral::new(
|
||||
e.getPoints()[0],
|
||||
e.getPoints()[1],
|
||||
e.getPoints()[2],
|
||||
e.getPoints()[3],
|
||||
);
|
||||
e.getPoints().iter().any(|p| q2.is_inside(*p))
|
||||
} else {
|
||||
e.getText() == r.getText()
|
||||
&& e.getBarcodeFormat() == r.getBarcodeFormat()
|
||||
}
|
||||
})
|
||||
};
|
||||
!already_found
|
||||
})
|
||||
.map(|(_, r)| r)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if unique_results.is_empty() {
|
||||
return Err(Exceptions::NOT_FOUND);
|
||||
}
|
||||
Ok(results)
|
||||
Ok(unique_results)
|
||||
}
|
||||
}
|
||||
impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
const MIN_DIMENSION_TO_RECUR: f32 = 10.0;
|
||||
const MIN_DIMENSION_TO_RECUR: f32 = 100.0;
|
||||
const MAX_DEPTH: u32 = 4;
|
||||
|
||||
pub fn new(delegate: T) -> Self {
|
||||
@@ -89,52 +135,11 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
return;
|
||||
};
|
||||
|
||||
// let alreadyFound = results.iter().any(|r| r.getText() == result.getText() && r.getBarcodeFormat() == result.getBarcodeFormat());
|
||||
|
||||
let resultPoints = result.getPoints().clone();
|
||||
|
||||
let possible_new_result = Self::translatePoints(result, xOffset, yOffset);
|
||||
|
||||
let already_found = if possible_new_result.getPoints().len() >= 4 {
|
||||
let q1 = Quadrilateral::new(
|
||||
possible_new_result.getPoints()[0],
|
||||
possible_new_result.getPoints()[1],
|
||||
possible_new_result.getPoints()[2],
|
||||
possible_new_result.getPoints()[3],
|
||||
);
|
||||
results.iter().any(|e| {
|
||||
if e.getPoints().len() >= 4 {
|
||||
let q2 = Quadrilateral::new(
|
||||
e.getPoints()[0],
|
||||
e.getPoints()[1],
|
||||
e.getPoints()[2],
|
||||
e.getPoints()[3],
|
||||
);
|
||||
Quadrilateral::have_intersecting_bounding_boxes(&q1, &q2)
|
||||
} else {
|
||||
e.getPoints().iter().any(|p| q1.is_inside(*p))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
results.iter().any(|e| {
|
||||
if e.getPoints().len() >= 4 {
|
||||
let q2 = Quadrilateral::new(
|
||||
e.getPoints()[0],
|
||||
e.getPoints()[1],
|
||||
e.getPoints()[2],
|
||||
e.getPoints()[3],
|
||||
);
|
||||
e.getPoints().iter().any(|p| q2.is_inside(*p))
|
||||
} else {
|
||||
e.getText() == possible_new_result.getText()
|
||||
&& e.getBarcodeFormat() == possible_new_result.getBarcodeFormat()
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if !already_found {
|
||||
results.push(possible_new_result);
|
||||
}
|
||||
results.push(possible_new_result);
|
||||
|
||||
if resultPoints.is_empty() {
|
||||
return;
|
||||
@@ -213,13 +218,6 @@ impl<T: Reader> GenericMultipleBarcodeReader<T> {
|
||||
.map(|oldPoint| point_f(oldPoint.x + xOffset as f32, oldPoint.y + yOffset as f32))
|
||||
.collect();
|
||||
|
||||
// let mut newPoints = Vec::with_capacity(oldPoints.len());
|
||||
// for oldPoint in oldPoints {
|
||||
// newPoints.push(point(
|
||||
// oldPoint.getX() + xOffset as f32,
|
||||
// oldPoint.getY() + yOffset as f32,
|
||||
// ));
|
||||
// }
|
||||
let mut newRXingResult = RXingResult::new_complex(
|
||||
result.getText(),
|
||||
result.getRawBytes().clone(),
|
||||
|
||||
@@ -30,7 +30,7 @@ use serde::{Deserialize, Serialize};
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RXingResult {
|
||||
text: String,
|
||||
rawBytes: Vec<u8>,
|
||||
|
||||
BIN
test_resources/blackbox/multi-1/AllSupportedBarcodeTypes.png
Normal file
BIN
test_resources/blackbox/multi-1/AllSupportedBarcodeTypes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 335 KiB |
@@ -23,3 +23,27 @@ fn issue_28() {
|
||||
);
|
||||
rxing::helpers::detect_multiple_in_file_with_hints("test_resources/blackbox/github_issue_cases/226611447-be6041dc-5b21-42fe-827b-068ccc59082c.png", &mut hints).unwrap_or_default();
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
#[test]
|
||||
fn dynamsoft_all_supported_formats_image_fault() {
|
||||
use rxing::DecodingHintDictionary;
|
||||
|
||||
let mut hints: DecodingHintDictionary = DecodingHintDictionary::new();
|
||||
hints.insert(
|
||||
rxing::DecodeHintType::TRY_HARDER,
|
||||
rxing::DecodeHintValue::TryHarder(true),
|
||||
);
|
||||
let results = rxing::helpers::detect_multiple_in_file_with_hints(
|
||||
"test_resources/blackbox/multi-1/AllSupportedBarcodeTypes.png",
|
||||
&mut hints,
|
||||
)
|
||||
.expect("must not fault during read");
|
||||
|
||||
assert!(
|
||||
results.len() >= 11,
|
||||
"regression detection, base count of 11 codes"
|
||||
);
|
||||
|
||||
// ToDo: This test is incomplete. Some that should be detected aren't, and some that are detected shouldn't be.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user