diff --git a/.gitignore b/.gitignore index cb8c9e0..b6b9fae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -.direnv \ No newline at end of file +.direnv +output.svg \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 3226484..323df3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,243 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "askama" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94" +dependencies = [ + "basic-toml", + "mime", + "mime_guess", + "nom", + "proc-macro2", + "quote", + "serde", + "syn 2.0.28", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "basic-toml" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + [[package]] name = "dyesub-tool" version = "0.1.0" +dependencies = [ + "askama", + "derive_more", +] + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml index 06f08e8..20dab38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["dyesub-tool"] \ No newline at end of file +members = ["dyesub-tool"] diff --git a/dyesub-tool/Cargo.toml b/dyesub-tool/Cargo.toml index d032fce..1ff22f0 100644 --- a/dyesub-tool/Cargo.toml +++ b/dyesub-tool/Cargo.toml @@ -3,6 +3,6 @@ name = "dyesub-tool" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +askama = "0.12.0" +derive_more = "0.99.17" diff --git a/dyesub-tool/src/main.rs b/dyesub-tool/src/main.rs index e7a11a9..dd455cd 100644 --- a/dyesub-tool/src/main.rs +++ b/dyesub-tool/src/main.rs @@ -1,3 +1,33 @@ -fn main() { - println!("Hello, world!"); +pub mod svg; +use svg::*; + +use std::{fs::OpenOptions, io::Write}; +use askama::Template; +use derive_more::From; + +#[derive(Template)] +#[template(path = "document.xml")] +struct DocumentTemplate { + width: SVGMeasure, + height: SVGMeasure, +} + +#[derive(From, Debug)] +enum Error { + Io(std::io::Error), + Template(askama::Error), +} + +fn main() -> Result<(), Error> { + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open("output.svg")?; + let document = DocumentTemplate { + width: SVGMeasure::new(8.5, SVGUnit::Inch), + height: SVGMeasure::new(11.0,SVGUnit::Inch), + }; + write!(file, "{}", document.render()?)?; + Ok(()) } diff --git a/dyesub-tool/src/svg/measure.rs b/dyesub-tool/src/svg/measure.rs new file mode 100644 index 0000000..6750efc --- /dev/null +++ b/dyesub-tool/src/svg/measure.rs @@ -0,0 +1,52 @@ +use super::SVGUnit; +use std::fmt; +use std::{ops::{Add, Sub, Mul, Div}, fmt::Display}; + +pub struct SVGMeasure { + pub measure: f64, + pub unit: SVGUnit, +} + +impl SVGMeasure { + pub fn new(measure: f64, unit: SVGUnit) -> Self { + Self { measure, unit } + } +} + +impl Display for SVGMeasure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{}", self.measure, self.unit) + } +} + +impl Add for SVGMeasure { + type Output = Self; + + fn add(self, other: SVGMeasure) -> SVGMeasure { + SVGMeasure::new(self.measure + other.measure, self.unit) + } +} + +impl Sub for SVGMeasure { + type Output = Self; + + fn sub(self, other: SVGMeasure) -> SVGMeasure { + SVGMeasure::new(self.measure - other.measure, self.unit) + } +} + +impl Mul for SVGMeasure { + type Output = Self; + + fn mul(self, scalar: f64) -> SVGMeasure { + SVGMeasure::new(self.measure * scalar, self.unit) + } +} + +impl Div for SVGMeasure { + type Output = Self; + + fn div(self, scalar: f64) -> SVGMeasure { + SVGMeasure::new(self.measure / scalar, self.unit) + } +} \ No newline at end of file diff --git a/dyesub-tool/src/svg/mod.rs b/dyesub-tool/src/svg/mod.rs new file mode 100644 index 0000000..3c500f1 --- /dev/null +++ b/dyesub-tool/src/svg/mod.rs @@ -0,0 +1,5 @@ +mod unit; +pub use unit::SVGUnit; + +mod measure; +pub use measure::SVGMeasure; \ No newline at end of file diff --git a/dyesub-tool/src/svg/unit.rs b/dyesub-tool/src/svg/unit.rs new file mode 100644 index 0000000..6c4ef9a --- /dev/null +++ b/dyesub-tool/src/svg/unit.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display}; + +/// https://oreillymedia.github.io/Using_SVG/guide/units.html +pub enum SVGUnit { + /// Pixel units, directly equivalent to SVG user units. + Pixel, + /// Inches. + Inch, + /// Centimeters. + Centimeter, + /// Millimeters. + Millimeter, + /// Points. + Point, + // Picas. + Pica, + /// Em units. Equivalent to the computed font-size in effect for an element. + Em, + /// Ex units. Equivalent to the height of a lower-case letter in the font (and font-size) in effect for an element. If the font doesn’t include lower-case letters, or doesn’t include the metadata about the ex-height, then 1ex = 0.5em. + Ex, + /// Character units. Equivalent to the width of the `0` (zero) character in the font and font-size in effect for an element. + Character, + /// Root-em units. The font size of the root element in the document, regardless of any settings for the current element. + Rem, + /// Viewport width units. 1% of the viewport width. + ViewportWidth, + /// Viewport height units. 1% of the viewport height. + ViewportHeight, + /// Viewport minimum units. 1% of the viewport width or height, whichever is smaller. + ViewportMinimum, + /// Viewport maximum units. 1% of the viewport width or height, whichever is larger. + ViewportMaximum, +} + +impl Display for SVGUnit { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use SVGUnit::*; + write!(f, "{}", match &self { + Pixel => "px", + Inch => "in", + Centimeter => "cm", + Millimeter => "mm", + Point => "pt", + Pica => "pc", + Em => "em", + Ex => "ex", + Character => "ch", + Rem => "rem", + ViewportWidth => "vw", + ViewportHeight => "vh", + ViewportMinimum => "vmin", + ViewportMaximum => "vmax", + }) + } +} \ No newline at end of file diff --git a/dyesub-tool/templates/document.xml b/dyesub-tool/templates/document.xml new file mode 100644 index 0000000..d555166 --- /dev/null +++ b/dyesub-tool/templates/document.xml @@ -0,0 +1,5 @@ + + + diff --git a/flake.nix b/flake.nix index f25a342..98edfdf 100644 --- a/flake.nix +++ b/flake.nix @@ -51,7 +51,7 @@ Updating `cargoHash`: pname = "dyesub-tool"; version = "0.1.0"; buildAndTestSubdir = "dyesub-tool"; - cargoHash = "sha256-hFxEu/sPAxrjOpXqSPDucOqmgsOjb6YBxnWeVl4MV74="; + cargoHash = "sha256-owoTOMY/u7K3Y96FIHXMJeqILAOFR2wSYozzsT+0p64="; meta = meta // { description = "A tool for generating dye sublimation transfer sheet SVGs for Japanese thumb shift 拇指シフト keycaps."; };