Browse Source

refactor drawing to work from thyme representation

Getty Ritter 3 months ago
parent
commit
82b6236550
6 changed files with 133 additions and 19 deletions
  1. 6 2
      Cargo.toml
  2. 0 1
      src/data.rs
  3. 15 13
      src/draw.rs
  4. 44 3
      src/file.rs
  5. 45 0
      tools/svg-from-thyme/main.rs
  6. 23 0
      tools/svg-from-thyme/opts.rs

+ 6 - 2
Cargo.toml

@@ -22,9 +22,13 @@ zip = "*"
 name = "thyme-from-png"
 path = "tools/thyme-from-png/main.rs"
 
+# [[bin]]
+# name = "svg-from-png"
+# path = "tools/svg-from-png/main.rs"
+
 [[bin]]
-name = "svg-from-png"
-path = "tools/svg-from-png/main.rs"
+name = "svg-from-thyme"
+path = "tools/svg-from-thyme/main.rs"
 
 [[bin]]
 name = "thyme-editor"

+ 0 - 1
src/data.rs

@@ -60,7 +60,6 @@ impl Mapping {
                 Ok((c, e))
             })
             .collect::<Result<HashMap<Pixel, Option<ColorEntry>>, Box<dyn std::error::Error>>>()?;
-        println!("{:?}", color_map);
         let all_image_colors = img
             .iter()
             .map(|(_, color)| color)

+ 15 - 13
src/draw.rs

