Skip to content

Instantly share code, notes, and snippets.

@acorn1010
Created February 24, 2023 19:52
Show Gist options
  • Save acorn1010/6a0e47a2a6ee4c348e8eaa4d41ba8cfc to your computer and use it in GitHub Desktop.
Save acorn1010/6a0e47a2a6ee4c348e8eaa4d41ba8cfc to your computer and use it in GitHub Desktop.
Rust TypeScript type generator for images
use std::env;
use std::fs::File;
use std::io::Write;
use std::time::Instant;
use walkdir::WalkDir;
use image::GenericImageView;
use rayon::prelude::*;
fn main() {
// Read input and output file paths
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
eprintln!("Usage: program_name input_file_path output_file_path");
return;
}
let input_file_path = &args[1];
let output_file_path = &args[2];
println!("Generating image TypeScript file...");
let start = Instant::now();
let entries =
WalkDir::new(input_file_path)
.into_iter()
.filter_map(|e| e.ok())
.collect::<Vec<_>>();
let extensions = ["webp"]; // TODO(acorn1010): Maybe add png here, since it's a different size?
let results: Vec<_> = entries
.par_iter()
.filter_map(|entry| {
match entry.path().extension().and_then(|ext| ext.to_str()) {
Some(extension) if extensions.contains(&extension) => {
if let Ok(image) = image::open(&entry.path()) {
let (width, height) = image.dimensions();
let filename = entry.path()
.with_extension("")
.strip_prefix(input_file_path)
.unwrap()
.display()
.to_string();
Some((filename, width, height))
} else {
None
}
}
_ => None,
}
})
.collect();
let mut sorted_results = results;
sorted_results.par_sort_unstable_by(|a, b| a.0.cmp(&b.0));
let mut file = File::create(output_file_path).unwrap();
file.write_all(b"/** This file is auto-generated by scripts/rust/image_utils. */\n").unwrap();
file.write_all(b"\n").unwrap();
file.write_all(b"/**\n").unwrap();
file.write_all(b" * Maps the base filepath (from Foony's domain) to an image path without the extension.\n").unwrap();
file.write_all(b" * .webp and .avif extensions are supported for all files here.\n").unwrap();
file.write_all(b" */\n").unwrap();
file.write_all(b"export type SiteImages = {\n").unwrap();
for (filename, width, height) in sorted_results {
let line = format!(" '{}': {{width: {}, height: {}}},\n", filename, width, height);
file.write_all(line.as_bytes()).unwrap();
}
file.write_all(b"};\n").unwrap();
file.write_all(b"export type SiteImage = keyof SiteImages;\n").unwrap();
println!("Elapsed time: {:?}", start.elapsed());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment