Files
rxing/src/multi/qrcode/qr_code_multi_reader.rs
2022-12-01 11:17:23 -06:00

201 lines
7.4 KiB
Rust

/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::{cmp::Ordering, collections::HashMap};
use crate::{
common::DetectorRXingResult,
multi::MultipleBarcodeReader,
qrcode::{
decoder::{self, QRCodeDecoderMetaData},
QRCodeReader,
},
BarcodeFormat, Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue,
};
use super::detector::MultiDetector;
/**
* This implementation can detect and decode multiple QR Codes in an image.
*
* @author Sean Owen
* @author Hannes Erven
*/
pub struct QRCodeMultiReader(QRCodeReader);
impl MultipleBarcodeReader for QRCodeMultiReader {
fn decodeMultiple(
&self,
image: &crate::BinaryBitmap,
) -> Result<Vec<crate::RXingResult>, crate::Exceptions> {
self.decodeMultipleWithHints(image, &HashMap::new())
}
fn decodeMultipleWithHints(
&self,
image: &crate::BinaryBitmap,
hints: &crate::DecodingHintDictionary,
) -> Result<Vec<crate::RXingResult>, crate::Exceptions> {
let mut results = Vec::new();
let detectorRXingResults =
MultiDetector::new(image.getBlackMatrix().clone()).detectMulti(hints)?;
for detectorRXingResult in detectorRXingResults {
let mut proc = || -> Result<(), Exceptions> {
let decoderRXingResult = decoder::decoder::decode_bitmatrix_with_hints(
detectorRXingResult.getBits(),
hints,
)?;
let mut points = detectorRXingResult.getPoints().clone();
// If the code was mirrored: swap the bottom-left and the top-right points.
let other = decoderRXingResult.getOther();
if other.is::<QRCodeDecoderMetaData>() {
(other
.downcast::<QRCodeDecoderMetaData>()
.expect("must downcast to QRCodeDecoderMetaData"))
.applyMirroredCorrection(&mut points);
}
// if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) {
// ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points);
// }
let mut result = RXingResult::new(
decoderRXingResult.getText(),
decoderRXingResult.getRawBytes().clone(),
points,
BarcodeFormat::QR_CODE,
);
let byteSegments = decoderRXingResult.getByteSegments();
// if (byteSegments != null) {
result.putMetadata(
RXingResultMetadataType::BYTE_SEGMENTS,
RXingResultMetadataValue::ByteSegments(byteSegments.clone()),
);
// }
let ecLevel = decoderRXingResult.getECLevel();
// if (ecLevel != null) {
result.putMetadata(
RXingResultMetadataType::ERROR_CORRECTION_LEVEL,
RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_owned()),
);
// }
if decoderRXingResult.hasStructuredAppend() {
result.putMetadata(
RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE,
RXingResultMetadataValue::StructuredAppendSequence(
decoderRXingResult.getStructuredAppendSequenceNumber(),
),
);
result.putMetadata(
RXingResultMetadataType::STRUCTURED_APPEND_PARITY,
RXingResultMetadataValue::StructuredAppendParity(
decoderRXingResult.getStructuredAppendParity(),
),
);
}
results.push(result);
Ok(())
};
let output = proc();
if output.is_ok() {
continue;
} else if let Err(Exceptions::ReaderException(_)) = output {
// ignore and continue
continue;
} else {
return Err(output.err().unwrap());
}
}
results = Self::processStructuredAppend(results)?;
Ok(results)
}
}
impl QRCodeMultiReader {
fn processStructuredAppend(results: Vec<RXingResult>) -> Result<Vec<RXingResult>, Exceptions> {
let mut newRXingResults = Vec::new();
let mut saRXingResults = Vec::new();
for result in &results {
if result
.getRXingResultMetadata()
.contains_key(&RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE)
{
saRXingResults.push(result.clone());
} else {
newRXingResults.push(result.clone());
}
}
if saRXingResults.is_empty() {
return Ok(results);
}
// sort and concatenate the SA list items
saRXingResults.sort_by(compareRXingResult);
let mut newText = String::new();
let mut newRawBytes = Vec::new(); //new ByteArrayOutputStream();
let mut newByteSegment = Vec::new(); //new ByteArrayOutputStream();
for saRXingResult in saRXingResults {
newText.push_str(saRXingResult.getText());
let saBytes = saRXingResult.getRawBytes();
newRawBytes.extend_from_slice(saBytes);
// newRawBytes.write(saBytes, 0, saBytes.len());
if let Some(RXingResultMetadataValue::ByteSegments(byteSegments)) = saRXingResult
.getRXingResultMetadata()
.get(&RXingResultMetadataType::BYTE_SEGMENTS)
{
for segment in byteSegments {
// newByteSegment.write(segment, 0, segment.len());
newByteSegment.extend_from_slice(segment);
}
};
}
let mut newRXingResult =
RXingResult::new(&newText, newRawBytes, Vec::new(), BarcodeFormat::QR_CODE);
if newByteSegment.len() > 0 {
newRXingResult.putMetadata(
RXingResultMetadataType::BYTE_SEGMENTS,
RXingResultMetadataValue::ByteSegments(vec![newByteSegment]),
);
}
newRXingResults.push(newRXingResult);
Ok(newRXingResults)
}
}
fn compareRXingResult(a: &RXingResult, b: &RXingResult) -> Ordering {
let aNumber = if let Some(RXingResultMetadataValue::StructuredAppendSequence(v)) = a
.getRXingResultMetadata()
.get(&RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE)
{
v
} else {
&-1
};
let bNumber = if let Some(RXingResultMetadataValue::StructuredAppendSequence(v)) = b
.getRXingResultMetadata()
.get(&RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE)
{
v
} else {
&-1
};
aNumber.cmp(bNumber)
}