Skip to content

Commit

Permalink
Initial D
Browse files Browse the repository at this point in the history
  • Loading branch information
ronvoluted committed Mar 29, 2023
1 parent e7264ba commit 760ef37
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "dds-to-img"
version = "0.1.0"
edition = "2021"

[dependencies]
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

# DDS-to-img

Rust CLI to recursively convert a directory of DDS files to other image formats.

## Usage
1. [ffmpeg](https://ffmpeg.org) must be installed and in your [`path`](https://learn.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ee537574(v=office.14)#to-add-a-path-to-the-path-environment-variable).
2. [texconv](https://github.com/Microsoft/DirectXTex/wiki/Texconv) must be installed and in your [`path`](https://learn.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ee537574(v=office.14)#to-add-a-path-to-the-path-environment-variable).
3. Run [`dds-to-img.exe`](https://github.com/ronvoluted/dds-to-img/releases/latest) on a directory of `*.dds` files
```
dds-to-img <directory> [{png|webp}]
```
**Example:**
```
dds-to-image textures/ui webp
```
The directory structure will be maintained and output to a new sibling folder named `<directory>_<image format>`

### Arguments
- `directory` (required): Folder to look for `*.dds` files in.
- `{png|webp}` (optional): Image format to convert to. Defaults to `png`.
122 changes: 122 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, Stdio};
use std::sync::atomic::{AtomicUsize, Ordering};

static PROCESSED_COUNT: AtomicUsize = AtomicUsize::new(0);

fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Usage: dds-to-img <directory> [png | webp | avif | gif]");
return;
}

let dir = &args[1];
let format = if args.len() >= 3 {
args[2].to_lowercase()
} else {
"png".to_string()
};

if !["png", "webp", "avif", "gif"].contains(&format.as_str()) {
println!("Invalid output format. Supported formats: png, webp, avif, gif");
return;
}

let output_dir = format!("{}_{}", dir, format);
fs::create_dir_all(&output_dir).expect("Failed to create output directory");

process_directory(dir, &output_dir, dir, &format);
}

fn process_directory<P: AsRef<Path>, Q: AsRef<Path>, R: AsRef<Path>>(
dir: &P,
output_base_dir: &Q,
root_dir: &R,
format: &str,
) {
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries {
if let Ok(entry) = entry {
let path = entry.path();
if path.is_dir() {
process_directory(&path, output_base_dir, root_dir, format);
} else {
process_file(&path, output_base_dir, root_dir, format);
}
}
}
} else {
println!("Failed to read directory {:?}", dir.as_ref());
}
}

fn process_file<P: AsRef<Path>, Q: AsRef<Path>, R: AsRef<Path>>(
path: &P,
output_base_dir: &Q,
root_dir: &R,
format: &str,
) {
let path = path.as_ref();
if let Some(extension) = path.extension() {
if extension == "dds" {
let input_file = path.to_str().unwrap();
let file_stem = path.file_stem().unwrap().to_str().unwrap();

let relative_path = path.strip_prefix(root_dir).unwrap();
let parent_dir = relative_path.parent().unwrap();
let output_subdir = output_base_dir.as_ref().join(parent_dir);
fs::create_dir_all(&output_subdir).expect("Failed to create output subdirectory");

let output_bmp_path = output_subdir.join(file_stem).with_extension("BMP");
let output_file_path = output_subdir.join(file_stem).with_extension(format);

let texconv_status = Command::new("texconv")
.args(&[
"-ft",
"bmp",
"-f",
"B8G8R8A8_UNORM",
"-y",
"-o",
output_subdir.to_str().unwrap(),
input_file,
])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("Failed to run texconv");

if texconv_status.success() {
let ffmpeg_status = Command::new("ffmpeg")
.args(&[
"-i",
output_bmp_path.to_str().unwrap(),
"-update",
"1",
output_file_path.to_str().unwrap(),
])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.expect("Failed to run ffmpeg");

if ffmpeg_status.success() {
fs::remove_file(output_bmp_path).expect("Failed to remove BMP file");
let count = PROCESSED_COUNT.fetch_add(1, Ordering::SeqCst) + 1;
println!(
"{} ({} processed)",
output_file_path.to_str().unwrap(),
count
);
} else {
println!("Failed to process file {:?}", path);
}
} else {
println!("Failed to process file {:?}", path);
}
}
}
}

0 comments on commit 760ef37

Please sign in to comment.