From 357a6a953d16a92ab19e1fe43bb5b7ae9a0752d5 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 12 Aug 2022 22:38:38 -0500 Subject: [PATCH] multi migrated errors --- .../multi/ByQuadrantReader.java | 0 .../multi/GenericMultipleBarcodeReader.java | 0 .../multi/MultipleBarcodeReader.java | 0 .../multi/qrcode/QRCodeMultiReader.java | 0 .../multi/qrcode/detector/MultiDetector.java | 0 .../detector/MultiFinderPatternFinder.java | 0 .../output/zxing/multi/by_quadrant_reader.rs | 133 ------- .../multi/generic_multiple_barcode_reader.rs | 162 --------- .../zxing/multi/multiple_barcode_reader.rs | 30 -- .../multi/qrcode/detector/multi_detector.rs | 67 ---- .../detector/multi_finder_pattern_finder.rs | 301 --------------- .../multi/qrcode/q_r_code_multi_reader.rs | 134 ------- src/multi.rs | 285 +++++++++++++++ src/multi/qrcode.rs | 129 +++++++ src/multi/qrcode/detector.rs | 344 ++++++++++++++++++ 15 files changed, 758 insertions(+), 827 deletions(-) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/ByQuadrantReader.java (100%) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/GenericMultipleBarcodeReader.java (100%) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/MultipleBarcodeReader.java (100%) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/qrcode/QRCodeMultiReader.java (100%) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/qrcode/detector/MultiDetector.java (100%) rename port_src/core/{src/main/java/com/google/zxing => DONE}/multi/qrcode/detector/MultiFinderPatternFinder.java (100%) delete mode 100644 port_src/output/zxing/multi/by_quadrant_reader.rs delete mode 100644 port_src/output/zxing/multi/generic_multiple_barcode_reader.rs delete mode 100644 port_src/output/zxing/multi/multiple_barcode_reader.rs delete mode 100644 port_src/output/zxing/multi/qrcode/detector/multi_detector.rs delete mode 100644 port_src/output/zxing/multi/qrcode/detector/multi_finder_pattern_finder.rs delete mode 100644 port_src/output/zxing/multi/qrcode/q_r_code_multi_reader.rs diff --git a/port_src/core/src/main/java/com/google/zxing/multi/ByQuadrantReader.java b/port_src/core/DONE/multi/ByQuadrantReader.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/ByQuadrantReader.java rename to port_src/core/DONE/multi/ByQuadrantReader.java diff --git a/port_src/core/src/main/java/com/google/zxing/multi/GenericMultipleBarcodeReader.java b/port_src/core/DONE/multi/GenericMultipleBarcodeReader.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/GenericMultipleBarcodeReader.java rename to port_src/core/DONE/multi/GenericMultipleBarcodeReader.java diff --git a/port_src/core/src/main/java/com/google/zxing/multi/MultipleBarcodeReader.java b/port_src/core/DONE/multi/MultipleBarcodeReader.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/MultipleBarcodeReader.java rename to port_src/core/DONE/multi/MultipleBarcodeReader.java diff --git a/port_src/core/src/main/java/com/google/zxing/multi/qrcode/QRCodeMultiReader.java b/port_src/core/DONE/multi/qrcode/QRCodeMultiReader.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/qrcode/QRCodeMultiReader.java rename to port_src/core/DONE/multi/qrcode/QRCodeMultiReader.java diff --git a/port_src/core/src/main/java/com/google/zxing/multi/qrcode/detector/MultiDetector.java b/port_src/core/DONE/multi/qrcode/detector/MultiDetector.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/qrcode/detector/MultiDetector.java rename to port_src/core/DONE/multi/qrcode/detector/MultiDetector.java diff --git a/port_src/core/src/main/java/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java b/port_src/core/DONE/multi/qrcode/detector/MultiFinderPatternFinder.java similarity index 100% rename from port_src/core/src/main/java/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java rename to port_src/core/DONE/multi/qrcode/detector/MultiFinderPatternFinder.java diff --git a/port_src/output/zxing/multi/by_quadrant_reader.rs b/port_src/output/zxing/multi/by_quadrant_reader.rs deleted file mode 100644 index c6aaf60..0000000 --- a/port_src/output/zxing/multi/by_quadrant_reader.rs +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi; - -/** - * This class attempts to decode a barcode from an image, not by scanning the whole image, - * but by scanning subsets of the image. This is important when there may be multiple barcodes in - * an image, and detecting a barcode may find parts of multiple barcode and fail to decode - * (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center - * 'quadrant' to cover the case where a barcode is found in the center. - * - * @see GenericMultipleBarcodeReader - */ -#[derive(Reader)] -pub struct ByQuadrantReader { - - let delegate: Reader; -} - -impl ByQuadrantReader { - - pub fn new( delegate: &Reader) -> ByQuadrantReader { - let .delegate = delegate; - } - - pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result> { - return Ok(self.decode(image, null)); - } - - pub fn decode(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException, ChecksumException, FormatException */Result> { - let width: i32 = image.get_width(); - let height: i32 = image.get_height(); - let half_width: i32 = width / 2; - let half_height: i32 = height / 2; - let tryResult1 = 0; - 'try1: loop { - { - // No need to call makeAbsolute as results will be relative to original top left here - return Ok(self.delegate.decode(&image.crop(0, 0, half_width, half_height), &hints)); - } - break 'try1 - } - match tryResult1 { - catch ( re: &NotFoundException) { - } 0 => break - } - - let tryResult1 = 0; - 'try1: loop { - { - let result: Result = self.delegate.decode(&image.crop(half_width, 0, half_width, half_height), &hints); - ::make_absolute(&result.get_result_points(), half_width, 0); - return Ok(result); - } - break 'try1 - } - match tryResult1 { - catch ( re: &NotFoundException) { - } 0 => break - } - - let tryResult1 = 0; - 'try1: loop { - { - let result: Result = self.delegate.decode(&image.crop(0, half_height, half_width, half_height), &hints); - ::make_absolute(&result.get_result_points(), 0, half_height); - return Ok(result); - } - break 'try1 - } - match tryResult1 { - catch ( re: &NotFoundException) { - } 0 => break - } - - let tryResult1 = 0; - 'try1: loop { - { - let result: Result = self.delegate.decode(&image.crop(half_width, half_height, half_width, half_height), &hints); - ::make_absolute(&result.get_result_points(), half_width, half_height); - return Ok(result); - } - break 'try1 - } - match tryResult1 { - catch ( re: &NotFoundException) { - } 0 => break - } - - let quarter_width: i32 = half_width / 2; - let quarter_height: i32 = half_height / 2; - let center: BinaryBitmap = image.crop(quarter_width, quarter_height, half_width, half_height); - let result: Result = self.delegate.decode(center, &hints); - ::make_absolute(&result.get_result_points(), quarter_width, quarter_height); - return Ok(result); - } - - pub fn reset(&self) { - self.delegate.reset(); - } - - fn make_absolute( points: &Vec, left_offset: i32, top_offset: i32) { - if points != null { - { - let mut i: i32 = 0; - while i < points.len() { - { - let relative: ResultPoint = points[i]; - if relative != null { - points[i] = ResultPoint::new(relative.get_x() + left_offset, relative.get_y() + top_offset); - } - } - i += 1; - } - } - - } - } -} - diff --git a/port_src/output/zxing/multi/generic_multiple_barcode_reader.rs b/port_src/output/zxing/multi/generic_multiple_barcode_reader.rs deleted file mode 100644 index 56aee20..0000000 --- a/port_src/output/zxing/multi/generic_multiple_barcode_reader.rs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi; - -/** - *

Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. - * After one barcode is found, the areas left, above, right and below the barcode's - * {@link ResultPoint}s are scanned, recursively.

