/* * 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, crate::Exceptions> { self.decodeMultipleWithHints(image, &HashMap::new()) } fn decodeMultipleWithHints( &self, image: &crate::BinaryBitmap, hints: &crate::DecodingHintDictionary, ) -> Result, 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::() { (other .downcast::() .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) -> Result, 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) }