use std::{ collections::{HashMap, HashSet}, io::Write, path::PathBuf, rc::Rc, }; use crate::{ common::{BitMatrix, HybridBinarizer}, multi::{GenericMultipleBarcodeReader, MultipleBarcodeReader}, BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, Luma8LuminanceSource, MultiFormatReader, RXingResult, Reader, }; #[cfg(feature = "image")] use crate::BufferedImageLuminanceSource; #[cfg(feature = "svg_read")] pub fn detect_in_svg( file_name: &str, barcode_type: Option, ) -> Result { detect_in_svg_with_hints(file_name, barcode_type, &mut HashMap::new()) } #[cfg(feature = "svg_read")] pub fn detect_in_svg_with_hints( file_name: &str, barcode_type: Option, hints: &mut DecodingHintDictionary, ) -> Result { use std::{fs::File, io::Read}; use crate::SVGLuminanceSource; let path = PathBuf::from(file_name); if !path.exists() { return Err(Exceptions::IllegalArgumentException(Some( "file does not exist".to_owned(), ))); } let Ok(mut file) = File::open(path) else { return Err(Exceptions::IllegalArgumentException(Some("file cannot be opened".to_owned()))); }; let mut svg_data = Vec::new(); if file.read_to_end(&mut svg_data).is_err() { return Err(Exceptions::IllegalArgumentException(Some( "file cannot be read".to_owned(), ))); } let mut multi_format_reader = MultiFormatReader::default(); if let Some(bc_type) = barcode_type { hints.insert( DecodeHintType::POSSIBLE_FORMATS, DecodeHintValue::PossibleFormats(HashSet::from([bc_type])), ); } hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); multi_format_reader.decode_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( SVGLuminanceSource::new(&svg_data)?, )))), hints, ) } #[cfg(feature = "svg_read")] pub fn detect_multiple_in_svg(file_name: &str) -> Result, Exceptions> { detect_multiple_in_svg_with_hints(file_name, &mut HashMap::new()) } #[cfg(feature = "svg_read")] pub fn detect_multiple_in_svg_with_hints( file_name: &str, hints: &mut DecodingHintDictionary, ) -> Result, Exceptions> { use std::{fs::File, io::Read}; use crate::SVGLuminanceSource; let path = PathBuf::from(file_name); if !path.exists() { return Err(Exceptions::IllegalArgumentException(Some( "file does not exist".to_owned(), ))); } let Ok(mut file) = File::open(path) else { return Err(Exceptions::IllegalArgumentException(Some("file cannot be opened".to_owned()))); }; let mut svg_data = Vec::new(); if file.read_to_end(&mut svg_data).is_err() { return Err(Exceptions::IllegalArgumentException(Some( "file cannot be read".to_owned(), ))); } let multi_format_reader = MultiFormatReader::default(); let mut scanner = GenericMultipleBarcodeReader::new(multi_format_reader); hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); scanner.decode_multiple_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( SVGLuminanceSource::new(&svg_data)?, )))), hints, ) } #[cfg(feature = "image")] pub fn detect_in_file( file_name: &str, barcode_type: Option, ) -> Result { detect_in_file_with_hints(file_name, barcode_type, &mut HashMap::new()) } #[cfg(feature = "image")] pub fn detect_in_file_with_hints( file_name: &str, barcode_type: Option, hints: &mut DecodingHintDictionary, ) -> Result { let Ok(img) = image::open(file_name) else { return Err(Exceptions::IllegalArgumentException(Some(format!("file '{file_name}' not found or cannot be opened")))); }; let mut multi_format_reader = MultiFormatReader::default(); if let Some(bc_type) = barcode_type { hints.insert( DecodeHintType::POSSIBLE_FORMATS, DecodeHintValue::PossibleFormats(HashSet::from([bc_type])), ); } hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); multi_format_reader.decode_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( BufferedImageLuminanceSource::new(img), )))), hints, ) } #[cfg(feature = "image")] pub fn detect_multiple_in_file(file_name: &str) -> Result, Exceptions> { detect_multiple_in_file_with_hints(file_name, &mut HashMap::new()) } #[cfg(feature = "image")] pub fn detect_multiple_in_file_with_hints( file_name: &str, hints: &mut DecodingHintDictionary, ) -> Result, Exceptions> { let img = image::open(file_name).unwrap(); let multi_format_reader = MultiFormatReader::default(); let mut scanner = GenericMultipleBarcodeReader::new(multi_format_reader); hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); scanner.decode_multiple_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( BufferedImageLuminanceSource::new(img), )))), hints, ) } pub fn detect_in_luma( luma: Vec, width: u32, height: u32, barcode_type: Option, ) -> Result { detect_in_luma_with_hints(luma, height, width, barcode_type, &mut HashMap::new()) } pub fn detect_in_luma_with_hints( luma: Vec, width: u32, height: u32, barcode_type: Option, hints: &mut DecodingHintDictionary, ) -> Result { let mut multi_format_reader = MultiFormatReader::default(); if let Some(bc_type) = barcode_type { hints.insert( DecodeHintType::POSSIBLE_FORMATS, DecodeHintValue::PossibleFormats(HashSet::from([bc_type])), ); } hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); multi_format_reader.decode_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( Luma8LuminanceSource::new(luma, width, height), )))), hints, ) } pub fn detect_multiple_in_luma( luma: Vec, width: u32, height: u32, ) -> Result, Exceptions> { detect_multiple_in_luma_with_hints(luma, width, height, &mut HashMap::new()) } pub fn detect_multiple_in_luma_with_hints( luma: Vec, width: u32, height: u32, hints: &mut DecodingHintDictionary, ) -> Result, Exceptions> { let multi_format_reader = MultiFormatReader::default(); let mut scanner = GenericMultipleBarcodeReader::new(multi_format_reader); hints .entry(DecodeHintType::TRY_HARDER) .or_insert(DecodeHintValue::TryHarder(true)); scanner.decode_multiple_with_hints( &mut BinaryBitmap::new(Rc::new(HybridBinarizer::new(Box::new( Luma8LuminanceSource::new(luma, width, height), )))), hints, ) } #[cfg(feature = "image")] pub fn save_image(file_name: &str, bit_matrix: &BitMatrix) -> Result<(), Exceptions> { let image: image::DynamicImage = bit_matrix.into(); match image.save(file_name) { Ok(_) => Ok(()), Err(err) => Err(Exceptions::IllegalArgumentException(Some(format!( "could not save file '{file_name}': {err}" )))), } } #[cfg(feature = "svg_write")] pub fn save_svg(file_name: &str, bit_matrix: &BitMatrix) -> Result<(), Exceptions> { let svg: svg::Document = bit_matrix.into(); match svg::save(file_name, &svg) { Ok(_) => Ok(()), Err(err) => Err(Exceptions::IllegalArgumentException(Some(format!( "could not save file '{}': {}", file_name, err )))), } } pub fn save_file(file_name: &str, bit_matrix: &BitMatrix) -> Result<(), Exceptions> { let path = PathBuf::from(file_name); #[allow(unused_variables)] let ext: String = if let Some(e) = path.extension() { e.to_string_lossy().to_string() } else { String::default() }; #[cfg(feature = "svg_write")] if ext == "svg" { return save_svg(file_name, bit_matrix); } #[cfg(feature = "image")] if !ext.is_empty() && ext != "txt" { return save_image(file_name, bit_matrix); } match || -> std::io::Result<_> { let file = std::fs::File::create(path)?; let mut output = std::io::BufWriter::new(file); output.write_all(bit_matrix.to_string().as_bytes())?; output.flush()?; Ok(()) }() { Ok(_) => Ok(()), Err(_) => Err(Exceptions::IllegalArgumentException(Some(format!( "could not write to '{file_name}'" )))), } }