- * - *

A caller may want to also employ {@link ByQuadrantReader} when attempting to find multiple - * 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent - * detecting any one of them.

- * - *

That is, instead of passing a {@link Reader} a caller might pass - * {@code new ByQuadrantReader(reader)}.

- * - * @author Sean Owen - */ - - const MIN_DIMENSION_TO_RECUR: i32 = 100; - - const MAX_DEPTH: i32 = 4; - - const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; -#[derive(MultipleBarcodeReader)] -pub struct GenericMultipleBarcodeReader { - - let delegate: Reader; -} - -impl GenericMultipleBarcodeReader { - - pub fn new( delegate: &Reader) -> GenericMultipleBarcodeReader { - let .delegate = delegate; - } - - pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> { - return Ok(self.decode_multiple(image, null)); - } - - pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> { - let results: List = ArrayList<>::new(); - self.do_decode_multiple(image, &hints, &results, 0, 0, 0); - if results.is_empty() { - throw NotFoundException::get_not_found_instance(); - } - return Ok(results.to_array(EMPTY_RESULT_ARRAY)); - } - - fn do_decode_multiple(&self, image: &BinaryBitmap, hints: &Map, results: &List, x_offset: i32, y_offset: i32, current_depth: i32) { - if current_depth > MAX_DEPTH { - return; - } - let mut result: Result; - let tryResult1 = 0; - 'try1: loop { - { - result = self.delegate.decode(image, &hints); - } - break 'try1 - } - match tryResult1 { - catch ( ignored: &ReaderException) { - return; - } 0 => break - } - - let already_found: bool = false; - for let existing_result: Result in results { - if existing_result.get_text().equals(&result.get_text()) { - already_found = true; - break; - } - } - if !already_found { - results.add(&::translate_result_points(result, x_offset, y_offset)); - } - let result_points: Vec = result.get_result_points(); - if result_points == null || result_points.len() == 0 { - return; - } - let width: i32 = image.get_width(); - let height: i32 = image.get_height(); - let min_x: f32 = width; - let min_y: f32 = height; - let max_x: f32 = 0.0f; - let max_y: f32 = 0.0f; - for let point: ResultPoint in result_points { - if point == null { - continue; - } - let x: f32 = point.get_x(); - let y: f32 = point.get_y(); - if x < min_x { - min_x = x; - } - if y < min_y { - min_y = y; - } - if x > max_x { - max_x = x; - } - if y > max_y { - max_y = y; - } - } - // Decode left of barcode - if min_x > MIN_DIMENSION_TO_RECUR { - self.do_decode_multiple(&image.crop(0, 0, min_x as i32, height), &hints, &results, x_offset, y_offset, current_depth + 1); - } - // Decode above barcode - if min_y > MIN_DIMENSION_TO_RECUR { - self.do_decode_multiple(&image.crop(0, 0, width, min_y as i32), &hints, &results, x_offset, y_offset, current_depth + 1); - } - // Decode right of barcode - if max_x < width - MIN_DIMENSION_TO_RECUR { - self.do_decode_multiple(&image.crop(max_x as i32, 0, width - max_x as i32, height), &hints, &results, x_offset + max_x as i32, y_offset, current_depth + 1); - } - // Decode below barcode - if max_y < height - MIN_DIMENSION_TO_RECUR { - self.do_decode_multiple(&image.crop(0, max_y as i32, width, height - max_y as i32), &hints, &results, x_offset, y_offset + max_y as i32, current_depth + 1); - } - } - - fn translate_result_points( result: &Result, x_offset: i32, y_offset: i32) -> Result { - let old_result_points: Vec = result.get_result_points(); - if old_result_points == null { - return result; - } - let new_result_points: [Option; old_result_points.len()] = [None; old_result_points.len()]; - { - let mut i: i32 = 0; - while i < old_result_points.len() { - { - let old_point: ResultPoint = old_result_points[i]; - if old_point != null { - new_result_points[i] = ResultPoint::new(old_point.get_x() + x_offset, old_point.get_y() + y_offset); - } - } - i += 1; - } - } - - let new_result: Result = Result::new(&result.get_text(), &result.get_raw_bytes(), &result.get_num_bits(), new_result_points, &result.get_barcode_format(), &result.get_timestamp()); - new_result.put_all_metadata(&result.get_result_metadata()); - return new_result; - } -} - diff --git a/port_src/output/zxing/multi/multiple_barcode_reader.rs b/port_src/output/zxing/multi/multiple_barcode_reader.rs deleted file mode 100644 index 6fdb447..0000000 --- a/port_src/output/zxing/multi/multiple_barcode_reader.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi; - -/** - * Implementation of this interface attempt to read several barcodes from one image. - * - * @see com.google.zxing.Reader - * @author Sean Owen - */ -pub trait MultipleBarcodeReader { - - fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> ; - - fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> ; -} - diff --git a/port_src/output/zxing/multi/qrcode/detector/multi_detector.rs b/port_src/output/zxing/multi/qrcode/detector/multi_detector.rs deleted file mode 100644 index 21cb56e..0000000 --- a/port_src/output/zxing/multi/qrcode/detector/multi_detector.rs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi::qrcode::detector; - -/** - *

Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code - * is rotated or skewed, or partially obscured.

