use std::collections::HashMap;
use crate::{
common::Result, multi::MultipleBarcodeReader, BarcodeFormat, Binarizer, BinaryBitmap,
DecodingHintDictionary, Exceptions, Point, RXingResult, RXingResultMetadataType,
RXingResultMetadataValue, Reader,
};
use super::{
decoder::pdf_417_scanning_decoder, detector::pdf_417_detector, pdf_417_common,
PDF417RXingResultMetadata,
};
#[derive(Default)]
pub struct PDF417Reader;
impl Reader for PDF417Reader {
fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
self.decode_with_hints(image, &HashMap::new())
}
fn decode_with_hints<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
hints: &crate::DecodingHintDictionary,
) -> Result<crate::RXingResult> {
let result = Self::decode(image, hints, false)?;
if result.is_empty() {
return Err(Exceptions::NOT_FOUND);
}
Ok(result[0].clone())
}
}
impl MultipleBarcodeReader for PDF417Reader {
fn decode_multiple<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
) -> Result<Vec<RXingResult>> {
self.decode_multiple_with_hints(image, &HashMap::new())
}
fn decode_multiple_with_hints<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<Vec<RXingResult>> {
Self::decode(image, hints, true)
}
}
impl PDF417Reader {
pub fn new() -> Self {
Self
}
fn decode<B: Binarizer>(
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
multiple: bool,
) -> Result<Vec<RXingResult>> {
let mut results = Vec::new();
let detectorRXingResult = pdf_417_detector::detect_with_hints(image, hints, multiple)?;
for points in detectorRXingResult.getPoints() {
let points_filtered = points.iter().flatten().copied().collect();
let decoderRXingResult = pdf_417_scanning_decoder::decode(
detectorRXingResult.getBits(),
points[4],
points[5],
points[6],
points[7],
Self::getMinCodewordWidth(points),
Self::getMaxCodewordWidth(points),
)?;
let mut result = RXingResult::new(
decoderRXingResult.getText(),
decoderRXingResult.getRawBytes().clone(),
points_filtered,
BarcodeFormat::PDF_417,
);
result.putMetadata(
RXingResultMetadataType::ERROR_CORRECTION_LEVEL,
RXingResultMetadataValue::ErrorCorrectionLevel(
decoderRXingResult.getECLevel().to_owned(),
),
);
if let Some(pdf417RXingResultMetadata) = decoderRXingResult.getOther() {
if pdf417RXingResultMetadata.is::<PDF417RXingResultMetadata>() {
let data = RXingResultMetadataValue::Pdf417ExtraMetadata(
pdf417RXingResultMetadata
.clone()
.downcast::<PDF417RXingResultMetadata>()
.map_err(|_| Exceptions::ILLEGAL_STATE)?,
);
result.putMetadata(RXingResultMetadataType::PDF417_EXTRA_METADATA, data);
}
}
result.putMetadata(
RXingResultMetadataType::ORIENTATION,
RXingResultMetadataValue::Orientation(detectorRXingResult.getRotation() as i32),
);
result.putMetadata(
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
RXingResultMetadataValue::SymbologyIdentifier(format!(
"]L{}",
decoderRXingResult.getSymbologyModifier()
)),
);
results.push(result);
}
Ok(results)
}
fn getMaxWidth(p1: &Option<Point>, p2: &Option<Point>) -> u64 {
if let (Some(p1), Some(p2)) = (p1, p2) {
(p1.x - p2.x).abs() as u64
} else {
0
}
}
fn getMinWidth(p1: &Option<Point>, p2: &Option<Point>) -> u64 {
if let (Some(p1), Some(p2)) = (p1, p2) {
(p1.x - p2.x).abs() as u64
} else {
u32::MAX as u64
}
}
fn getMaxCodewordWidth(p: &[Option<Point>]) -> u32 {
Self::getMaxWidth(&p[0], &p[4])
.max(
Self::getMaxWidth(&p[6], &p[2]) * pdf_417_common::MODULES_IN_CODEWORD as u64
/ pdf_417_common::MODULES_IN_STOP_PATTERN as u64,
)
.max(Self::getMaxWidth(&p[1], &p[5]).max(
Self::getMaxWidth(&p[7], &p[3]) * pdf_417_common::MODULES_IN_CODEWORD as u64
/ pdf_417_common::MODULES_IN_STOP_PATTERN as u64,
)) as u32
}
fn getMinCodewordWidth(p: &[Option<Point>]) -> u32 {
Self::getMinWidth(&p[0], &p[4])
.min(
Self::getMinWidth(&p[6], &p[2]) * pdf_417_common::MODULES_IN_CODEWORD as u64
/ pdf_417_common::MODULES_IN_STOP_PATTERN as u64,
)
.min(Self::getMinWidth(&p[1], &p[5]).min(
Self::getMinWidth(&p[7], &p[3]) * pdf_417_common::MODULES_IN_CODEWORD as u64
/ pdf_417_common::MODULES_IN_STOP_PATTERN as u64,
)) as u32
}
}