From 29722b6fb26ecbd33a21d0386f6c694e247fbff5 Mon Sep 17 00:00:00 2001
From: Sameer Puri
Date: Thu, 1 Jun 2023 17:05:22 -0700
Subject: [PATCH] web: zip for batch processing, resolves #39
---
Cargo.lock | 30 ++++++++++++++
web/Cargo.toml | 1 +
web/src/main.rs | 107 ++++++++++++++++++++++++++++++++++--------------
3 files changed, 108 insertions(+), 30 deletions(-)
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") }
+
+
+ )
+ }
+ disabled={generate_disabled}
+ onclick={generate_onclick}
+ />
+
+
{
for app_store.svgs.iter().enumerate().map(|(i, svg)| {
@@ -155,26 +222,6 @@ fn App(_props: &()) -> Html {
})
}
-
-
- )
- }
- disabled={generate_disabled}
- onclick={generate_onclick}
- />
-
-