use std::mem::swap;
use crate::{
Result, SymbolType,
color::Color,
config::{DecoderConfig, internal::DecoderState},
decoder::DECODE_WINDOW,
image_data::ImageData,
img_scanner_config::ImageScannerConfig,
symbol::{Orientation, Symbol},
};
#[cfg(feature = "codabar")]
use crate::decoder::CodabarDecoder;
#[cfg(feature = "code39")]
use crate::decoder::Code39Decoder;
#[cfg(feature = "code93")]
use crate::decoder::Code93Decoder;
#[cfg(feature = "code128")]
use crate::decoder::Code128Decoder;
#[cfg(feature = "databar")]
use crate::decoder::DatabarDecoder;
#[cfg(feature = "i25")]
use crate::decoder::I25Decoder;
#[cfg(feature = "qrcode")]
use crate::decoder::QrFinder;
#[cfg(feature = "qrcode")]
use crate::finder::find_qr;
#[cfg(feature = "qrcode")]
use crate::qrcode::qrdec::QrReader;
#[cfg(feature = "sqcode")]
use crate::sqcode::SqReader;
#[cfg(feature = "codabar")]
use crate::decoders::codabar::decode_codabar;
#[cfg(feature = "code39")]
use crate::decoders::code39::decode_code39;
#[cfg(feature = "code93")]
use crate::decoders::code93::decode_code93;
#[cfg(feature = "code128")]
use crate::decoders::code128::decode_code128;
#[cfg(feature = "databar")]
use crate::decoders::databar::decode_databar;
#[cfg(feature = "ean")]
use crate::decoders::ean::{EanDecoder, decode_ean};
#[cfg(feature = "i25")]
use crate::decoders::i25::decode_i25;
const QR_FINDER_SUBPREC: i32 = 2;
use crate::decoder::BBox;
fn qr_fixed(v: i32, rnd: i32) -> u32 {
(((v as u32) << 1) + (rnd as u32)) << (QR_FINDER_SUBPREC - 1)
}
const ZBAR_FIXED: i32 = 5;
const ROUND: u32 = 1 << (ZBAR_FIXED - 1); const ZBAR_SCANNER_THRESH_FADE: u32 = 8;
const ZBAR_SCANNER_THRESH_MIN: u32 = 4;
const EWMA_WEIGHT: u32 = 25;
const THRESH_INIT: u32 = 14;
const BUFFER_MIN: usize = 0x20;
const BUFFER_MAX: usize = 0x100;
pub(crate) struct ImageScanner {
y1_min_thresh: u32,
x: u32,
y0: [i32; 4],
y1_sign: i32,
y1_thresh: u32,
cur_edge: u32,
last_edge: u32,
width: u32,
pub(crate) idx: u8,
pub(crate) w: [u32; DECODE_WINDOW],
pub(crate) type_: SymbolType,
pub(crate) lock: SymbolType,
pub(crate) modifiers: u32,
pub(crate) direction: i32,
pub(crate) s6: u32,
buffer: Vec<u8>,
pub(crate) config: DecoderState,
#[cfg(feature = "ean")]
pub(crate) ean: EanDecoder,
#[cfg(feature = "i25")]
pub(crate) i25: I25Decoder,
#[cfg(feature = "databar")]
pub(crate) databar: DatabarDecoder,
#[cfg(feature = "codabar")]
pub(crate) codabar: CodabarDecoder,
#[cfg(feature = "code39")]
pub(crate) code39: Code39Decoder,
#[cfg(feature = "code93")]
pub(crate) code93: Code93Decoder,
#[cfg(feature = "code128")]
pub(crate) code128: Code128Decoder,
#[cfg(feature = "qrcode")]
pub(crate) qrf: QrFinder,
#[cfg(feature = "qrcode")]
qr: QrReader,
#[cfg(feature = "sqcode")]
sq: SqReader,
dx: i32,
dy: i32,
du: i32,
umin: i32,
v: i32,
syms: Vec<Symbol>,
#[cfg(feature = "qrcode")]
last_qr_finder_regions: Vec<BBox>,
scanner_config: ImageScannerConfig,
}
impl Default for ImageScanner {
fn default() -> Self {
let mut scanner = Self {
y1_min_thresh: ZBAR_SCANNER_THRESH_MIN,
x: 0,
y0: [0; 4],
y1_sign: 0,
y1_thresh: 0,
cur_edge: 0,
last_edge: 0,
width: 0,
idx: 0,
w: Default::default(),
type_: SymbolType::default(),
lock: SymbolType::default(),
modifiers: 0,
direction: 0,
s6: 0,
buffer: Vec::with_capacity(BUFFER_MIN),
config: DecoderState::default(),
#[cfg(feature = "ean")]
ean: EanDecoder::default(),
#[cfg(feature = "i25")]
i25: I25Decoder::default(),
#[cfg(feature = "databar")]
databar: DatabarDecoder::default(),
#[cfg(feature = "codabar")]
codabar: CodabarDecoder::default(),
#[cfg(feature = "code39")]
code39: Code39Decoder::default(),
#[cfg(feature = "code93")]
code93: Code93Decoder::default(),
#[cfg(feature = "code128")]
code128: Code128Decoder::default(),
#[cfg(feature = "qrcode")]
qrf: QrFinder::default(),
#[cfg(feature = "qrcode")]
qr: QrReader::default(),
#[cfg(feature = "sqcode")]
sq: SqReader::default(),
dx: 0,
dy: 0,
du: 0,
umin: 0,
v: 0,
syms: vec![],
#[cfg(feature = "qrcode")]
last_qr_finder_regions: Vec::new(),
scanner_config: ImageScannerConfig::default(),
};
scanner.sync_config_to_decoders();
scanner.decoder_reset();
scanner
}
}
impl ImageScanner {
pub(crate) fn with_config(config: DecoderConfig) -> Self {
let decoder_state: DecoderState = (&config).into();
let mut scanner_config = ImageScannerConfig {
position_tracking: decoder_state.scanner.position_tracking,
test_inverted: decoder_state.scanner.test_inverted,
x_density: decoder_state.scanner.x_density,
y_density: decoder_state.scanner.y_density,
ean_composite: decoder_state.is_enabled(SymbolType::Composite),
uncertainty: Default::default(),
};
for sym in SymbolType::ALL.iter() {
if let Some(sym_config) = decoder_state.get(*sym) {
scanner_config
.uncertainty
.insert(*sym, sym_config.uncertainty);
}
}
let mut scanner = Self {
config: decoder_state,
scanner_config,
..Default::default()
};
scanner.sync_config_to_decoders();
scanner.decoder_reset();
scanner
}
pub(crate) fn add_symbol(&mut self, sym: Symbol) {
self.syms.push(sym);
}
pub(crate) fn find_duplicate_symbol(
&mut self,
symbol_type: SymbolType,
data: &[u8],
) -> Option<&mut Symbol> {
self.syms
.iter_mut()
.find(|sym| sym.symbol_type() == symbol_type && sym.data == data)
}
pub(crate) fn width(&self) -> u32 {
self.width
}
pub(crate) fn calc_thresh(&mut self) -> u32 {
let thresh = self.y1_thresh;
if thresh <= self.y1_min_thresh || self.width == 0 {
return self.y1_min_thresh;
}
let dx = (self.x << ZBAR_FIXED) - self.last_edge;
let mut t = thresh as u64 * dx as u64;
t /= self.width as u64;
t /= ZBAR_SCANNER_THRESH_FADE as u64;
if thresh > t as u32 {
let new_thresh = thresh - t as u32;
if new_thresh > self.y1_min_thresh {
return new_thresh;
}
}
self.y1_thresh = self.y1_min_thresh;
self.y1_min_thresh
}
pub(crate) fn scanner_flush(&mut self) -> SymbolType {
if self.y1_sign == 0 {
return SymbolType::None;
}
let x = (self.x << ZBAR_FIXED) + ROUND;
if self.cur_edge != x || self.y1_sign > 0 {
let edge = self.process_edge();
self.cur_edge = x;
self.y1_sign = -self.y1_sign;
return edge;
}
self.y1_sign = 0;
self.width = 0;
self.decode_width(0)
}
pub(crate) fn new_scan(&mut self) -> SymbolType {
let mut edge = SymbolType::None;
while self.y1_sign != 0 {
let tmp = self.scanner_flush();
if tmp > edge {
edge = tmp;
}
}
self.x = 0;
self.y0 = Default::default();
self.y1_sign = 0;
self.y1_thresh = self.y1_min_thresh;
self.cur_edge = 0;
self.last_edge = 0;
self.width = 0;
self.decoder_new_scan();
edge
}
pub(crate) fn scan_y(&mut self, y: i32) -> SymbolType {
let x = self.x;
let mut y0_1 = self.y0[((x.wrapping_sub(1)) & 3) as usize];
let mut y0_0 = y0_1;
if x != 0 {
y0_0 += ((y - y0_1) * EWMA_WEIGHT as i32) >> ZBAR_FIXED;
self.y0[(x & 3) as usize] = y0_0;
} else {
y0_0 = y;
y0_1 = y;
self.y0[0] = y;
self.y0[1] = y;
self.y0[2] = y;
self.y0[3] = y;
}
let y0_2 = self.y0[((x.wrapping_sub(2)) & 3) as usize];
let y0_3 = self.y0[((x.wrapping_sub(3)) & 3) as usize];
let mut y1_1 = y0_1 - y0_2;
{
let y1_2 = y0_2 - y0_3;
if y1_1.abs() < y1_2.abs() && ((y1_1 >= 0) == (y1_2 >= 0)) {
y1_1 = y1_2;
}
}
let y2_1 = y0_0 - (y0_1 * 2) + y0_2;
let y2_2 = y0_1 - (y0_2 * 2) + y0_3;
let mut edge = SymbolType::None;
if (y2_1 == 0 || ((y2_1 > 0) == (y2_2 < 0))) && (self.calc_thresh() <= y1_1.unsigned_abs())
{
let y1_rev = if self.y1_sign > 0 { y1_1 < 0 } else { y1_1 > 0 };
if y1_rev {
edge = self.process_edge();
}
if y1_rev || (self.y1_sign.abs() < y1_1.abs()) {
self.y1_sign = y1_1;
self.y1_thresh = (y1_1.unsigned_abs() * THRESH_INIT + ROUND) >> ZBAR_FIXED;
if self.y1_thresh < self.y1_min_thresh {
self.y1_thresh = self.y1_min_thresh;
}
let d = y2_1 - y2_2;
self.cur_edge = 1 << ZBAR_FIXED;
if d == 0 {
self.cur_edge >>= 1;
} else if y2_1 != 0 {
self.cur_edge -= (((y2_1 << ZBAR_FIXED) + 1) / d) as u32;
}
self.cur_edge += x << ZBAR_FIXED;
}
}
self.x = x + 1;
edge
}
pub(crate) fn quiet_border(&mut self) {
self.scanner_flush();
self.scanner_flush();
self.new_scan();
}
pub(crate) fn get_edge(&self, offset: u32, prec: i32) -> u32 {
let edge = self
.last_edge
.wrapping_sub(offset)
.wrapping_sub(1 << ZBAR_FIXED)
.wrapping_sub(ROUND);
let prec = ZBAR_FIXED - prec;
match prec {
1.. => edge >> prec,
0 => edge,
_ => edge << (-prec),
}
}
fn process_edge(&mut self) -> SymbolType {
if self.y1_sign == 0 {
self.last_edge = (1 << ZBAR_FIXED) + ROUND;
self.cur_edge = (1 << ZBAR_FIXED) + ROUND;
} else if self.last_edge == 0 {
self.last_edge = self.cur_edge;
}
self.width = self.cur_edge - self.last_edge;
self.last_edge = self.cur_edge;
let width = self.width;
self.decode_width(width)
}
fn sync_config_to_decoders(&mut self) {
#[cfg(feature = "ean")]
{
self.ean.enable = self.config.ean_enabled();
}
}
pub(crate) fn color(&self) -> Color {
self.idx.into()
}
pub(crate) fn get_width(&self, offset: u8) -> u32 {
self.w[((self.idx as usize).wrapping_sub(offset as usize)) & (DECODE_WINDOW - 1)]
}
pub(crate) fn pair_width(&self, offset: u8) -> u32 {
self.get_width(offset) + self.get_width(offset + 1)
}
pub(crate) fn calc_s(&self, mut offset: u8, mut n: u8) -> u32 {
let mut s = 0;
while n > 0 {
s += self.get_width(offset);
offset += 1;
n -= 1;
}
s
}
pub(crate) fn set_buffer_capacity(&mut self, len: usize) -> Result<(), ()> {
if len <= BUFFER_MIN {
return Ok(());
}
let current_alloc = self.buffer_capacity();
if len < current_alloc {
return Ok(());
}
if len > BUFFER_MAX {
return Err(());
}
self.buffer.reserve_exact(len - current_alloc);
Ok(())
}
pub(crate) fn buffer_capacity(&self) -> usize {
self.buffer.capacity()
}
pub(crate) fn set_buffer_len(&mut self, len: usize) {
debug_assert!(len <= self.buffer_capacity());
self.buffer.resize(len, 0);
}
pub(crate) fn buffer_mut_slice(&mut self, len: usize) -> Result<&mut [u8], ()> {
if len > BUFFER_MAX {
return Err(());
}
self.buffer.resize(len, 0);
Ok(&mut self.buffer[..len])
}
pub(crate) fn buffer_slice(&self) -> &[u8] {
&self.buffer
}
pub(crate) fn write_buffer_byte(&mut self, pos: usize, value: u8) -> Result<(), ()> {
self.buffer_mut_slice(pos + 1)?[pos] = value;
Ok(())
}
pub(crate) fn truncate_buffer(&mut self, len: usize) {
self.buffer.truncate(len);
}
pub(crate) fn is_enabled(&self, sym: SymbolType) -> bool {
self.config.is_enabled(sym)
}
pub(crate) fn should_emit_checksum(&self, sym: SymbolType) -> bool {
self.config
.get(sym)
.map(|c| c.checksum.emit_check)
.unwrap_or(false)
}
pub(crate) fn should_validate_checksum(&self, sym: SymbolType) -> bool {
self.config
.get(sym)
.map(|c| c.checksum.add_check)
.unwrap_or(false)
}
pub(crate) fn get_length_limits(&self, sym: SymbolType) -> Option<(u32, u32)> {
self.config
.get(sym)
.and_then(|c| c.length_limits)
.map(|l| (l.min, l.max))
}
pub(crate) fn decoder_reset(&mut self) {
self.idx = 0;
self.w.fill(0);
self.type_ = SymbolType::None;
self.lock = SymbolType::None;
self.modifiers = 0;
self.direction = 0;
self.s6 = 0;
self.set_buffer_len(0);
#[cfg(feature = "ean")]
self.ean.reset();
#[cfg(feature = "i25")]
self.i25.reset();
#[cfg(feature = "databar")]
self.databar.reset();
#[cfg(feature = "codabar")]
self.codabar.reset();
#[cfg(feature = "code39")]
self.code39.reset();
#[cfg(feature = "code93")]
self.code93.reset();
#[cfg(feature = "code128")]
self.code128.reset();
#[cfg(feature = "qrcode")]
self.qrf.reset();
}
pub(crate) fn decoder_new_scan(&mut self) {
self.w.fill(0);
self.lock = SymbolType::None;
self.idx = 0;
self.s6 = 0;
#[cfg(feature = "ean")]
self.ean.new_scan();
#[cfg(feature = "i25")]
self.i25.reset();
#[cfg(feature = "databar")]
self.databar.reset();
#[cfg(feature = "codabar")]
self.codabar.reset();
#[cfg(feature = "code39")]
self.code39.reset();
#[cfg(feature = "code93")]
self.code93.reset();
#[cfg(feature = "code128")]
self.code128.reset();
#[cfg(feature = "qrcode")]
self.qrf.reset();
}
pub(crate) fn acquire_lock(&mut self, req: SymbolType) -> bool {
if self.lock != SymbolType::None {
return false;
}
self.lock = req;
true
}
pub(crate) fn release_lock(&mut self, req: SymbolType) -> bool {
if self.lock != req {
return false;
}
self.lock = SymbolType::None;
true
}
pub(crate) fn decode_width(&mut self, w: u32) -> SymbolType {
let mut sym = SymbolType::None;
self.w[(self.idx & (DECODE_WINDOW - 1) as u8) as usize] = w;
self.s6 = self.s6.wrapping_sub(self.get_width(7));
self.s6 = self.s6.wrapping_add(self.get_width(1));
#[cfg(feature = "qrcode")]
if self.is_enabled(SymbolType::QrCode) {
let tmp = find_qr(self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "ean")]
if self.ean.enable {
let tmp = decode_ean(&mut *self);
if tmp != SymbolType::None {
sym = tmp;
}
}
#[cfg(feature = "code39")]
if self.is_enabled(SymbolType::Code39) {
let tmp = decode_code39(&mut *self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "code93")]
if self.is_enabled(SymbolType::Code93) {
let tmp = decode_code93(&mut *self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "code128")]
if self.is_enabled(SymbolType::Code128) {
let tmp = decode_code128(&mut *self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "databar")]
if self.is_enabled(SymbolType::Databar) || self.is_enabled(SymbolType::DatabarExp) {
let tmp = decode_databar(&mut *self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "codabar")]
if self.is_enabled(SymbolType::Codabar) {
let tmp = decode_codabar(&mut *self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
#[cfg(feature = "i25")]
if self.is_enabled(SymbolType::I25) {
let tmp = decode_i25(self);
if tmp > SymbolType::Partial {
sym = tmp;
}
}
self.idx = self.idx.wrapping_add(1);
self.type_ = sym;
if sym != SymbolType::None {
if self.lock != SymbolType::None
&& sym > SymbolType::Partial
&& sym != SymbolType::QrCode
{
self.lock = SymbolType::None;
}
if sym > SymbolType::Partial {
self.symbol_handler();
}
}
sym
}
pub(crate) fn get_type(&self) -> SymbolType {
self.type_
}
pub(crate) fn get_modifiers(&self) -> u32 {
self.modifiers
}
pub(crate) fn scan_image(&mut self, img: &mut ImageData) -> (Vec<Symbol>, Vec<BBox>) {
let symbols = self.scan_image_internal(img);
#[cfg(feature = "qrcode")]
let finder_regions = std::mem::take(&mut self.last_qr_finder_regions);
#[cfg(not(feature = "qrcode"))]
let finder_regions: Vec<BBox> = Vec::new();
if symbols.is_empty()
&& self.scanner_config.test_inverted
&& let Some(mut inv) = img.copy(true)
{
let inverted_symbols = self.scan_image_internal(&mut inv);
if !inverted_symbols.is_empty() {
return (inverted_symbols, finder_regions);
}
}
(symbols, finder_regions)
}
#[cfg(feature = "qrcode")]
pub(crate) fn qr_handler(&mut self) {
let line = &mut self.qrf.line;
let pos0 = line.pos[0] as u32;
let boffs_in = line.boffs as u32;
let len_in = line.len as u32;
let eoffs_in = line.eoffs as u32;
let mut u = self.get_edge(pos0, QR_FINDER_SUBPREC);
let boffs_edge = self.get_edge(boffs_in, QR_FINDER_SUBPREC);
let len_edge = self.get_edge(len_in, QR_FINDER_SUBPREC);
let eoffs_edge = self.get_edge(eoffs_in, QR_FINDER_SUBPREC);
let line = &mut self.qrf.line;
line.boffs = (u as i32) - boffs_edge as i32;
line.len = len_edge as i32;
line.eoffs = eoffs_edge as i32 - line.len;
line.len -= u as i32;
u = (qr_fixed(self.umin, 0) as i64 + (self.du as i64) * (u as i64)) as u32;
if self.du < 0 {
std::mem::swap(&mut line.boffs, &mut line.eoffs);
u = u.wrapping_sub(line.len as u32);
}
let vert: i32 = if self.dx != 0 { 0 } else { 1 };
line.pos[vert as usize] = u as i32;
line.pos[(1 - vert) as usize] = qr_fixed(self.v, 1) as i32;
self.qr.found_line(vert, line);
}
#[cfg(feature = "sqcode")]
pub(crate) fn sq_handler(&mut self) {
self.sq.set_enabled(self.is_enabled(SymbolType::SqCode));
}
fn scan_image_internal(&mut self, img: &mut ImageData) -> Vec<Symbol> {
#[cfg(feature = "qrcode")]
self.qr.reset();
#[cfg(feature = "sqcode")]
self.sq.reset();
self.syms.clear();
let w = img.width;
let h = img.height;
let data = img.data.as_slice();
self.new_scan();
let density = self.scanner_config.y_density;
if density > 0 {
let mut p = 0;
let mut x = 0i32;
let mut y = 0i32;
let mut border = ((h - 1) % density).div_ceil(2);
if border > h / 2 {
border = h / 2;
}
assert!(border <= h);
self.dy = 0;
y += border as i32;
p += (border * w) as isize;
self.v = y;
while (y as u32) < h {
self.dx = 1;
self.du = 1;
self.umin = 0;
while (x as u32) < w {
let d = data[p as usize];
x += 1;
p += 1;
self.scan_y(d as i32);
}
self.quiet_border();
x -= 1;
y += density as i32;
p += -1 + (density as i32 * w as i32) as isize;
self.v = y;
if (y as u32) >= h {
break;
}
self.dx = -1;
self.du = -1;
self.umin = w as i32;
while x >= 0 {
let d = data[p as usize];
x -= 1;
p -= 1;
self.scan_y(d as i32);
}
self.quiet_border();
x += 1;
y += density as i32;
p += 1 + (density as i32 * w as i32) as isize;
self.v = y;
}
}
self.dx = 0;
let density = self.scanner_config.x_density;
if density > 0 {
let mut p = 0;
let mut x = 0i32;
let mut y = 0i32;
let mut border = ((w - 1) % density).div_ceil(2);
if border > w / 2 {
border = w / 2;
}
assert!(border <= w);
x += border as i32;
p += border as isize;
self.v = x;
while (x as u32) < w {
self.dy = 1;
self.du = 1;
self.umin = 0;
while (y as u32) < h {
let d = data[p as usize];
y += 1;
p += w as isize;
self.scan_y(d as i32);
}
self.quiet_border();
x += density as i32;
y -= 1;
p += (density as isize) - (w as isize);
self.v = x;
if (x as u32) >= w {
break;
}
self.dy = -1;
self.du = -1;
self.umin = h as i32;
while y >= 0 {
let d = data[p as usize];
y -= 1;
p -= w as isize;
self.scan_y(d as i32);
}
self.quiet_border();
x += density as i32;
y += 1;
p += (density as isize) + (w as isize);
self.v = x;
}
}
self.dy = 0;
#[cfg(feature = "qrcode")]
{
let (qr_symbols, regions) = self.qr.decode(img);
for sym in qr_symbols {
self.add_symbol(sym);
}
self.last_qr_finder_regions = regions;
}
#[cfg(feature = "sqcode")]
{
self.sq_handler();
if let Ok(Some(symbol)) = self.sq.decode(img) {
self.add_symbol(symbol);
}
}
let filter = density == 1 || self.scanner_config.y_density == 1;
let scanner = &mut *self;
scanner.syms.retain(|sym| {
let sym_type = sym.symbol_type();
if (sym_type < SymbolType::Composite && sym_type > SymbolType::Partial)
|| sym_type == SymbolType::Databar
|| sym_type == SymbolType::DatabarExp
|| sym_type == SymbolType::Codabar
{
!((sym_type == SymbolType::Codabar || filter) && sym.quality < 4)
} else {
true
}
});
let mut nean = 0;
let mut naddon = 0;
for sym in &scanner.syms {
let sym_type = sym.symbol_type();
if sym_type < SymbolType::Composite && sym_type != SymbolType::Isbn10 {
if sym_type > SymbolType::Ean5 {
nean += 1;
} else if sym_type > SymbolType::Partial {
naddon += 1;
}
}
}
if nean == 1 && naddon == 1 && scanner.scanner_config.ean_composite {
let mut ean_sym: Option<Symbol> = None;
let mut addon_sym: Option<Symbol> = None;
let mut other_syms = Vec::new();
for sym in scanner.syms.drain(..) {
let sym_type = sym.symbol_type();
if sym_type < SymbolType::Composite && sym_type > SymbolType::Partial {
if sym_type <= SymbolType::Ean5 {
addon_sym = Some(sym);
} else {
ean_sym = Some(sym);
}
} else {
other_syms.push(sym);
}
}
if let (Some(ean), Some(addon)) = (ean_sym, addon_sym) {
other_syms.push(Symbol::composite(ean, addon));
}
scanner.syms = other_syms;
}
let mut symbols = vec![];
swap(&mut symbols, &mut scanner.syms);
symbols
}
pub(crate) fn symbol_handler(&mut self) {
let symbol_type = self.get_type();
let mut x = 0;
let mut y = 0;
#[cfg(feature = "qrcode")]
if symbol_type == SymbolType::QrCode {
self.qr_handler();
return;
}
#[cfg(not(feature = "qrcode"))]
if symbol_type == SymbolType::QrCode {
return;
}
let position_tracking = self.scanner_config.position_tracking;
if position_tracking {
let w = self.width();
let u = self.umin + self.du * self.get_edge(w, 0) as i32;
if self.dx != 0 {
x = u;
y = self.v;
} else {
x = self.v;
y = u;
}
}
if symbol_type <= SymbolType::Partial {
return;
}
let data_vec = self.buffer_slice().to_vec();
if let Some(sym) = self.find_duplicate_symbol(symbol_type, &data_vec) {
sym.quality += 1;
if position_tracking {
sym.add_point(x, y);
}
return;
}
let mut sym = Symbol::new(symbol_type);
sym.modifiers = self.get_modifiers();
sym.data.extend_from_slice(&data_vec);
if position_tracking {
sym.add_point(x, y);
}
let dir = self.direction;
if dir != 0 {
let base = if self.dy != 0 { 1 } else { 0 };
let offset = (self.du ^ dir) & 2;
sym.orientation = match base + offset {
0 => Orientation::Up,
1 => Orientation::Down,
2 => Orientation::Right,
3 => Orientation::Left,
_ => Orientation::Unknown,
};
}
self.add_symbol(sym);
}
}