Files
rxing/src/helpers.rs
2023-01-27 15:24:24 -06:00

309 lines
9.0 KiB
Rust

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<BarcodeFormat>,
) -> Result<RXingResult, Exceptions> {
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<BarcodeFormat>,
hints: &mut DecodingHintDictionary,
) -> Result<RXingResult, 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 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<Vec<RXingResult>, 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<Vec<RXingResult>, 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<BarcodeFormat>,
) -> Result<RXingResult, Exceptions> {
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<BarcodeFormat>,
hints: &mut DecodingHintDictionary,
) -> Result<RXingResult, Exceptions> {
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<Vec<RXingResult>, 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<Vec<RXingResult>, 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<u8>,
width: u32,
height: u32,
barcode_type: Option<BarcodeFormat>,
) -> Result<RXingResult, Exceptions> {
detect_in_luma_with_hints(luma, height, width, barcode_type, &mut HashMap::new())
}
pub fn detect_in_luma_with_hints(
luma: Vec<u8>,
width: u32,
height: u32,
barcode_type: Option<BarcodeFormat>,
hints: &mut DecodingHintDictionary,
) -> Result<RXingResult, Exceptions> {
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<u8>,
width: u32,
height: u32,
) -> Result<Vec<RXingResult>, Exceptions> {
detect_multiple_in_luma_with_hints(luma, width, height, &mut HashMap::new())
}
pub fn detect_multiple_in_luma_with_hints(
luma: Vec<u8>,
width: u32,
height: u32,
hints: &mut DecodingHintDictionary,
) -> Result<Vec<RXingResult>, 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}'"
)))),
}
}