1use crate::{
18 Binarizer, BinaryBitmap, DecodeHints, Exceptions, Point, RXingResult, Reader,
19 common::{Quadrilateral, Result},
20 point,
21};
22
23use super::MultipleBarcodeReader;
24
25#[derive(Default)]
40pub struct GenericMultipleBarcodeReader<T: Reader>(T);
41
42impl<T: Reader> MultipleBarcodeReader for GenericMultipleBarcodeReader<T> {
43 fn decode_multiple<B: Binarizer>(
44 &mut self,
45 image: &mut BinaryBitmap<B>,
46 ) -> Result<Vec<RXingResult>> {
47 self.decode_multiple_with_hints(image, &DecodeHints::default())
48 }
49
50 fn decode_multiple_with_hints<B: Binarizer>(
51 &mut self,
52 image: &mut BinaryBitmap<B>,
53 hints: &DecodeHints,
54 ) -> Result<Vec<RXingResult>> {
55 let mut results = Vec::new();
56 self.do_decode_multiple(image, hints, &mut results, 0, 0, 0);
57
58 let unique_results: Vec<RXingResult> = results
59 .iter()
60 .enumerate()
61 .filter(|(i, r)| {
62 let already_found = if r.getPoints().len() >= 4 {
63 let q1 = Quadrilateral::new(
64 r.getPoints()[0],
65 r.getPoints()[1],
66 r.getPoints()[2],
67 r.getPoints()[3],
68 );
69 results.iter().skip(*i + 1).any(|e| {
70 if e.getPoints().len() >= 4 {
71 let q2 = Quadrilateral::new(
72 e.getPoints()[0],
73 e.getPoints()[1],
74 e.getPoints()[2],
75 e.getPoints()[3],
76 );
77 Quadrilateral::have_intersecting_bounding_boxes(&q1, &q2)
78 } else {
79 e.getPoints().iter().any(|p| q1.is_inside(*p))
80 }
81 })
82 } else {
83 results.iter().skip(*i + 1).any(|e| {
84 if e.getPoints().len() >= 4 {
85 let q2 = Quadrilateral::new(
86 e.getPoints()[0],
87 e.getPoints()[1],
88 e.getPoints()[2],
89 e.getPoints()[3],
90 );
91 e.getPoints().iter().any(|p| q2.is_inside(*p))
92 } else {
93 e.getText() == r.getText()
94 && e.getBarcodeFormat() == r.getBarcodeFormat()
95 }
96 })
97 };
98 !already_found
99 })
100 .map(|(_, r)| r)
101 .cloned()
102 .collect();
103
104 if unique_results.is_empty() {
105 return Err(Exceptions::NOT_FOUND);
106 }
107 Ok(unique_results)
108 }
109}
110impl<T: Reader> GenericMultipleBarcodeReader<T> {
111 const MIN_DIMENSION_TO_RECUR: f32 = 100.0;
112 const MAX_DEPTH: u32 = 4;
113
114 pub fn new(delegate: T) -> Self {
115 Self(delegate)
116 }
117
118 fn do_decode_multiple<B: Binarizer>(
119 &mut self,
120 image: &mut BinaryBitmap<B>,
121 hints: &DecodeHints,
122 results: &mut Vec<RXingResult>,
123 xOffset: u32,
124 yOffset: u32,
125 currentDepth: u32,
126 ) {
127 if currentDepth > Self::MAX_DEPTH {
128 return;
129 }
130
131 let Ok(result) = self.0.decode_with_hints(image, hints) else {
133 return;
134 };
135
136 let resultPoints = result.getPoints().to_vec();
137
138 let possible_new_result = Self::translatePoints(result, xOffset, yOffset);
139
140 results.push(possible_new_result);
141
142 if resultPoints.is_empty() {
143 return;
144 }
145
146 let width = image.get_width();
147 let height = image.get_height();
148 let mut minX: f32 = width as f32;
149 let mut minY: f32 = height as f32;
150 let mut maxX: f32 = 0.0;
151 let mut maxY: f32 = 0.0;
152 for point in resultPoints.into_iter() {
153 let x = point.x;
154 let y = point.y;
155
156 minX = f32::min(x, minX);
157 minY = f32::min(y, minY);
158 maxX = f32::max(x, maxX);
159 maxY = f32::max(y, maxY);
160 }
161
162 if minX > Self::MIN_DIMENSION_TO_RECUR {
164 self.do_decode_multiple(
165 &mut image.crop(0, 0, minX as usize, height),
166 hints,
167 results,
168 xOffset,
169 yOffset,
170 currentDepth + 1,
171 );
172 }
173 if minY > Self::MIN_DIMENSION_TO_RECUR {
175 self.do_decode_multiple(
176 &mut image.crop(0, 0, width, minY as usize),
177 hints,
178 results,
179 xOffset,
180 yOffset,
181 currentDepth + 1,
182 );
183 }
184 if maxX < (width as f32) - Self::MIN_DIMENSION_TO_RECUR {
186 self.do_decode_multiple(
187 &mut image.crop(maxX as usize, 0, width - maxX as usize, height),
188 hints,
189 results,
190 xOffset + maxX as u32,
191 yOffset,
192 currentDepth + 1,
193 );
194 }
195 if maxY < (height as f32) - Self::MIN_DIMENSION_TO_RECUR {
197 self.do_decode_multiple(
198 &mut image.crop(0, maxY as usize, width, height - maxY as usize),
199 hints,
200 results,
201 xOffset,
202 yOffset + maxY as u32,
203 currentDepth + 1,
204 );
205 }
206 }
207
208 fn translatePoints(result: RXingResult, xOffset: u32, yOffset: u32) -> RXingResult {
209 let oldPoints = result.getPoints();
210 if oldPoints.is_empty() {
211 return result;
212 }
213
214 let newPoints: Vec<Point> = oldPoints
215 .iter()
216 .map(|oldPoint| point(oldPoint.x + xOffset as f32, oldPoint.y + yOffset as f32))
217 .collect();
218
219 let mut newRXingResult = RXingResult::new_complex(
220 result.getText(),
221 result.getRawBytes().to_vec(),
222 result.getNumBits(),
223 newPoints,
224 *result.getBarcodeFormat(),
225 result.getTimestamp(),
226 );
227 newRXingResult.putAllMetadata(result.getRXingResultMetadata().clone());
228
229 newRXingResult
230 }
231}