Skip to content

Commit

Permalink
Add --recursive option (#43)
Browse files Browse the repository at this point in the history
Add `--recursive` option and therefore fix #42.

This PR includes two breaking changes to the public API:

- added second parameter (`recurse`) to `spreet::fs::get_svg_input_paths`
- added second parameter (`base_path`) to `spreet::sprite::sprite_name`
  • Loading branch information
DerZade authored Feb 13, 2023
1 parent 0bf3312 commit 737f5ed
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Development version

- Add `--recursive` argument, to include images in sub-directories (see [#43](https://github.com/flother/spreet/pull/43))
- **Breaking change**: update [Oxipng](https://github.com/shssoichiro/oxipng) dependency to v7. Spritesheet PNGs output by Spreet are now compressed using [libdeflate](https://github.com/ebiggers/libdeflate). This produces smaller files but the PNGs won't be byte-to-byte compatible with spritesheets output by earlier versions of Spreet. This also causes Spreet's minimum Rust version to be 1.61.0

## v0.5.0 (2022-12-11)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Options:
-r, --ratio <RATIO> Set the output pixel ratio [default: 1]
--retina Set the pixel ratio to 2 (equivalent to `--ratio=2`)
--unique Store only unique images in the spritesheet, and map them to multiple names
--recursive Include images in sub-directories
-m, --minify-index-file Remove whitespace from the JSON index file
-h, --help Print help information
-V, --version Print version information
Expand Down
3 changes: 3 additions & 0 deletions src/bin/spreet/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub struct Cli {
/// Store only unique images in the spritesheet, and map them to multiple names
#[arg(long)]
pub unique: bool,
/// Include images in sub-directories
#[arg(long)]
pub recursive: bool,
/// Remove whitespace from the JSON index file
#[arg(short, long)]
pub minify_index_file: bool,
Expand Down
4 changes: 2 additions & 2 deletions src/bin/spreet/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn main() {
let pixel_ratio = if args.retina { 2 } else { args.ratio };

// Collect the file paths for all SVG images in the input directory.
let svg_paths = get_svg_input_paths(&args.input);
let svg_paths = get_svg_input_paths(&args.input, args.recursive);
if svg_paths.is_empty() {
eprintln!("Error: no SVGs found in {:?}", &args.input);
std::process::exit(exitcode::NOINPUT);
Expand All @@ -32,7 +32,7 @@ fn main() {
.par_iter()
.map(|svg_path| match load_svg(svg_path) {
Ok(svg) => (
sprite::sprite_name(svg_path),
sprite::sprite_name(svg_path, args.input.as_path()),
sprite::generate_pixmap_from_svg(svg, pixel_ratio).unwrap(),
),
Err(_) => {
Expand Down
19 changes: 14 additions & 5 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,23 @@ pub fn is_useful_input(entry: &DirEntry) -> bool {

/// Returns a vector of file paths matching all SVGs within the given directory.
///
/// This does not recurse into sub-directories; they are silently ignored. It ignores hidden files
/// (files whose names begin with `.`) but it does follow symlinks.
pub fn get_svg_input_paths(path: &Path) -> Vec<PathBuf> {
/// It ignores hidden files (files whose names begin with `.`) but it does follow symlinks.
pub fn get_svg_input_paths(path: &Path, recursive: bool) -> Vec<PathBuf> {
read_dir(path)
.unwrap()
.flatten()
.filter(is_useful_input)
.map(|entry| entry.path())
.filter_map(|entry| {
let path_buf = entry.path();

if recursive && path_buf.is_dir() {
Some(get_svg_input_paths(path_buf.as_path(), recursive))
} else if is_useful_input(&entry) {
Some(vec![path_buf])
} else {
None
}
})
.flatten()
.collect()
}

Expand Down
17 changes: 15 additions & 2 deletions src/sprite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,21 @@ impl Spritesheet {
}

/// Returns the name (unique id within a spritesheet) taken from a file.
pub fn sprite_name(path: &Path) -> String {
format!("{}", path.file_stem().unwrap().to_string_lossy())
///
/// The unique sprite name is the relative path from `path` to `base_path`
/// without the file extension.
pub fn sprite_name(path: &Path, base_path: &Path) -> String {
let abs_path = path.canonicalize().unwrap();
let abs_base_path = base_path.canonicalize().unwrap();

let rel_path = abs_path.strip_prefix(abs_base_path).unwrap();

let file_stem = path.file_stem().unwrap();

match rel_path.parent() {
Some(parent) => format!("{}", parent.join(file_stem).to_string_lossy()),
None => format!("{}", file_stem.to_string_lossy()),
}
}

/// Generate a bitmap image from an SVG image.
Expand Down
22 changes: 22 additions & 0 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,28 @@ fn spreet_can_output_retina_spritesheet() -> Result<(), Box<dyn std::error::Erro
Ok(())
}

#[test]
fn spreet_can_output_recursive_spritesheet() -> Result<(), Box<dyn std::error::Error>> {
let temp = assert_fs::TempDir::new().unwrap();

let mut cmd = Command::cargo_bin("spreet")?;
cmd.arg("tests/fixtures/svgs")
.arg(temp.join("recursive"))
.arg("--recursive")
.assert()
.success();

let expected_spritesheet = Path::new("tests/fixtures/output/recursive@1x.png");
let actual_spritesheet = predicate::path::eq_file(temp.join("recursive.png"));
let expected_index = Path::new("tests/fixtures/output/recursive@1x.json");
let actual_index = predicate::path::eq_file(temp.join("recursive.json"));

assert!(actual_spritesheet.eval(expected_spritesheet));
assert!(actual_index.eval(expected_index));

Ok(())
}

#[test]
fn spreet_can_output_unique_retina_spritesheet() -> Result<(), Box<dyn std::error::Error>> {
let temp = assert_fs::TempDir::new().unwrap();
Expand Down
30 changes: 30 additions & 0 deletions tests/fixtures/output/recursive@1x.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"another_bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 35,
"y": 16
},
"bicycle": {
"height": 15,
"pixelRatio": 1,
"width": 15,
"x": 20,
"y": 16
},
"circle": {
"height": 20,
"pixelRatio": 1,
"width": 20,
"x": 0,
"y": 0
},
"recursive/bear": {
"height": 16,
"pixelRatio": 1,
"width": 16,
"x": 20,
"y": 0
}
}
Binary file added tests/fixtures/output/recursive@1x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions tests/fixtures/svgs/recursive/bear.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions tests/sprite.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::path::Path;

use spreet::sprite::sprite_name;

#[test]
fn sprite_name_works_with_root_files() {
assert_eq!(
sprite_name(
Path::new("./tests/fixtures/svgs/recursive/bear.svg"),
Path::new("./tests/fixtures/svgs/recursive")
),
"bear"
);
}

#[test]
fn sprite_name_works_with_nested_files() {
assert_eq!(
sprite_name(
Path::new("./tests/fixtures/svgs/recursive/bear.svg"),
Path::new("./tests/fixtures/svgs")
),
"recursive/bear"
);
}

#[test]
fn sprite_name_works_with_deeply_nested_files() {
assert_eq!(
sprite_name(
Path::new("./tests/fixtures/svgs/recursive/bear.svg"),
Path::new("./tests")
),
"fixtures/svgs/recursive/bear"
);
}

0 comments on commit 737f5ed

Please sign in to comment.