@@ -1,14 +1,18 @@
-use crate::data::{Config, Mapping};
-use crate::image::Image;
+use crate::data::Config;
+use crate::file::ThymeFile;
 
 pub struct Pattern {
-    pub image: Image,
+    pub thyme: ThymeFile,
+    // pub image: Image,
     pub config: Config,
-    pub mapping: Mapping,
+    // pub mapping: Mapping,
 }
 
 impl Pattern {
     pub fn draw(&self, ctx: cairo::Context) -> Result<(), Box<dyn std::error::Error>> {
+        let width = self.thyme.width;
+        let height = self.thyme.height;
+
         ctx.set_source_rgb(1.0, 1.0, 1.0);
         ctx.paint()?;
 
@@ -18,9 +22,9 @@ impl Pattern {
         layout.set_font_description(Some(&font));
 
         ctx.set_source_rgb(0.0, 0.0, 0.0);
-        for i in 0..=self.image.width {
+        for i in 0..=width {
             ctx.move_to(self.config.scale(i), 0.0);
-            ctx.line_to(self.config.scale(i), self.config.scale(self.image.height));
+            ctx.line_to(self.config.scale(i), self.config.scale(height));
             ctx.set_line_width(if i % self.config.grid_every == 0 {
                 self.config.major_line_weight
             } else {
@@ -28,9 +32,9 @@ impl Pattern {
             });
             ctx.stroke()?;
         }
-        for j in 0..=self.image.height {
+        for j in 0..=height {
             ctx.move_to(0.0, self.config.scale(j));
-            ctx.line_to(self.config.scale(self.image.width), self.config.scale(j));
+            ctx.line_to(self.config.scale(width), self.config.scale(j));
             ctx.set_line_width(if j % self.config.grid_every == 0 {
                 self.config.major_line_weight
             } else {
@@ -41,12 +45,10 @@ impl Pattern {
 
         ctx.set_source_rgb(0.0, 0.0, 0.0);
 
-        for ((x, y), pixel) in self.image.iter() {
-            let l = self.mapping.lookup(pixel);
-
-            if !l.is_empty() {
+        for ((x, y), stitch) in self.thyme.iter() {
+            if let Some((_, color)) = stitch {
                 ctx.move_to(self.config.scale(x) + 5.0, self.config.scale(y) + 3.0);
-                layout.set_text(l);
+                layout.set_text(&color.symbol);
                 pangocairo::functions::show_layout(&ctx, &layout);
             }
         }

+ 44 - 3
src/file.rs

@@ -8,7 +8,7 @@ use std::io::{Read, Seek, Write};
 
 const CURRENT_VERSION: &'static str = "0";
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
 pub enum StitchType {
     Normal,
     HalfUp,
@@ -34,6 +34,7 @@ pub struct Stitch {
 #[derive(Debug, Serialize, Deserialize)]
 pub struct Color {
     pub name: String,
+    pub symbol: String,
     pub color: Pixel,
 }
 
@@ -66,6 +67,7 @@ impl ThymeFile {
                 palette.push(Color {
                     color: *color,
                     name: i.name.to_owned(),
+                    symbol: i.symbol.to_owned(),
                 });
                 lookup.insert(color, idx);
             }
@@ -73,8 +75,7 @@ impl ThymeFile {
 
         let payload = image
             .iter()
-            .map(|(idx, pixel)| {
-                println!("{:?}: => {:?}", idx, lookup.get(&pixel));
+            .map(|(_idx, pixel)| {
                 if let Some(color) = lookup.get(&pixel) {
                     Some(Stitch {
                         color: *color,
@@ -214,6 +215,16 @@ impl ThymeFile {
             })
             .collect()
     }
+
+    pub fn iter<'a>(&'a self) -> ThymeImageIterator<'a> {
+        ThymeImageIterator {
+            palette: &self.palette,
+            x: 0,
+            y: 0,
+            width: self.width,
+            values: self.payload.iter(),
+        }
+    }
 }
 
 // internal structs for serializing/deserializing the image part
@@ -240,3 +251,33 @@ impl IntermediateStitch {
         })
     }
 }
+
+pub struct ThymeImageIterator<'a> {
+    width: u32,
+    x: u32,
+    y: u32,
+    palette: &'a [Color],
+    values: std::slice::Iter<'a, Option<Stitch>>,
+}
+
+impl<'a> Iterator for ThymeImageIterator<'a> {
+    type Item = ((u32, u32), Option<(StitchType, &'a Color)>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let px = self.values.next();
+        if let Some(px) = px {
+            let r = px.as_ref().map(|stitch| {
+                (stitch.typ, &self.palette[stitch.color.idx as usize])
+            });
+            let ret = ((self.x, self.y), r);
+            self.x += 1;
+            if self.x == self.width {
+                self.x = 0;
+                self.y += 1;
+            }
+            Some(ret)
+        } else {
+            None
+        }
+    }
+}

+ 45 - 0
tools/svg-from-thyme/main.rs

@@ -0,0 +1,45 @@
+mod opts;
+
+use crate::opts::Options;
+use clap::Parser;
+use thyme::{
+    file::ThymeFile,
+    data::Config,
+    draw::Pattern,
+};
+use std::fs::File;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    // read the command-line options
+    let opts = Options::parse();
+
+    // load the thyme file
+    let thyme = {
+        let mut f = File::open(opts.file)?;
+        ThymeFile::from_stream(&mut f)?
+    };
+
+    let config = Config {
+        grid_every: opts.grid,
+        line_weight: opts.line_weight,
+        major_line_weight: opts.major_line_weight,
+        grid_size: opts.size,
+        font: opts.font.clone(),
+    };
+
+    let surf = cairo::SvgSurface::new(
+        config.scale(thyme.width),
+        config.scale(thyme.height),
+        Some(opts.output.unwrap_or_else(|| "output.svg".to_string())),
+    )?;
+
+    Pattern {
+        thyme,
+        config,
+    }
+    .draw(cairo::Context::new(&surf)?)?;
+
+    surf.finish();
+
+    Ok(())
+}

+ 23 - 0
tools/svg-from-thyme/opts.rs

@@ -0,0 +1,23 @@
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+pub struct Options {
+    pub file: String,
+    pub output: Option<String>,
+
+    #[clap(long, default_value_t = 10)]
+    pub grid: u32,
+
+    #[clap(long, default_value_t = 1.0)]
+    pub line_weight: f64,
+
+    #[clap(long, default_value_t = 3.0)]
+    pub major_line_weight: f64,
+
+    #[clap(long, default_value_t = 24.0)]
+    pub size: f64,
+
+    #[clap(long, default_value_t = String::from("Fira Sans 12"))]
+    pub font: String,
+}