use crate::{
common::{BitArray, Result},
point_f, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
Exceptions, RXingResult, RXingResultMetadataType, RXingResultMetadataValue, Reader,
};
pub trait OneDReader: Reader {
fn _do_decode<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
hints: &DecodingHintDictionary,
) -> Result<RXingResult> {
let mut hints = hints.clone();
let width = image.get_width();
let height = image.get_height();
let try_harder = matches!(
hints.get(&DecodeHintType::TRY_HARDER),
Some(DecodeHintValue::TryHarder(true))
);
let row_step = 1.max(height >> (if try_harder { 8 } else { 5 }));
let max_lines = if try_harder {
height } else {
15 };
let middle = height / 2;
for x in 0..max_lines {
let row_steps_above_or_below = (x + 1) / 2;
let is_above = (x & 0x01) == 0; let row_number: isize = middle as isize
+ row_step as isize
* (if is_above {
row_steps_above_or_below as isize
} else {
-(row_steps_above_or_below as isize)
});
if row_number < 0 || row_number >= height as isize {
break;
}
let mut row = if let Ok(res) = image.get_black_row(row_number as usize) {
res
} else {
continue;
};
for attempt in 0..2 {
if attempt == 1 {
row.to_mut().reverse();
if hints.contains_key(&DecodeHintType::NEED_RESULT_POINT_CALLBACK) {
hints.remove(&DecodeHintType::NEED_RESULT_POINT_CALLBACK);
}
}
let Ok(mut result) = self.decode_row(row_number as u32, &row, &hints) else {
continue;
};
if attempt == 1 {
result.putMetadata(
RXingResultMetadataType::ORIENTATION,
RXingResultMetadataValue::Orientation(180),
);
let points = result.getPointsMut();
if !points.is_empty() && points.len() >= 2 {
points[0] = point_f(width as f32 - points[0].x - 1.0, points[0].y);
points[1] = point_f(width as f32 - points[1].x - 1.0, points[1].y);
}
}
return Ok(result);
}
}
Err(Exceptions::NOT_FOUND)
}
fn decode_row(
&mut self,
rowNumber: u32,
row: &BitArray,
hints: &DecodingHintDictionary,
) -> Result<RXingResult>;
}
pub fn pattern_match_variance(
counters: &[u32],
pattern: &[u32],
mut max_individual_variance: f32,
) -> f32 {
let num_counters = counters.len();
let mut total = 0.0;
let mut pattern_length = 0;
for i in 0..num_counters {
total += counters[i] as f32;
pattern_length += pattern[i];
}
if total < pattern_length as f32 {
return f32::INFINITY;
}
let unit_bar_width = total / pattern_length as f32;
max_individual_variance *= unit_bar_width;
let mut total_variance = 0.0;
for x in 0..num_counters {
let counter = counters[x];
let scaled_pattern = (pattern[x] as f32) * unit_bar_width;
let variance = if (counter as f32) > scaled_pattern {
counter as f32 - scaled_pattern
} else {
scaled_pattern - counter as f32
};
if variance > max_individual_variance {
return f32::INFINITY;
}
total_variance += variance;
}
total_variance / total
}
pub fn record_pattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
let num_counters = counters.len();
counters.fill(0);
let end = row.get_size();
if start >= end {
return Err(Exceptions::NOT_FOUND);
}
let mut is_white = !row.get(start);
let mut counter_position = 0;
let mut i = start;
while i < end {
if row.get(i) != is_white {
counters[counter_position] += 1;
} else {
counter_position += 1;
if counter_position == num_counters {
break;
} else {
counters[counter_position] = 1;
is_white = !is_white;
}
}
i += 1;
}
if !(counter_position == num_counters || (counter_position == num_counters - 1 && i == end)) {
return Err(Exceptions::NOT_FOUND);
}
Ok(())
}
pub fn record_pattern_in_reverse(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<()> {
let mut start = start;
let mut num_transitions_left = counters.len() as isize;
let mut last = row.get(start);
while start > 0 && num_transitions_left >= 0 {
start -= 1;
if row.get(start) != last {
num_transitions_left -= 1;
last = !last;
}
}
if num_transitions_left >= 0 {
return Err(Exceptions::NOT_FOUND);
}
record_pattern(row, start + 1, counters)?;
Ok(())
}