mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
add svg_read support (basic)
This commit is contained in:
10
Cargo.toml
10
Cargo.toml
@@ -23,20 +23,22 @@ uriparse = "0.6.4"
|
|||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
chrono-tz = "0.8"
|
chrono-tz = "0.8"
|
||||||
image = {version = "0.24", optional = true}
|
image = {version = "0.24", optional = true}
|
||||||
imageproc = {version = "0.23.0", optional = true}
|
imageproc = {version = "0.23", optional = true}
|
||||||
unicode-segmentation = "1.10.0"
|
unicode-segmentation = "1.10"
|
||||||
codepage-437 = "0.1.0"
|
codepage-437 = "0.1.0"
|
||||||
rxing-one-d-proc-derive = "0.3.0"
|
rxing-one-d-proc-derive = "0.3"
|
||||||
#rxing-one-d-proc-derive = {path ="../rxing-one-d-proc-derive"}
|
#rxing-one-d-proc-derive = {path ="../rxing-one-d-proc-derive"}
|
||||||
num = "0.4.0"
|
num = "0.4.0"
|
||||||
svg = {version = "0.13", optional = true}
|
svg = {version = "0.13", optional = true}
|
||||||
|
resvg = {version = "0.28.0", optional = true, default-features=false}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
java-properties = "1.4.1"
|
java-properties = "1.4.1"
|
||||||
java-rand = "0.2.0"
|
java-rand = "0.2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["image", "svg_write"]
|
default = ["image", "svg_write", "svg_read"]
|
||||||
image = ["dep:image", "dep:imageproc"]
|
image = ["dep:image", "dep:imageproc"]
|
||||||
allow_forced_iso_ied_18004_compliance = []
|
allow_forced_iso_ied_18004_compliance = []
|
||||||
svg_write = ["dep:svg"]
|
svg_write = ["dep:svg"]
|
||||||
|
svg_read = ["dep:resvg", "image"]
|
||||||
|
|||||||
104
src/helpers.rs
104
src/helpers.rs
@@ -13,6 +13,110 @@ use crate::{
|
|||||||
Reader,
|
Reader,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[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")]
|
#[cfg(feature = "image")]
|
||||||
pub fn detect_in_file(
|
pub fn detect_in_file(
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub use buffered_image_luminance_source::*;
|
|||||||
mod PlanarYUVLuminanceSourceTestCase;
|
mod PlanarYUVLuminanceSourceTestCase;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod RGBLuminanceSourceTestCase;
|
mod rgb_luminance_source_test_case;
|
||||||
|
|
||||||
pub type EncodingHintDictionary = HashMap<EncodeHintType, EncodeHintValue>;
|
pub type EncodingHintDictionary = HashMap<EncodeHintType, EncodeHintValue>;
|
||||||
pub type DecodingHintDictionary = HashMap<DecodeHintType, DecodeHintValue>;
|
pub type DecodingHintDictionary = HashMap<DecodeHintType, DecodeHintValue>;
|
||||||
@@ -99,3 +99,8 @@ pub mod helpers;
|
|||||||
|
|
||||||
mod luma_luma_source;
|
mod luma_luma_source;
|
||||||
pub use luma_luma_source::*;
|
pub use luma_luma_source::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "svg_read")]
|
||||||
|
mod svg_luminance_source;
|
||||||
|
#[cfg(feature = "svg_read")]
|
||||||
|
pub use svg_luminance_source::*;
|
||||||
|
|||||||
85
src/svg_luminance_source.rs
Normal file
85
src/svg_luminance_source.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use crate::{BufferedImageLuminanceSource, Exceptions, LuminanceSource};
|
||||||
|
use image::{DynamicImage, RgbaImage};
|
||||||
|
use resvg::{self, usvg::Options};
|
||||||
|
|
||||||
|
pub struct SVGLuminanceSource(BufferedImageLuminanceSource);
|
||||||
|
|
||||||
|
impl LuminanceSource for SVGLuminanceSource {
|
||||||
|
fn getRow(&self, y: usize) -> Vec<u8> {
|
||||||
|
self.0.getRow(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getMatrix(&self) -> Vec<u8> {
|
||||||
|
self.0.getMatrix()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getWidth(&self) -> usize {
|
||||||
|
self.0.getWidth()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getHeight(&self) -> usize {
|
||||||
|
self.0.getHeight()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invert(&mut self) {
|
||||||
|
self.0.invert()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isCropSupported(&self) -> bool {
|
||||||
|
self.0.isCropSupported()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn crop(
|
||||||
|
&self,
|
||||||
|
left: usize,
|
||||||
|
top: usize,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
) -> Result<Box<dyn LuminanceSource>, Exceptions> {
|
||||||
|
self.0.crop(left, top, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isRotateSupported(&self) -> bool {
|
||||||
|
self.0.isRotateSupported()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotateCounterClockwise(&self) -> Result<Box<dyn LuminanceSource>, Exceptions> {
|
||||||
|
self.0.rotateCounterClockwise()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotateCounterClockwise45(&self) -> Result<Box<dyn LuminanceSource>, Exceptions> {
|
||||||
|
self.0.rotateCounterClockwise45()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SVGLuminanceSource {
|
||||||
|
pub fn new(svg_data: &[u8]) -> Result<Self, Exceptions> {
|
||||||
|
// Load the SVG file
|
||||||
|
let Ok(tree) = resvg::usvg::Tree::from_data(svg_data, &Options::default()) else {
|
||||||
|
return Err(Exceptions::FormatException(Some(format!("could not parse svg data: {}", "err"))));
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(mut pixmap) = resvg::tiny_skia::Pixmap::new(tree.size.width() as u32, tree.size.height() as u32) else {
|
||||||
|
return Err(Exceptions::FormatException(Some("could not create pixmap".to_owned())));
|
||||||
|
};
|
||||||
|
|
||||||
|
resvg::render(
|
||||||
|
&tree,
|
||||||
|
resvg::usvg::FitTo::Original,
|
||||||
|
resvg::tiny_skia::Transform::default(),
|
||||||
|
pixmap.as_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(buffer) = RgbaImage::from_raw(tree.size.width() as u32, tree.size.height() as u32, pixmap.data().to_vec()) else {
|
||||||
|
return Err(Exceptions::FormatException(Some("could not create image buffer".to_owned())));
|
||||||
|
};
|
||||||
|
|
||||||
|
// let Ok(image) = image::load_from_memory_with_format(pixmap.data(), image::ImageFormat::Bmp) else {
|
||||||
|
// return Err(Exceptions::FormatException(Some("could not generate image".to_owned())));
|
||||||
|
// };
|
||||||
|
|
||||||
|
Ok(Self(BufferedImageLuminanceSource::new(DynamicImage::from(
|
||||||
|
buffer,
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user