- * - * @author Sean Owen - * @author Hannes Erven - */ - - const EMPTY_DETECTOR_RESULTS: [Option; 0] = [None; 0]; -pub struct MultiDetector { - super: Detector; -} - -impl MultiDetector { - - pub fn new( image: &BitMatrix) -> MultiDetector { - super(image); - } - - pub fn detect_multi(&self, hints: &Map) -> /* throws NotFoundException */Result, Rc> { - let image: BitMatrix = get_image(); - let result_point_callback: ResultPointCallback = if hints == null { null } else { hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback }; - let finder: MultiFinderPatternFinder = MultiFinderPatternFinder::new(image, result_point_callback); - let infos: Vec = finder.find_multi(&hints); - if infos.len() == 0 { - throw NotFoundException::get_not_found_instance(); - } - let result: List = ArrayList<>::new(); - for let info: FinderPatternInfo in infos { - let tryResult1 = 0; - 'try1: loop { - { - result.add(&process_finder_pattern_info(info)); - } - break 'try1 - } - match tryResult1 { - catch ( e: &ReaderException) { - } 0 => break - } - - } - if result.is_empty() { - return Ok(EMPTY_DETECTOR_RESULTS); - } else { - return Ok(result.to_array(EMPTY_DETECTOR_RESULTS)); - } - } -} - diff --git a/port_src/output/zxing/multi/qrcode/detector/multi_finder_pattern_finder.rs b/port_src/output/zxing/multi/qrcode/detector/multi_finder_pattern_finder.rs deleted file mode 100644 index 4a4c159..0000000 --- a/port_src/output/zxing/multi/qrcode/detector/multi_finder_pattern_finder.rs +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi::qrcode::detector; - -/** - *

This class attempts to find finder patterns in a QR Code. Finder patterns are the square - * markers at three corners of a QR Code.

- * - *

This class is thread-safe but not reentrant. Each thread must allocate its own object. - * - *

In contrast to {@link FinderPatternFinder}, this class will return an array of all possible - * QR code locations in the image.

- * - *

Use the TRY_HARDER hint to ask for a more thorough detection.

- * - * @author Sean Owen - * @author Hannes Erven - */ - - const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; - - const EMPTY_FP_ARRAY: [Option; 0] = [None; 0]; - - const EMPTY_FP_2D_ARRAY: [Option; 0] = [None; 0]; - -// TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for -// since it limits the number of regions to decode -// max. legal count of modules per QR code edge (177) - const MAX_MODULE_COUNT_PER_EDGE: f32 = 180; - -// min. legal count per modules per QR code edge (11) - const MIN_MODULE_COUNT_PER_EDGE: f32 = 9; - -/** - * More or less arbitrary cutoff point for determining if two finder patterns might belong - * to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their - * estimated modules sizes. - */ - const DIFF_MODSIZE_CUTOFF_PERCENT: f32 = 0.05f; - -/** - * More or less arbitrary cutoff point for determining if two finder patterns might belong - * to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their - * estimated modules sizes. - */ - const DIFF_MODSIZE_CUTOFF: f32 = 0.5f; -pub struct MultiFinderPatternFinder { - super: FinderPatternFinder; -} - -impl MultiFinderPatternFinder { - - /** - * A comparator that orders FinderPatterns by their estimated module size. - */ - #[derive(Comparator, Serializable)] - struct ModuleSizeComparator { - } - - impl ModuleSizeComparator { - - pub fn compare(&self, center1: &FinderPattern, center2: &FinderPattern) -> i32 { - let value: f32 = center2.get_estimated_module_size() - center1.get_estimated_module_size(); - return if value < 0.0 { -1 } else { if value > 0.0 { 1 } else { 0 } }; - } - } - - - pub fn new( image: &BitMatrix, result_point_callback: &ResultPointCallback) -> MultiFinderPatternFinder { - super(image, result_point_callback); - } - - /** - * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are - * those that have been detected at least 2 times, and whose module - * size differs from the average among those patterns the least - * @throws NotFoundException if 3 such finder patterns do not exist - */ - fn select_multiple_best_patterns(&self) -> /* throws NotFoundException */Result>, Rc> { - let possible_centers: List = ArrayList<>::new(); - for let fp: FinderPattern in get_possible_centers() { - if fp.get_count() >= 2 { - possible_centers.add(fp); - } - } - let size: i32 = possible_centers.size(); - if size < 3 { - // Couldn't find enough finder patterns - throw NotFoundException::get_not_found_instance(); - } - /* - * Begin HE modifications to safely detect multiple codes of equal size - */ - if size == 3 { - return Ok( : vec![FinderPattern; 1] = vec![possible_centers.to_array(EMPTY_FP_ARRAY), ] - ); - } - // Sort by estimated module size to speed up the upcoming checks - Collections::sort(&possible_centers, ModuleSizeComparator::new()); - /* - * Now lets start: build a list of tuples of three finder locations that - * - feature similar module sizes - * - are placed in a distance so the estimated module count is within the QR specification - * - have similar distance between upper left/right and left top/bottom finder patterns - * - form a triangle with 90° angle (checked by comparing top right/bottom left distance - * with pythagoras) - * - * Note: we allow each point to be used for more than one code region: this might seem - * counterintuitive at first, but the performance penalty is not that big. At this point, - * we cannot make a good quality decision whether the three finders actually represent - * a QR code, or are just by chance laid out so it looks like there might be a QR code there. - * So, if the layout seems right, lets have the decoder try to decode. - */ - // holder for the results - let results: List> = ArrayList<>::new(); - { - let mut i1: i32 = 0; - while i1 < (size - 2) { - { - let p1: FinderPattern = possible_centers.get(i1); - if p1 == null { - continue; - } - { - let mut i2: i32 = i1 + 1; - while i2 < (size - 1) { - { - let p2: FinderPattern = possible_centers.get(i2); - if p2 == null { - continue; - } - // Compare the expected module sizes; if they are really off, skip - let v_mod_size12: f32 = (p1.get_estimated_module_size() - p2.get_estimated_module_size()) / Math::min(&p1.get_estimated_module_size(), &p2.get_estimated_module_size()); - let v_mod_size12_a: f32 = Math::abs(p1.get_estimated_module_size() - p2.get_estimated_module_size()); - if v_mod_size12_a > DIFF_MODSIZE_CUTOFF && v_mod_size12 >= DIFF_MODSIZE_CUTOFF_PERCENT { - // any more interesting elements for the given p1. - break; - } - { - let mut i3: i32 = i2 + 1; - while i3 < size { - { - let p3: FinderPattern = possible_centers.get(i3); - if p3 == null { - continue; - } - // Compare the expected module sizes; if they are really off, skip - let v_mod_size23: f32 = (p2.get_estimated_module_size() - p3.get_estimated_module_size()) / Math::min(&p2.get_estimated_module_size(), &p3.get_estimated_module_size()); - let v_mod_size23_a: f32 = Math::abs(p2.get_estimated_module_size() - p3.get_estimated_module_size()); - if v_mod_size23_a > DIFF_MODSIZE_CUTOFF && v_mod_size23 >= DIFF_MODSIZE_CUTOFF_PERCENT { - // any more interesting elements for the given p1. - break; - } - let test: vec![Vec; 3] = vec![p1, p2, p3, ] - ; - ResultPoint::order_best_patterns(test); - // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal - let info: FinderPatternInfo = FinderPatternInfo::new(test); - let d_a: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_bottom_left()); - let d_c: f32 = ResultPoint::distance(&info.get_top_right(), &info.get_bottom_left()); - let d_b: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_top_right()); - // Check the sizes - let estimated_module_count: f32 = (d_a + d_b) / (p1.get_estimated_module_size() * 2.0f); - if estimated_module_count > MAX_MODULE_COUNT_PER_EDGE || estimated_module_count < MIN_MODULE_COUNT_PER_EDGE { - continue; - } - // Calculate the difference of the edge lengths in percent - let v_a_b_b_c: f32 = Math::abs((d_a - d_b) / Math::min(d_a, d_b)); - if v_a_b_b_c >= 0.1f { - continue; - } - // Calculate the diagonal length by assuming a 90° angle at topleft - let d_cpy: f32 = Math::sqrt(d_a as f64 * d_a + d_b as f64 * d_b) as f32; - // Compare to the real distance in % - let v_py_c: f32 = Math::abs((d_c - d_cpy) / Math::min(d_c, d_cpy)); - if v_py_c >= 0.1f { - continue; - } - // All tests passed! - results.add(test); - } - i3 += 1; - } - } - - } - i2 += 1; - } - } - - } - i1 += 1; - } - } - - if !results.is_empty() { - return Ok(results.to_array(EMPTY_FP_2D_ARRAY)); - } - // Nothing found! - throw NotFoundException::get_not_found_instance(); - } - - pub fn find_multi(&self, hints: &Map) -> /* throws NotFoundException */Result, Rc> { - let try_harder: bool = hints != null && hints.contains_key(DecodeHintType::TRY_HARDER); - let image: BitMatrix = get_image(); - let max_i: i32 = image.get_height(); - let max_j: i32 = image.get_width(); - // We are looking for black/white/black/white/black modules in - // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the - // image, and then account for the center being 3 modules in size. This gives the smallest - // number of pixels the center could be, so skip this often. When trying harder, look for all - // QR versions regardless of how dense they are. - let i_skip: i32 = (3 * max_i) / (4 * MAX_MODULES); - if i_skip < MIN_SKIP || try_harder { - i_skip = MIN_SKIP; - } - let state_count: [i32; 5] = [0; 5]; - { - let mut i: i32 = i_skip - 1; - while i < max_i { - { - // Get a row of black/white values - do_clear_counts(&state_count); - let current_state: i32 = 0; - { - let mut j: i32 = 0; - while j < max_j { - { - if image.get(j, i) { - // Black pixel - if (current_state & 1) == 1 { - // Counting white pixels - current_state += 1; - } - state_count[current_state] += 1; - } else { - // White pixel - if (current_state & 1) == 0 { - // Counting black pixels - if current_state == 4 { - // A winner? - if found_pattern_cross(&state_count) && handle_possible_center(&state_count, i, j) { - // Yes - // Clear state to start looking again - current_state = 0; - do_clear_counts(&state_count); - } else { - // No, shift counts back by two - do_shift_counts2(&state_count); - current_state = 3; - } - } else { - state_count[current_state += 1] += 1; - } - } else { - // Counting white pixels - state_count[current_state] += 1; - } - } - } - j += 1; - } - } - - if found_pattern_cross(&state_count) { - handle_possible_center(&state_count, i, max_j); - } - } - i += i_skip; - } - } - - // for i=iSkip-1 ... - let pattern_info: Vec> = self.select_multiple_best_patterns(); - let result: List = ArrayList<>::new(); - for let pattern: Vec in pattern_info { - ResultPoint::order_best_patterns(pattern); - result.add(FinderPatternInfo::new(pattern)); - } - if result.is_empty() { - return Ok(EMPTY_RESULT_ARRAY); - } else { - return Ok(result.to_array(EMPTY_RESULT_ARRAY)); - } - } -} - diff --git a/port_src/output/zxing/multi/qrcode/q_r_code_multi_reader.rs b/port_src/output/zxing/multi/qrcode/q_r_code_multi_reader.rs deleted file mode 100644 index 2727046..0000000 --- a/port_src/output/zxing/multi/qrcode/q_r_code_multi_reader.rs +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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. - */ -// package com::google::zxing::multi::qrcode; - -/** - * This implementation can detect and decode multiple QR Codes in an image. - * - * @author Sean Owen - * @author Hannes Erven - */ - - const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; - - const NO_POINTS: [Option; 0] = [None; 0]; -#[derive(MultipleBarcodeReader)] -pub struct QRCodeMultiReader { - super: QRCodeReader; -} - -impl QRCodeMultiReader { - - pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> { - return Ok(self.decode_multiple(image, null)); - } - - pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> { - let mut results: List = ArrayList<>::new(); - let detector_results: Vec = MultiDetector::new(&image.get_black_matrix()).detect_multi(&hints); - for let detector_result: DetectorResult in detector_results { - let tryResult1 = 0; - 'try1: loop { - { - let decoder_result: DecoderResult = get_decoder().decode(&detector_result.get_bits(), &hints); - let points: Vec = detector_result.get_points(); - // If the code was mirrored: swap the bottom-left and the top-right points. - if decoder_result.get_other() instanceof QRCodeDecoderMetaData { - (decoder_result.get_other() as QRCodeDecoderMetaData).apply_mirrored_correction(points); - } - let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::QR_CODE); - let byte_segments: List> = decoder_result.get_byte_segments(); - if byte_segments != null { - result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments); - } - let ec_level: String = decoder_result.get_e_c_level(); - if ec_level != null { - result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level); - } - if decoder_result.has_structured_append() { - result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE, &decoder_result.get_structured_append_sequence_number()); - result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_PARITY, &decoder_result.get_structured_append_parity()); - } - results.add(result); - } - break 'try1 - } - match tryResult1 { - catch ( re: &ReaderException) { - } 0 => break - } - - } - if results.is_empty() { - return Ok(EMPTY_RESULT_ARRAY); - } else { - results = ::process_structured_append(&results); - return Ok(results.to_array(EMPTY_RESULT_ARRAY)); - } - } - - fn process_structured_append( results: &List) -> List { - let new_results: List = ArrayList<>::new(); - let sa_results: List = ArrayList<>::new(); - for let result: Result in results { - if result.get_result_metadata().contains_key(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) { - sa_results.add(result); - } else { - new_results.add(result); - } - } - if sa_results.is_empty() { - return results; - } - // sort and concatenate the SA list items - Collections::sort(&sa_results, SAComparator::new()); - let new_text: StringBuilder = StringBuilder::new(); - let new_raw_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new(); - let new_byte_segment: ByteArrayOutputStream = ByteArrayOutputStream::new(); - for let sa_result: Result in sa_results { - new_text.append(&sa_result.get_text()); - let sa_bytes: Vec = sa_result.get_raw_bytes(); - new_raw_bytes.write(&sa_bytes, 0, sa_bytes.len()); - let byte_segments: Iterable> = sa_result.get_result_metadata().get(ResultMetadataType::BYTE_SEGMENTS) as Iterable>; - if byte_segments != null { - for let segment: Vec in byte_segments { - new_byte_segment.write(&segment, 0, segment.len()); - } - } - } - let new_result: Result = Result::new(&new_text.to_string(), &new_raw_bytes.to_byte_array(), NO_POINTS, BarcodeFormat::QR_CODE); - if new_byte_segment.size() > 0 { - new_result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &Collections::singleton_list(&new_byte_segment.to_byte_array())); - } - new_results.add(new_result); - return new_results; - } - - #[derive(Comparator, Serializable)] - struct SAComparator { - } - - impl SAComparator { - - pub fn compare(&self, a: &Result, b: &Result) -> i32 { - let a_number: i32 = a.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32; - let b_number: i32 = b.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32; - return Integer::compare(a_number, b_number); - } - } - -} - diff --git a/src/multi.rs b/src/multi.rs index e69de29..fd49870 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -0,0 +1,285 @@ +use crate::{BinaryBitmap,DecodeHintType,NotFoundException,RXingResult,Reader,ReaderException,ResultPoint,ChecksumException,FormatException}; + +// ByQuadrantReader.java +/** + * This class attempts to decode a barcode from an image, not by scanning the whole image, + * but by scanning subsets of the image. This is important when there may be multiple barcodes in + * an image, and detecting a barcode may find parts of multiple barcode and fail to decode + * (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center + * 'quadrant' to cover the case where a barcode is found in the center. + * + * @see GenericMultipleBarcodeReader + */ +pub struct ByQuadrantReader { + + let delegate: Reader; +} + +impl Reader for ByQuadrantReader { + pub fn decode(&self, image: &BinaryBitmap) -> /* throws NotFoundException, ChecksumException, FormatException */Result> { + return Ok(self.decode(image, null)); + } + + pub fn decode(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException, ChecksumException, FormatException */Result> { + let width: i32 = image.get_width(); + let height: i32 = image.get_height(); + let half_width: i32 = width / 2; + let half_height: i32 = height / 2; + let tryResult1 = 0; + 'try1: loop { + { + // No need to call makeAbsolute as results will be relative to original top left here + return Ok(self.delegate.decode(&image.crop(0, 0, half_width, half_height), &hints)); + } + break 'try1 + } + match tryResult1 { + catch ( re: &NotFoundException) { + } 0 => break + } + + let tryResult1 = 0; + 'try1: loop { + { + let result: Result = self.delegate.decode(&image.crop(half_width, 0, half_width, half_height), &hints); + ::make_absolute(&result.get_result_points(), half_width, 0); + return Ok(result); + } + break 'try1 + } + match tryResult1 { + catch ( re: &NotFoundException) { + } 0 => break + } + + let tryResult1 = 0; + 'try1: loop { + { + let result: Result = self.delegate.decode(&image.crop(0, half_height, half_width, half_height), &hints); + ::make_absolute(&result.get_result_points(), 0, half_height); + return Ok(result); + } + break 'try1 + } + match tryResult1 { + catch ( re: &NotFoundException) { + } 0 => break + } + + let tryResult1 = 0; + 'try1: loop { + { + let result: Result = self.delegate.decode(&image.crop(half_width, half_height, half_width, half_height), &hints); + ::make_absolute(&result.get_result_points(), half_width, half_height); + return Ok(result); + } + break 'try1 + } + match tryResult1 { + catch ( re: &NotFoundException) { + } 0 => break + } + + let quarter_width: i32 = half_width / 2; + let quarter_height: i32 = half_height / 2; + let center: BinaryBitmap = image.crop(quarter_width, quarter_height, half_width, half_height); + let result: Result = self.delegate.decode(center, &hints); + ::make_absolute(&result.get_result_points(), quarter_width, quarter_height); + return Ok(result); + } + + pub fn reset(&self) { + self.delegate.reset(); + } +} + +impl ByQuadrantReader { + + pub fn new( delegate: &Reader) -> ByQuadrantReader { + let .delegate = delegate; + } + + + + fn make_absolute( points: &Vec, left_offset: i32, top_offset: i32) { + if points != null { + { + let mut i: i32 = 0; + while i < points.len() { + { + let relative: ResultPoint = points[i]; + if relative != null { + points[i] = ResultPoint::new(relative.get_x() + left_offset, relative.get_y() + top_offset); + } + } + i += 1; + } + } + + } + } +} + + +// MultipleBarcodeReader.java +/** + * Implementation of this interface attempt to read several barcodes from one image. + * + * @see com.google.zxing.Reader + * @author Sean Owen + */ +pub trait MultipleBarcodeReader { + + fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> ; + + fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> ; +} + +// GenericMultipleBarcodeReader.java +/** + *

Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. + * After one barcode is found, the areas left, above, right and below the barcode's + * {@link ResultPoint}s are scanned, recursively.

