Skip to content
Snippets Groups Projects
main.rs 1.54 KiB
Newer Older
use clap::Parser;
use png_to_svg::cli::Cli;
use png_to_svg::formatting::El;
use png_to_svg::output::create_output_canvas;
use rayon::prelude::{ParallelBridge, ParallelIterator};

fn to_opacity(value: u8) -> f32 {
	value as f32 / 255.0
}

fn main() -> anyhow::Result<()> {
	let args = Cli::parse();

	println!("{:?}", args);

	let input = image::open(args.input_file)?;
	let input = input
		.as_rgba8()
		.ok_or_else(|| anyhow::Error::msg("Invalid input format"))?;

	let (sender, thread_handle) = create_output_canvas(
		input.width() as usize * args.scale,
		input.height() as usize * args.scale,
		args.output_file,
	);

	let pixel_width = input.width() as usize;
	input
		.pixels()
		.into_iter()
		.enumerate()
		.map(move |(idx, pixel)| (idx, pixel, sender.clone()))
		.par_bridge()
		.for_each(move |(index, pixel, sender)| {
			// Skip blank pixels
			if pixel.0.iter().all(|val| *val == 0) {
				return;
			}
			let (x, y) = (index % pixel_width, index / pixel_width);
			let attributes = vec![
				("width", format!("{}", args.scale)).into(),
				("height", format!("{}", args.scale)).into(),
				("x", format!("{}", x * args.scale)).into(),
				("y", format!("{}", y * args.scale)).into(),
				(
					"fill",
					format!("rgb({}, {}, {})", pixel.0[0], pixel.0[1], pixel.0[2]),
				)
					.into(),
				("fill-opacity", format!("{}", to_opacity(pixel.0[3]))).into(),
			];

			let _ = sender.send(El::create("rect", attributes.as_slice()));
		});

	thread_handle
		.join()
		.map_err(|_| anyhow::Error::msg("The image writing thread failed, somehow"))??;

	Ok(())
}