diff --git a/.gitignore b/.gitignore index 2573e7f..d661a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /target /inputs -/outputs +/assets /metadata -.DS_Store \ No newline at end of file +.DS_Store diff --git a/src/cli/generate.rs b/src/cli/generate.rs index a644984..a7c3996 100644 --- a/src/cli/generate.rs +++ b/src/cli/generate.rs @@ -1,6 +1,6 @@ use clap::{Parser, ValueHint}; use console::style; -use image::imageops::overlay; +use image::{imageops, DynamicImage}; use rand::distributions::WeightedIndex; use rand::prelude::*; use rand::seq::SliceRandom; @@ -26,24 +26,24 @@ pub struct GenerateArgs { /// Number of assets to generate #[clap(short, long)] count: u128, - + /// Input directory #[clap(short, long, value_hint = ValueHint::FilePath, value_name = "INPUT PATH", default_value = ASSETS_INPUT)] - input: PathBuf, - + input_dir: PathBuf, + /// Output assets directory #[clap(short, long, value_hint = ValueHint::FilePath, value_name = "ASSETS OUTPUT PATH", default_value = ASSETS_OUTPUT)] - assets: PathBuf, - + assets_dir: PathBuf, + /// Output metadata directory #[clap(short, long, value_hint = ValueHint::FilePath, value_name = "METADATA OUTPUT PATH", default_value = METADATA_OUTPUT)] - metadata: PathBuf, + metadata_dir: PathBuf, } impl Cmd for GenerateArgs { fn run(self) -> eyre::Result<()> { let GenerateArgs { count, - input, - assets, - metadata, + input_dir, + assets_dir, + metadata_dir, } = self; println!( @@ -52,30 +52,30 @@ impl Cmd for GenerateArgs { PALETTE_EMOJI ); - if !input.exists() { + if !input_dir.exists() { + // TODO: Deal with these unwraps let mut cwd: String = env::current_dir()?.to_str().unwrap().to_owned(); cwd.push_str("/"); - cwd.push_str(input.to_str().unwrap()); + cwd.push_str(input_dir.to_str().unwrap()); eyre::bail!("Directory {:?} does not exist", cwd) } - let trait_layers = load_layers(input)?; + let trait_layers = load_layers(input_dir)?; // Create the assets output folder if it does not exist - if !assets.exists() { - // fs::create_dir_all(&assets)?; + if !assets_dir.exists() { + fs::create_dir_all(&assets_dir)?; } // Create the metadata output folder if it does not exist - if !metadata.exists() { - // fs::create_dir_all(&metadata)?; + if !metadata_dir.exists() { + fs::create_dir_all(&metadata_dir)?; } let trait_layer_keys: Vec = trait_layers.keys().cloned().collect(); - println!("{:?}", trait_layer_keys); - for _ in 0..count { + for i in 0..count { let selected_layers: Vec<&Box> = trait_layer_keys .iter() .map(|trait_type| { @@ -92,9 +92,9 @@ impl Cmd for GenerateArgs { .map(|l| l.unwrap()) .collect(); - println!("{:?}", selected_layers); - - let asset = create_artwork(&selected_layers); + println!("Creating id {i}"); + let asset = create_artwork(&selected_layers)?; + asset.save(format!("{}/{}.png", assets_dir.to_str().unwrap(), i))?; } todo!() } @@ -125,9 +125,27 @@ impl Layer { } } -fn create_artwork(layers: &[&Box]) { +type FinalImage = DynamicImage; + +fn create_artwork(layers: &[&Box]) -> eyre::Result { // TODO: Add error handling rather than unwrap - let base_layer = &layers.first().unwrap(); + let canvas = &layers.first().unwrap(); + + let mut canvas = image::open(&canvas.value) + .map_err(|_| DirError::FileNotFoundError("Failed to open file".to_string()))?; + + // Skip the first element (the base layer) + for layer in layers.iter().skip(1) { + let layer = image::open(&layer.value) + .map_err(|_| DirError::FileNotFoundError("Failed to open file".to_string()))?; + imageops::overlay(&mut canvas, &layer, 0, 0) + } + + Ok(canvas) +} + +fn create_metadata(layers: &[&Box]) -> eyre::Result<()> { + todo!() } fn encode_combination(layers: &[&Box]) -> eyre::Result { @@ -161,20 +179,14 @@ fn load_layers(input_dir: PathBuf) -> eyre::Result { let mut subdir_layers: Vec> = vec![]; for file in subdir { - let file = file?.file_name(); - - let file_path = Path::new(&file); - - let trait_value = file_path.file_stem().ok_or(DirError::FileStemError( - "Error reading file stem.".to_string(), - ))?; + let trait_value = file?.path(); let rarity = 1; // Cloning since I need trait_type later as well let trait_type = trait_type.clone(); - let layer = Box::new(Layer::new(trait_type, trait_value.into(), rarity)); + let layer = Box::new(Layer::new(trait_type, trait_value, rarity)); subdir_layers.push(layer); } diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 5ba3e7b..d02c94d 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -13,7 +13,7 @@ impl Dir { info!("Reading current path {path:?}"); // Get the subdirectories of the input folder - let mut contents = fs::read_dir(&path)? + let contents = fs::read_dir(&path)? .map(|result| result.map(|item| item.path())) .filter(|c| c.as_ref().unwrap().is_dir()) .collect::, _>>()?; @@ -31,4 +31,6 @@ impl Dir { pub enum DirError { #[error("failed to get file stem: {0}")] FileStemError(String), + #[error("failed to open file: {0}")] + FileNotFoundError(String), }