diff --git a/Cargo.toml b/Cargo.toml index f3d36b5..f9155ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,12 +29,14 @@ codepage-437 = "0.1.0" rxing-one-d-proc-derive = "0.3.0" #rxing-one-d-proc-derive = {path ="../rxing-one-d-proc-derive"} num = "0.4.0" +svg = {version = "0.13", optional = true} [dev-dependencies] java-properties = "1.4.1" java-rand = "0.2.0" [features] -default = ["image"] +default = ["image", "svg_write"] image = ["dep:image", "dep:imageproc"] allow_forced_iso_ied_18004_compliance = [] +svg_write = ["dep:svg"] diff --git a/src/common/bit_matrix.rs b/src/common/bit_matrix.rs index dcfe994..1861671 100644 --- a/src/common/bit_matrix.rs +++ b/src/common/bit_matrix.rs @@ -679,30 +679,44 @@ impl From<&BitMatrix> for image::DynamicImage { fn from(value: &BitMatrix) -> Self { let mut pixels = image::ImageBuffer::new(value.width, value.height); - for y in 0..value.height { - for x in 0..value.width { - let pixel_value = if value.get(x, y) { u8::MIN } else { u8::MAX }; - let pixel_intrior = [pixel_value, pixel_value, pixel_value]; - let pixel = image::Rgb(pixel_intrior); - pixels.put_pixel(x, y, pixel); - } + for (x, y, pixel) in pixels.enumerate_pixels_mut() { + let new_pixel = if value.get(x as u32, y as u32) { + image::Rgb([0, 0, 0]) + } else { + image::Rgb([u8::MAX, u8::MAX, u8::MAX]) + }; + *pixel = new_pixel } + pixels.into() } } -// impl From for Vec { -// fn from(value: BitMatrix) -> Self { -// let mut output_vector = Vec::new(); -// for y in 0..value.getHeight() { -// for col in (0..value.getWidth()).step_by(8) { -// let mut byte = 0_u8; -// for x in 0..8 { -// byte |= u8::from(value.get(col+x, y)) << x -// } -// output_vector.push(byte); -// } -// } -// output_vector -// } -// } +#[cfg(feature = "svg_write")] +impl From<&BitMatrix> for svg::Document { + fn from(value: &BitMatrix) -> Self { + let block_size = 1; + let mut document = svg::Document::new().set( + "viewBox", + ( + 0, + 0, + value.width as u32 * block_size, + value.height as u32 * block_size, + ), + ); + for x in 0..value.width { + for y in 0..value.height { + if value.get(x, y) { + let block = svg::node::element::Rectangle::new() + .set("x", x * block_size) + .set("y", y * block_size) + .set("width", block_size) + .set("height", block_size); + document = document.add(block); + } + } + } + document + } +} diff --git a/src/helpers.rs b/src/helpers.rs index b1c2232..b84f45e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,7 @@ use std::{ collections::{HashMap, HashSet}, + io::Write, + path::PathBuf, rc::Rc, }; @@ -152,3 +154,50 @@ pub fn save_image(file_name: &str, bit_matrix: &BitMatrix) -> Result<(), Excepti )))), } } + +#[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); + + 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 + )))), + } +}