use crate::{
BarcodeFormat, DecodeHints, Exceptions, ImmutableReader, RXingResult, Reader,
common::{DetectorRXingResult, cpp_essentials::ConcentricPattern},
multi::MultipleBarcodeReader,
};
use super::{
decoder::Decode,
detector::{
DetectPureMQR, DetectPureQR, DetectPureRMQR, FindFinderPatterns, GenerateFinderPatternSets,
SampleMQR, SampleQR, SampleRMQR,
},
};
#[derive(Default)]
pub struct QrReader;
impl Reader for QrReader {
fn decode<B: crate::Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap<B>,
) -> crate::common::Result<crate::RXingResult> {
self.decode_with_hints(image, &DecodeHints::default())
}
fn decode_with_hints<B: crate::Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodeHints,
) -> crate::common::Result<RXingResult> {
self.internal_decode_with_hints(image, hints)
}
}
impl ImmutableReader for QrReader {
fn immutable_decode_with_hints<B: crate::Binarizer>(
&self,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodeHints,
) -> crate::common::Result<RXingResult> {
self.internal_decode_with_hints(image, hints)
}
}
impl MultipleBarcodeReader for QrReader {
fn decode_multiple<B: crate::Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap<B>,
) -> crate::common::Result<Vec<crate::RXingResult>> {
self.decode_multiple_with_hints(image, &DecodeHints::default())
}
fn decode_multiple_with_hints<B: crate::Binarizer>(
&mut self,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodeHints,
) -> crate::common::Result<Vec<crate::RXingResult>> {
self.decode_set_number_with_hints(image, hints, u32::MAX)
}
}
impl QrReader {
fn decode_set_number_with_hints<B: crate::Binarizer>(
&self,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodeHints,
count: u32,
) -> crate::common::Result<Vec<RXingResult>> {
let binImg = image.get_black_matrix(); let maxSymbols = count;
let try_harder = hints.TryHarder.unwrap_or(false);
let mut allFPs = FindFinderPatterns(binImg, try_harder);
let mut usedFPs: Vec<ConcentricPattern> = Vec::new();
let mut results: Vec<RXingResult> = Vec::new();
let (check_qr, check_mqr, check_rmqr) = if let Some(formats) = &hints.PossibleFormats {
(
formats.contains(&BarcodeFormat::QR_CODE),
formats.contains(&BarcodeFormat::MICRO_QR_CODE),
formats.contains(&BarcodeFormat::RECTANGULAR_MICRO_QR_CODE),
)
} else {
(true, true, true)
};
if check_qr {
let allFPSets = GenerateFinderPatternSets(&mut allFPs);
for fpSet in allFPSets {
if usedFPs.contains(&fpSet.bl)
|| usedFPs.contains(&fpSet.tl)
|| usedFPs.contains(&fpSet.tr)
{
continue;
}
let detectorResult = SampleQR(binImg, &fpSet);
if let Ok(detectorResult) = detectorResult {
let decoderResult = Decode(detectorResult.getBits());
let position = detectorResult.getPoints();
if let Ok(decoderResult) = decoderResult {
if decoderResult.isValid() {
usedFPs.push(fpSet.bl);
usedFPs.push(fpSet.tl);
usedFPs.push(fpSet.tr);
}
if decoderResult.isValid() {
results.push(RXingResult::with_decoder_result(
decoderResult,
position,
BarcodeFormat::QR_CODE,
));
if maxSymbols != 0 && (results.len() as u32) == maxSymbols {
break;
}
}
}
}
}
}
if check_mqr && !(maxSymbols != 0 && (results.len() as u32) == maxSymbols) {
for fp in &allFPs {
if usedFPs.contains(fp) {
continue;
}
let detectorResult = SampleMQR(binImg, *fp);
if let Ok(detectorResult) = detectorResult {
let decoderResult = Decode(detectorResult.getBits());
let position = detectorResult.getPoints();
if let Ok(decoderResult) = decoderResult {
if decoderResult.isValid() {
results.push(RXingResult::with_decoder_result(
decoderResult,
position,
BarcodeFormat::MICRO_QR_CODE,
));
if maxSymbols != 0 && (results.len() as u32) == maxSymbols {
break;
}
}
}
}
}
}
if check_rmqr && !(maxSymbols != 0 && (results.len() as u32) == maxSymbols) {
for fp in &allFPs {
if usedFPs.contains(fp) {
continue;
}
let detectorResult = SampleRMQR(binImg, *fp);
if let Ok(detectorResult) = detectorResult {
let decoderResult = Decode(detectorResult.getBits());
let position = detectorResult.getPoints();
if let Ok(decoderResult) = decoderResult {
if decoderResult.isValid() {
results.push(RXingResult::with_decoder_result(
decoderResult,
position,
BarcodeFormat::RECTANGULAR_MICRO_QR_CODE,
));
if maxSymbols != 0 && (results.len() as u32) == maxSymbols {
break;
}
}
}
}
}
}
Ok(results)
}
fn internal_decode_with_hints<B: crate::Binarizer>(
&self,
image: &mut crate::BinaryBitmap<B>,
hints: &DecodeHints,
) -> crate::common::Result<RXingResult> {
if !matches!(hints.PureBarcode, Some(true))
{
return Ok(self
.decode_set_number_with_hints(image, hints, 1)?
.first()
.ok_or(Exceptions::NOT_FOUND)?
.clone());
}
let binImg = image.get_black_matrix();
let mut detectorResult = Err(Exceptions::NOT_FOUND);
if let Some(formats) = &hints.PossibleFormats {
if formats.contains(&BarcodeFormat::QR_CODE) {
detectorResult = DetectPureQR(binImg);
}
if formats.contains(&BarcodeFormat::MICRO_QR_CODE) && detectorResult.is_err() {
detectorResult = DetectPureMQR(binImg);
}
if formats.contains(&BarcodeFormat::RECTANGULAR_MICRO_QR_CODE)
&& detectorResult.is_err()
{
detectorResult = DetectPureRMQR(binImg);
}
}
if detectorResult.is_err() {
for decode_function in [DetectPureQR, DetectPureMQR, DetectPureRMQR] {
detectorResult = decode_function(binImg);
if detectorResult.is_ok() {
break;
}
}
}
let detectorResult = detectorResult?;
let decoderResult = Decode(detectorResult.getBits())?;
let position = detectorResult.getPoints();
Ok(RXingResult::with_decoder_result(
decoderResult,
position,
if detectorResult.getBits().width() != detectorResult.getBits().height() {
BarcodeFormat::RECTANGULAR_MICRO_QR_CODE
} else if detectorResult.getBits().width() < 21 {
BarcodeFormat::MICRO_QR_CODE
} else {
BarcodeFormat::QR_CODE
},
))
}
}