use crate::{
common::{BitArray, Result},
point, Binarizer, BinaryBitmap, DecodeHints, Exceptions, LuminanceSource, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, Reader,
};
pub trait OneDReader: Reader {
const QUIET_ZONE: usize = 15;
fn _do_decode<B: Binarizer>(
&mut self,
image: &mut BinaryBitmap<B>,
hints: &DecodeHints,
) -> Result<RXingResult> {
let mut hints = hints.clone();
let width = image.get_width();
let height = image.get_height();
let try_harder = hints.TryHarder.unwrap_or(false);
let try_pure = hints.PureBarcode.unwrap_or(false);
if try_pure {
let mid_line = 1.max(image.get_height() / 2);
let rw = image
.get_source()
.get_row(mid_line)
.ok_or(Exceptions::index_out_of_bounds_with("row out of bounds"))?;
let decoded = self.decode_pure(mid_line as u32, &rw, &hints);
if decoded.is_ok() {
return decoded;
}
}
let row_step = usize::max(1, 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.div_ceil(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();
hints.NeedResultPointCallback = None;
}
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(width as f32 - points[0].x - 1.0, points[0].y);
points[1] = point(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: &DecodeHints,
) -> Result<RXingResult>;
fn decode_pure(
&mut self,
rowNumber: u32,
row: &[u8],
hints: &DecodeHints,
) -> Result<RXingResult> {
if row.is_empty() {
return Err(Exceptions::NOT_FOUND);
}
let new_row = pad_bitarray(row, Self::QUIET_ZONE);
self.decode_row(rowNumber, &new_row, hints)
}
}
fn pad_bitarray(bits: &[u8], quiet_zone: usize) -> BitArray {
const PIXEL_COLOR_SPLIT_POINT: u8 = u8::MAX / 2;
let mut new_row = BitArray::with_capacity(bits.len() + (quiet_zone * 2));
let value = bits[0] >= PIXEL_COLOR_SPLIT_POINT;
for _ in 0..quiet_zone {
new_row.appendBit(value);
}
for bit in bits {
new_row.appendBit(bit < &PIXEL_COLOR_SPLIT_POINT)
}
for _ in 0..quiet_zone {
new_row.appendBit(value);
}
new_row
}
pub fn pattern_match_variance(
counters: &[u32],
pattern: &[u32],
mut max_individual_variance: f32,
) -> f32 {
let num_counters = counters.len();
let total: f32 = counters.iter().sum::<u32>() as f32;
let pattern_length: u32 = pattern.iter().take(num_counters).sum();
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 (&counter, scaled_pattern) in counters.iter().zip(
pattern
.iter()
.take(num_counters)
.map(|&p| (p 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(())
}