+ * + *

A caller may want to also employ {@link ByQuadrantReader} when attempting to find multiple + * 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent + * detecting any one of them.

+ * + *

That is, instead of passing a {@link Reader} a caller might pass + * {@code new ByQuadrantReader(reader)}.

+ * + * @author Sean Owen + */ + +const MIN_DIMENSION_TO_RECUR: i32 = 100; + +const MAX_DEPTH: i32 = 4; + +const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; + +pub struct GenericMultipleBarcodeReader { + + let delegate: Reader; +} + +impl MultipleBarcodeReader for GenericMultipleBarcodeReader { + pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> { + return Ok(self.decode_multiple(image, null)); + } + + pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> { + let results: List = ArrayList<>::new(); + self.do_decode_multiple(image, &hints, &results, 0, 0, 0); + if results.is_empty() { + throw NotFoundException::get_not_found_instance(); + } + return Ok(results.to_array(EMPTY_RESULT_ARRAY)); + } +} + +impl GenericMultipleBarcodeReader { + + pub fn new( delegate: &Reader) -> GenericMultipleBarcodeReader { + let .delegate = delegate; + } + + + fn do_decode_multiple(&self, image: &BinaryBitmap, hints: &Map, results: &List, x_offset: i32, y_offset: i32, current_depth: i32) { + if current_depth > MAX_DEPTH { + return; + } + let mut result: Result; + let tryResult1 = 0; + 'try1: loop { + { + result = self.delegate.decode(image, &hints); + } + break 'try1 + } + match tryResult1 { + catch ( ignored: &ReaderException) { + return; + } 0 => break + } + + let already_found: bool = false; + for let existing_result: Result in results { + if existing_result.get_text().equals(&result.get_text()) { + already_found = true; + break; + } + } + if !already_found { + results.add(&::translate_result_points(result, x_offset, y_offset)); + } + let result_points: Vec = result.get_result_points(); + if result_points == null || result_points.len() == 0 { + return; + } + let width: i32 = image.get_width(); + let height: i32 = image.get_height(); + let min_x: f32 = width; + let min_y: f32 = height; + let max_x: f32 = 0.0f; + let max_y: f32 = 0.0f; + for let point: ResultPoint in result_points { + if point == null { + continue; + } + let x: f32 = point.get_x(); + let y: f32 = point.get_y(); + if x < min_x { + min_x = x; + } + if y < min_y { + min_y = y; + } + if x > max_x { + max_x = x; + } + if y > max_y { + max_y = y; + } + } + // Decode left of barcode + if min_x > MIN_DIMENSION_TO_RECUR { + self.do_decode_multiple(&image.crop(0, 0, min_x as i32, height), &hints, &results, x_offset, y_offset, current_depth + 1); + } + // Decode above barcode + if min_y > MIN_DIMENSION_TO_RECUR { + self.do_decode_multiple(&image.crop(0, 0, width, min_y as i32), &hints, &results, x_offset, y_offset, current_depth + 1); + } + // Decode right of barcode + if max_x < width - MIN_DIMENSION_TO_RECUR { + self.do_decode_multiple(&image.crop(max_x as i32, 0, width - max_x as i32, height), &hints, &results, x_offset + max_x as i32, y_offset, current_depth + 1); + } + // Decode below barcode + if max_y < height - MIN_DIMENSION_TO_RECUR { + self.do_decode_multiple(&image.crop(0, max_y as i32, width, height - max_y as i32), &hints, &results, x_offset, y_offset + max_y as i32, current_depth + 1); + } + } + + fn translate_result_points( result: &Result, x_offset: i32, y_offset: i32) -> Result { + let old_result_points: Vec = result.get_result_points(); + if old_result_points == null { + return result; + } + let new_result_points: [Option; old_result_points.len()] = [None; old_result_points.len()]; + { + let mut i: i32 = 0; + while i < old_result_points.len() { + { + let old_point: ResultPoint = old_result_points[i]; + if old_point != null { + new_result_points[i] = ResultPoint::new(old_point.get_x() + x_offset, old_point.get_y() + y_offset); + } + } + i += 1; + } + } + + let new_result: Result = Result::new(&result.get_text(), &result.get_raw_bytes(), &result.get_num_bits(), new_result_points, &result.get_barcode_format(), &result.get_timestamp()); + new_result.put_all_metadata(&result.get_result_metadata()); + return new_result; + } +} diff --git a/src/multi/qrcode.rs b/src/multi/qrcode.rs index e69de29..8be9931 100644 --- a/src/multi/qrcode.rs +++ b/src/multi/qrcode.rs @@ -0,0 +1,129 @@ +use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,NotFoundException,ReaderException,RXingResult,ResultMetadataType,ResultPoint}; +use crate::common{DecoderResult,DetectorResult}; +use crate::multi::{MultipleBarcodeReader}; +use crate::multi::qrcode::detector::MultiDetector; +use create::qrcode::{QRCodeReader}; +use crate::multi::qrcode::decoder::QRCodeDecoderMetaData; + + +// QRCodeMultiReader.java +/** + * This implementation can detect and decode multiple QR Codes in an image. + * + * @author Sean Owen + * @author Hannes Erven + */ + +const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; + +const NO_POINTS: [Option; 0] = [None; 0]; +pub struct QRCodeMultiReader { + super: QRCodeReader; +} + +impl MultipleBarcodeReader for QRCodeMultiReader { + pub fn decode_multiple(&self, image: &BinaryBitmap) -> /* throws NotFoundException */Result, Rc> { + return Ok(self.decode_multiple(image, null)); + } + + pub fn decode_multiple(&self, image: &BinaryBitmap, hints: &Map) -> /* throws NotFoundException */Result, Rc> { + let mut results: List = ArrayList<>::new(); + let detector_results: Vec = MultiDetector::new(&image.get_black_matrix()).detect_multi(&hints); + for let detector_result: DetectorResult in detector_results { + let tryResult1 = 0; + 'try1: loop { + { + let decoder_result: DecoderResult = get_decoder().decode(&detector_result.get_bits(), &hints); + let points: Vec = detector_result.get_points(); + // If the code was mirrored: swap the bottom-left and the top-right points. + if decoder_result.get_other() instanceof QRCodeDecoderMetaData { + (decoder_result.get_other() as QRCodeDecoderMetaData).apply_mirrored_correction(points); + } + let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::QR_CODE); + let byte_segments: List> = decoder_result.get_byte_segments(); + if byte_segments != null { + result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments); + } + let ec_level: String = decoder_result.get_e_c_level(); + if ec_level != null { + result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level); + } + if decoder_result.has_structured_append() { + result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE, &decoder_result.get_structured_append_sequence_number()); + result.put_metadata(ResultMetadataType::STRUCTURED_APPEND_PARITY, &decoder_result.get_structured_append_parity()); + } + results.add(result); + } + break 'try1 + } + match tryResult1 { + catch ( re: &ReaderException) { + } 0 => break + } + + } + if results.is_empty() { + return Ok(EMPTY_RESULT_ARRAY); + } else { + results = ::process_structured_append(&results); + return Ok(results.to_array(EMPTY_RESULT_ARRAY)); + } + } +} + +impl QRCodeMultiReader { + + + + fn process_structured_append( results: &List) -> List { + let new_results: List = ArrayList<>::new(); + let sa_results: List = ArrayList<>::new(); + for let result: Result in results { + if result.get_result_metadata().contains_key(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) { + sa_results.add(result); + } else { + new_results.add(result); + } + } + if sa_results.is_empty() { + return results; + } + // sort and concatenate the SA list items + Collections::sort(&sa_results, SAComparator::new()); + let new_text: StringBuilder = StringBuilder::new(); + let new_raw_bytes: ByteArrayOutputStream = ByteArrayOutputStream::new(); + let new_byte_segment: ByteArrayOutputStream = ByteArrayOutputStream::new(); + for let sa_result: Result in sa_results { + new_text.append(&sa_result.get_text()); + let sa_bytes: Vec = sa_result.get_raw_bytes(); + new_raw_bytes.write(&sa_bytes, 0, sa_bytes.len()); + let byte_segments: Iterable> = sa_result.get_result_metadata().get(ResultMetadataType::BYTE_SEGMENTS) as Iterable>; + if byte_segments != null { + for let segment: Vec in byte_segments { + new_byte_segment.write(&segment, 0, segment.len()); + } + } + } + let new_result: Result = Result::new(&new_text.to_string(), &new_raw_bytes.to_byte_array(), NO_POINTS, BarcodeFormat::QR_CODE); + if new_byte_segment.size() > 0 { + new_result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &Collections::singleton_list(&new_byte_segment.to_byte_array())); + } + new_results.add(new_result); + return new_results; + } + + #[derive(Comparator, Serializable)] + struct SAComparator { + } + + impl SAComparator { + + pub fn compare(&self, a: &Result, b: &Result) -> i32 { + let a_number: i32 = a.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32; + let b_number: i32 = b.get_result_metadata().get(ResultMetadataType::STRUCTURED_APPEND_SEQUENCE) as i32; + return Integer::compare(a_number, b_number); + } + } + +} + diff --git a/src/multi/qrcode/detector.rs b/src/multi/qrcode/detector.rs index e69de29..46cd848 100644 --- a/src/multi/qrcode/detector.rs +++ b/src/multi/qrcode/detector.rs @@ -0,0 +1,344 @@ +use crate::{DecodeHintType,NotFoundException,ReaderException,ResultPointCallback}; +use crate::common::{BitMatrix,DetectorResult}; +use crate::qrcode::detector::{Detector,FinderPatternInfo,FinderPattern,FinderPatternFinder}; + +// MultiDetector.java +/** + *

Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code + * is rotated or skewed, or partially obscured.

+ * + * @author Sean Owen + * @author Hannes Erven + */ + +const EMPTY_DETECTOR_RESULTS: [Option; 0] = [None; 0]; +pub struct MultiDetector { + super: Detector; +} + +impl Detector for MultiDetector{} + +impl MultiDetector { + + pub fn new( image: &BitMatrix) -> MultiDetector { + super(image); + } + + pub fn detect_multi(&self, hints: &Map) -> /* throws NotFoundException */Result, Rc> { + let image: BitMatrix = get_image(); + let result_point_callback: ResultPointCallback = if hints == null { null } else { hints.get(DecodeHintType::NEED_RESULT_POINT_CALLBACK) as ResultPointCallback }; + let finder: MultiFinderPatternFinder = MultiFinderPatternFinder::new(image, result_point_callback); + let infos: Vec = finder.find_multi(&hints); + if infos.len() == 0 { + throw NotFoundException::get_not_found_instance(); + } + let result: List = ArrayList<>::new(); + for let info: FinderPatternInfo in infos { + let tryResult1 = 0; + 'try1: loop { + { + result.add(&process_finder_pattern_info(info)); + } + break 'try1 + } + match tryResult1 { + catch ( e: &ReaderException) { + } 0 => break + } + + } + if result.is_empty() { + return Ok(EMPTY_DETECTOR_RESULTS); + } else { + return Ok(result.to_array(EMPTY_DETECTOR_RESULTS)); + } + } +} + +// MultiFinderPatternFinder.java +/** + *

