diff --git a/Cargo.lock b/Cargo.lock index e1987f0..100257f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,6 +286,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + [[package]] name = "darling" version = "0.13.4" @@ -1297,6 +1315,7 @@ dependencies = [ "web-sys", "yew", "yewdux", + "zip", ] [[package]] @@ -1849,3 +1868,14 @@ dependencies = [ "quote", "syn 1.0.109", ] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", +] diff --git a/web/Cargo.toml b/web/Cargo.toml index d55e480..5d3b53a 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4" svgtypes = "0.11" serde_json = "1" thiserror = "1.0" +zip = { version = "0.6", default-features = false } yew = { version ="0.20", features = ["csr"] } yewdux = "0.9.2" diff --git a/web/src/main.rs b/web/src/main.rs index c9cc452..e7d5911 100644 --- a/web/src/main.rs +++ b/web/src/main.rs @@ -1,10 +1,14 @@ -use std::path::Path; +use std::{ + io::Cursor, + path::{Path, PathBuf}, +}; use base64::Engine; use g_code::{ - emit::{format_gcode_fmt, FormatOptions}, + emit::{format_gcode_fmt, format_gcode_io, FormatOptions}, parse::snippet_parser, }; +use js_sys::Date; use log::Level; use roxmltree::Document; use svg2gcode::{svg2program, ConversionOptions, Machine}; @@ -20,6 +24,7 @@ use state::*; use ui::*; use util::*; use yewdux::prelude::{use_store, Dispatch}; +use zip::{write::FileOptions, CompressionMethod, ZipWriter}; #[function_component] fn App(_props: &()) -> Html { @@ -45,6 +50,13 @@ fn App(_props: &()) -> Html { let app_store = app_store.clone(); Callback::from(move |_| { generating_setter.set(true); + let mut zip = ZipWriter::new(Cursor::new(vec![])); + let opts = FileOptions::default().compression_method(CompressionMethod::Stored); + + if app_store.svgs.len() > 1 { + zip.add_directory("svg2gcode_output", opts.clone()).unwrap(); + } + for svg in app_store.svgs.iter() { let options = ConversionOptions { dimensions: svg.dimensions, @@ -90,24 +102,59 @@ fn App(_props: &()) -> Html { let program = svg2program(&document, &app_store.settings.conversion, options, machine); - let gcode = { - let mut acc: String = String::new(); - format_gcode_fmt( + let filepath = if app_store.svgs.len() > 1 { + PathBuf::from("svg2gcode_output") + .join(Path::new(svg.filename.as_str()).with_extension("gcode")) + } else { + Path::new(svg.filename.as_str()).with_extension("gcode") + }; + + if app_store.svgs.len() > 1 { + zip.start_file(filepath.to_string_lossy(), opts.clone()) + .unwrap(); + + format_gcode_io( &program, FormatOptions { checksums: app_store.settings.postprocess.checksums, line_numbers: app_store.settings.postprocess.line_numbers, ..Default::default() }, - &mut acc, + &mut zip, ) .unwrap(); - acc - }; + } else if app_store.svgs.len() == 1 { + let gcode = { + let mut acc = String::new(); + format_gcode_fmt( + &program, + FormatOptions { + checksums: app_store.settings.postprocess.checksums, + line_numbers: app_store.settings.postprocess.line_numbers, + ..Default::default() + }, + &mut acc, + ) + .unwrap(); + acc + }; + prompt_download(filepath, gcode.as_bytes()); + } + } - let filepath = Path::new(svg.filename.as_str()).with_extension("gcode"); - prompt_download(filepath, gcode.as_bytes()); + if app_store.svgs.len() > 1 { + zip.set_comment(format!( + "Created with svg2gcode: https://sameer.github.io/svg2gcode/\n{}", + env!("CARGO_PKG_DESCRIPTION") + )); + let output = zip.finish().unwrap(); + let date = Date::new_0().to_iso_string(); + prompt_download( + format!("svg2gcode_bulk_download_{date}.zip"), + output.get_ref(), + ); } + generating_setter.set(false); }) }; @@ -122,6 +169,26 @@ fn App(_props: &()) -> Html { { env!("CARGO_PKG_DESCRIPTION") }

+ +