Skip to main content

poe_data_tools_cli/commands/
dump_art.rs

1use std::{fs, path::Path};
2
3use anyhow::{Context, Result, ensure};
4use glob::{MatchOptions, Pattern};
5use poe_data_tools::fs::{FS, FileSystem};
6
7use crate::VERBOSE;
8
9/// Extract files to disk matching a glob pattern
10pub fn extract_art(fs: &mut FS, patterns: &[Pattern], output_folder: &Path) -> Result<()> {
11    image_extras::register();
12
13    for pattern in patterns {
14        ensure!(
15            pattern.as_str().ends_with(".dds"),
16            "Only .dds art export is supported."
17        );
18    }
19
20    let filenames = fs
21        .list()
22        .filter(|filename| {
23            patterns.iter().any(|pattern| {
24                pattern.matches_with(
25                    filename,
26                    MatchOptions {
27                        require_literal_separator: true,
28                        ..Default::default()
29                    },
30                )
31            })
32        })
33        .collect::<Vec<_>>();
34
35    fs.batch_read(&filenames)
36        // Print and filter out errors
37        .filter_map(|(path, res)| match res {
38            Ok(b) => Some((path, b)),
39            Err(e) => {
40                log::error!("Failed to extract file: {:?}: {:?}", path, e);
41                None
42            }
43        })
44        // Attempt to read file contents
45        .map(|(filename, contents)| -> Result<_, anyhow::Error> {
46            let img = image::load_from_memory(&contents)
47                .with_context(|| format!("Failed to parse DDS image: {filename}"))?;
48
49            let out_filename = output_folder.join(filename.as_ref()).with_extension("png");
50            fs::create_dir_all(out_filename.parent().unwrap())
51                .with_context(|| format!("Failed to create output folder: {out_filename:?}"))?;
52
53            img.save(out_filename)
54                .with_context(|| format!("Failed to write file: {filename}"))?;
55
56            Ok(filename)
57        })
58        // Report results
59        .for_each(|result| match result {
60            Ok(filename) => log::info!("Extracted file: {}", filename),
61            Err(e) => {
62                let error_message = if *VERBOSE.get().unwrap() {
63                    format!("{e:?}")
64                } else {
65                    format!("{e}")
66                };
67                log::error!("Failed to extract file: {error_message}");
68            }
69        });
70
71    Ok(())
72}