This class attempts to find finder patterns in a QR Code. Finder patterns are the square + * markers at three corners of a QR Code.

+ * + *

This class is thread-safe but not reentrant. Each thread must allocate its own object. + * + *

In contrast to {@link FinderPatternFinder}, this class will return an array of all possible + * QR code locations in the image.

+ * + *

Use the TRY_HARDER hint to ask for a more thorough detection.

+ * + * @author Sean Owen + * @author Hannes Erven + */ + +const EMPTY_RESULT_ARRAY: [Option; 0] = [None; 0]; + +const EMPTY_FP_ARRAY: [Option; 0] = [None; 0]; + +const EMPTY_FP_2D_ARRAY: [Option; 0] = [None; 0]; + +// TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for +// since it limits the number of regions to decode +// max. legal count of modules per QR code edge (177) +const MAX_MODULE_COUNT_PER_EDGE: f32 = 180; + +// min. legal count per modules per QR code edge (11) +const MIN_MODULE_COUNT_PER_EDGE: f32 = 9; + +/** + * More or less arbitrary cutoff point for determining if two finder patterns might belong + * to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their + * estimated modules sizes. + */ +const DIFF_MODSIZE_CUTOFF_PERCENT: f32 = 0.05f; + +/** + * More or less arbitrary cutoff point for determining if two finder patterns might belong + * to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their + * estimated modules sizes. + */ +const DIFF_MODSIZE_CUTOFF: f32 = 0.5f; +pub struct MultiFinderPatternFinder { + super: FinderPatternFinder; +} + +impl FinderPatternFinder for MultiFinderPatternFinder {} + +impl MultiFinderPatternFinder { + + /** + * A comparator that orders FinderPatterns by their estimated module size. + */ + #[derive(Comparator, Serializable)] + struct ModuleSizeComparator { + } + + impl ModuleSizeComparator { + + pub fn compare(&self, center1: &FinderPattern, center2: &FinderPattern) -> i32 { + let value: f32 = center2.get_estimated_module_size() - center1.get_estimated_module_size(); + return if value < 0.0 { -1 } else { if value > 0.0 { 1 } else { 0 } }; + } + } + + + pub fn new( image: &BitMatrix, result_point_callback: &ResultPointCallback) -> MultiFinderPatternFinder { + super(image, result_point_callback); + } + + /** + * @return the 3 best {@link FinderPattern}s from our list of candidates. The "best" are + * those that have been detected at least 2 times, and whose module + * size differs from the average among those patterns the least + * @throws NotFoundException if 3 such finder patterns do not exist + */ + fn select_multiple_best_patterns(&self) -> /* throws NotFoundException */Result>, Rc> { + let possible_centers: List = ArrayList<>::new(); + for let fp: FinderPattern in get_possible_centers() { + if fp.get_count() >= 2 { + possible_centers.add(fp); + } + } + let size: i32 = possible_centers.size(); + if size < 3 { + // Couldn't find enough finder patterns + throw NotFoundException::get_not_found_instance(); + } + /* + * Begin HE modifications to safely detect multiple codes of equal size + */ + if size == 3 { + return Ok( : vec![FinderPattern; 1] = vec![possible_centers.to_array(EMPTY_FP_ARRAY), ] + ); + } + // Sort by estimated module size to speed up the upcoming checks + Collections::sort(&possible_centers, ModuleSizeComparator::new()); + /* + * Now lets start: build a list of tuples of three finder locations that + * - feature similar module sizes + * - are placed in a distance so the estimated module count is within the QR specification + * - have similar distance between upper left/right and left top/bottom finder patterns + * - form a triangle with 90° angle (checked by comparing top right/bottom left distance + * with pythagoras) + * + * Note: we allow each point to be used for more than one code region: this might seem + * counterintuitive at first, but the performance penalty is not that big. At this point, + * we cannot make a good quality decision whether the three finders actually represent + * a QR code, or are just by chance laid out so it looks like there might be a QR code there. + * So, if the layout seems right, lets have the decoder try to decode. + */ + // holder for the results + let results: List> = ArrayList<>::new(); + { + let mut i1: i32 = 0; + while i1 < (size - 2) { + { + let p1: FinderPattern = possible_centers.get(i1); + if p1 == null { + continue; + } + { + let mut i2: i32 = i1 + 1; + while i2 < (size - 1) { + { + let p2: FinderPattern = possible_centers.get(i2); + if p2 == null { + continue; + } + // Compare the expected module sizes; if they are really off, skip + let v_mod_size12: f32 = (p1.get_estimated_module_size() - p2.get_estimated_module_size()) / Math::min(&p1.get_estimated_module_size(), &p2.get_estimated_module_size()); + let v_mod_size12_a: f32 = Math::abs(p1.get_estimated_module_size() - p2.get_estimated_module_size()); + if v_mod_size12_a > DIFF_MODSIZE_CUTOFF && v_mod_size12 >= DIFF_MODSIZE_CUTOFF_PERCENT { + // any more interesting elements for the given p1. + break; + } + { + let mut i3: i32 = i2 + 1; + while i3 < size { + { + let p3: FinderPattern = possible_centers.get(i3); + if p3 == null { + continue; + } + // Compare the expected module sizes; if they are really off, skip + let v_mod_size23: f32 = (p2.get_estimated_module_size() - p3.get_estimated_module_size()) / Math::min(&p2.get_estimated_module_size(), &p3.get_estimated_module_size()); + let v_mod_size23_a: f32 = Math::abs(p2.get_estimated_module_size() - p3.get_estimated_module_size()); + if v_mod_size23_a > DIFF_MODSIZE_CUTOFF && v_mod_size23 >= DIFF_MODSIZE_CUTOFF_PERCENT { + // any more interesting elements for the given p1. + break; + } + let test: vec![Vec; 3] = vec![p1, p2, p3, ] + ; + ResultPoint::order_best_patterns(test); + // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal + let info: FinderPatternInfo = FinderPatternInfo::new(test); + let d_a: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_bottom_left()); + let d_c: f32 = ResultPoint::distance(&info.get_top_right(), &info.get_bottom_left()); + let d_b: f32 = ResultPoint::distance(&info.get_top_left(), &info.get_top_right()); + // Check the sizes + let estimated_module_count: f32 = (d_a + d_b) / (p1.get_estimated_module_size() * 2.0f); + if estimated_module_count > MAX_MODULE_COUNT_PER_EDGE || estimated_module_count < MIN_MODULE_COUNT_PER_EDGE { + continue; + } + // Calculate the difference of the edge lengths in percent + let v_a_b_b_c: f32 = Math::abs((d_a - d_b) / Math::min(d_a, d_b)); + if v_a_b_b_c >= 0.1f { + continue; + } + // Calculate the diagonal length by assuming a 90° angle at topleft + let d_cpy: f32 = Math::sqrt(d_a as f64 * d_a + d_b as f64 * d_b) as f32; + // Compare to the real distance in % + let v_py_c: f32 = Math::abs((d_c - d_cpy) / Math::min(d_c, d_cpy)); + if v_py_c >= 0.1f { + continue; + } + // All tests passed! + results.add(test); + } + i3 += 1; + } + } + + } + i2 += 1; + } + } + + } + i1 += 1; + } + } + + if !results.is_empty() { + return Ok(results.to_array(EMPTY_FP_2D_ARRAY)); + } + // Nothing found! + throw NotFoundException::get_not_found_instance(); + } + + pub fn find_multi(&self, hints: &Map) -> /* throws NotFoundException */Result, Rc> { + let try_harder: bool = hints != null && hints.contains_key(DecodeHintType::TRY_HARDER); + let image: BitMatrix = get_image(); + let max_i: i32 = image.get_height(); + let max_j: i32 = image.get_width(); + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + let i_skip: i32 = (3 * max_i) / (4 * MAX_MODULES); + if i_skip < MIN_SKIP || try_harder { + i_skip = MIN_SKIP; + } + let state_count: [i32; 5] = [0; 5]; + { + let mut i: i32 = i_skip - 1; + while i < max_i { + { + // Get a row of black/white values + do_clear_counts(&state_count); + let current_state: i32 = 0; + { + let mut j: i32 = 0; + while j < max_j { + { + if image.get(j, i) { + // Black pixel + if (current_state & 1) == 1 { + // Counting white pixels + current_state += 1; + } + state_count[current_state] += 1; + } else { + // White pixel + if (current_state & 1) == 0 { + // Counting black pixels + if current_state == 4 { + // A winner? + if found_pattern_cross(&state_count) && handle_possible_center(&state_count, i, j) { + // Yes + // Clear state to start looking again + current_state = 0; + do_clear_counts(&state_count); + } else { + // No, shift counts back by two + do_shift_counts2(&state_count); + current_state = 3; + } + } else { + state_count[current_state += 1] += 1; + } + } else { + // Counting white pixels + state_count[current_state] += 1; + } + } + } + j += 1; + } + } + + if found_pattern_cross(&state_count) { + handle_possible_center(&state_count, i, max_j); + } + } + i += i_skip; + } + } + + // for i=iSkip-1 ... + let pattern_info: Vec> = self.select_multiple_best_patterns(); + let result: List = ArrayList<>::new(); + for let pattern: Vec in pattern_info { + ResultPoint::order_best_patterns(pattern); + result.add(FinderPatternInfo::new(pattern)); + } + if result.is_empty() { + return Ok(EMPTY_RESULT_ARRAY); + } else { + return Ok(result.to_array(EMPTY_RESULT_ARRAY)); + } + } +} +