#[cfg(not(all(
feature = "qrcode",
feature = "sqcode",
feature = "ean",
feature = "code128",
feature = "code39",
feature = "code93",
feature = "codabar",
feature = "databar",
feature = "i25"
)))]
compile_error!(
"zedbarimg binary requires all symbology features enabled. \
Build with default features: `cargo build --bin zedbarimg` \
For a minimal library, use: `cargo build --lib --no-default-features --features qrcode`"
);
use clap::Parser;
use std::io::Write;
use std::process;
use zedbar::{DecoderConfig, Image, Scanner, config::*};
#[derive(Parser)]
#[command(name = "zedbarimg")]
#[command(version)]
#[command(about = "Scan and decode bar codes from one or more image files", long_about = None)]
struct Args {
#[arg(short, long)]
quiet: bool,
#[arg(long)]
raw: bool,
#[arg(long)]
disable_all: bool,
#[arg(long)]
enable_ean13: bool,
#[arg(long)]
enable_ean8: bool,
#[arg(long)]
enable_ean2: bool,
#[arg(long)]
enable_ean5: bool,
#[arg(long)]
enable_upca: bool,
#[arg(long)]
enable_upce: bool,
#[arg(long)]
enable_isbn10: bool,
#[arg(long)]
enable_isbn13: bool,
#[arg(long)]
enable_code39: bool,
#[arg(long)]
enable_code93: bool,
#[arg(long)]
enable_code128: bool,
#[arg(long)]
enable_i25: bool,
#[arg(long)]
enable_codabar: bool,
#[arg(long)]
enable_databar: bool,
#[arg(long)]
enable_databar_exp: bool,
#[arg(long)]
enable_qr: bool,
#[arg(long)]
enable_sq: bool,
#[arg(long)]
disable_ean13: bool,
#[arg(long)]
disable_ean8: bool,
#[arg(long)]
disable_code39: bool,
#[arg(long)]
disable_code93: bool,
#[arg(long)]
disable_code128: bool,
#[arg(long)]
disable_qr: bool,
#[arg(required = true)]
files: Vec<String>,
}
fn main() {
let args = Args::parse();
let config = if args.disable_all {
let mut cfg = DecoderConfig::new().disable_all();
if args.enable_ean13 {
cfg = cfg.enable(Ean13);
}
if args.enable_ean8 {
cfg = cfg.enable(Ean8);
}
if args.enable_ean2 {
cfg = cfg.enable(Ean2);
}
if args.enable_ean5 {
cfg = cfg.enable(Ean5);
}
if args.enable_upca {
cfg = cfg.enable(Upca);
}
if args.enable_upce {
cfg = cfg.enable(Upce);
}
if args.enable_isbn10 {
cfg = cfg.enable(Isbn10);
}
if args.enable_isbn13 {
cfg = cfg.enable(Isbn13);
}
if args.enable_code39 {
cfg = cfg.enable(Code39);
}
if args.enable_code93 {
cfg = cfg.enable(Code93);
}
if args.enable_code128 {
cfg = cfg.enable(Code128);
}
if args.enable_i25 {
cfg = cfg.enable(I25);
}
if args.enable_codabar {
cfg = cfg.enable(Codabar);
}
if args.enable_databar {
cfg = cfg.enable(Databar);
}
if args.enable_databar_exp {
cfg = cfg.enable(DatabarExp);
}
if args.enable_qr {
cfg = cfg.enable(QrCode);
}
if args.enable_sq {
cfg = cfg.enable(SqCode);
}
cfg
} else {
let mut cfg = DecoderConfig::new();
if args.enable_ean13 {
cfg = cfg.enable(Ean13);
}
if args.enable_ean8 {
cfg = cfg.enable(Ean8);
}
if args.enable_ean2 {
cfg = cfg.enable(Ean2);
}
if args.enable_ean5 {
cfg = cfg.enable(Ean5);
}
if args.enable_upca {
cfg = cfg.enable(Upca);
}
if args.enable_upce {
cfg = cfg.enable(Upce);
}
if args.enable_isbn10 {
cfg = cfg.enable(Isbn10);
}
if args.enable_isbn13 {
cfg = cfg.enable(Isbn13);
}
if args.enable_code39 {
cfg = cfg.enable(Code39);
}
if args.enable_code93 {
cfg = cfg.enable(Code93);
}
if args.enable_code128 {
cfg = cfg.enable(Code128);
}
if args.enable_i25 {
cfg = cfg.enable(I25);
}
if args.enable_codabar {
cfg = cfg.enable(Codabar);
}
if args.enable_databar {
cfg = cfg.enable(Databar);
}
if args.enable_databar_exp {
cfg = cfg.enable(DatabarExp);
}
if args.enable_qr {
cfg = cfg.enable(QrCode);
}
if args.enable_sq {
cfg = cfg.enable(SqCode);
}
if args.disable_ean13 {
cfg = cfg.disable(Ean13);
}
if args.disable_ean8 {
cfg = cfg.disable(Ean8);
}
if args.disable_code39 {
cfg = cfg.disable(Code39);
}
if args.disable_code93 {
cfg = cfg.disable(Code93);
}
if args.disable_code128 {
cfg = cfg.disable(Code128);
}
if args.disable_qr {
cfg = cfg.disable(QrCode);
}
cfg
};
let mut total_symbols = 0;
for filename in &args.files {
let img = match ::image::ImageReader::open(filename) {
Ok(reader) => match reader.decode() {
Ok(img) => img,
Err(e) => {
if !args.quiet {
eprintln!("Failed to decode image '{}': {}", filename, e);
}
process::exit(1);
}
},
Err(e) => {
if !args.quiet {
eprintln!("Failed to open image '{}': {}", filename, e);
}
process::exit(1);
}
};
let gray = img.to_luma8();
let (width, height) = gray.dimensions();
let data = gray.as_raw();
let mut zedbar_img = match Image::from_gray(data, width, height) {
Ok(img) => img,
Err(e) => {
if !args.quiet {
eprintln!("Failed to create zedbar image: {}", e);
}
process::exit(1);
}
};
let mut scanner = Scanner::with_config(config.clone());
let symbols = scanner.scan(&mut zedbar_img);
total_symbols += symbols.len();
for symbol in symbols {
let symbol_type = symbol.symbol_type();
let data_bytes = symbol.data();
if args.raw {
let raw_bytes = symbol.raw_data().unwrap_or(data_bytes);
std::io::stdout().write_all(raw_bytes).ok();
println!();
} else {
if let Ok(data_str) = std::str::from_utf8(data_bytes) {
println!("{:?}:{}", symbol_type, data_str);
} else {
print!("{:?}:", symbol_type);
std::io::stdout().write_all(data_bytes).ok();
println!();
}
}
}
}
if !args.quiet {
if total_symbols == 0 {
eprintln!("No barcodes found");
process::exit(1);
} else {
eprintln!(
"scanned {} barcode symbols from {} image(s)",
total_symbols,
args.files.len()
);
}
} else if total_symbols == 0 {
process::exit(1);
}
}