file picker, progress bar, perf enhancements

This commit is contained in:
Ponj 2024-07-11 17:45:55 +02:00
parent 5c2607b574
commit 5d39e227b6
Signed by: p6nj
GPG key ID: CEAB625B75A836B2
4 changed files with 114 additions and 22 deletions

2
.gitignore vendored
View file

@ -1,3 +1,3 @@
/target
*.lock
bmp/out.bmp
bmp/out.*

View file

@ -14,3 +14,7 @@ image = "0.24.9"
anyhow = "1.0.86"
bingus = { version = "0.1.0", path = "bingus" }
num-traits = "0.2.19"
dasp_sample = "0.11.0"
rayon = "1.10.0"
dirs = "5.0.1"
rfd = "0.14.1"

View file

@ -15,3 +15,9 @@ image = { workspace = true }
fundsp = { workspace = true }
anyhow = { workspace = true }
bingus = { workspace = true }
dasp_sample = { workspace = true }
rayon = { workspace = true }
dirs = { workspace = true }
rfd = { workspace = true }
derive-new = "0.6.0"
indicatif = { version = "0.17.8", features = ["rayon"] }

View file

@ -1,27 +1,102 @@
use std::array;
use std::path::PathBuf;
use anyhow::Result;
use fundsp::{
hacker::{bell_hz, pipei, U12},
math::db_amp,
};
use image::io::Reader as ImageReader;
use anyhow::{Context, Result};
use dasp_sample::{Sample, U24};
use derive_new::new;
use dirs::{download_dir, home_dir, picture_dir};
use fundsp::math::uparc;
use image::{io::Reader as ImageReader, ImageBuffer, ImageFormat, Rgb};
use indicatif::{ParallelProgressIterator, ProgressStyle};
use rayon::{iter::ParallelIterator, slice::ParallelSlice};
use rfd::FileDialog;
struct Files {
input: PathBuf,
output: PathBuf,
}
#[derive(new)]
struct DataPath {
files: Files,
}
impl Files {
fn try_new(input: PathBuf, output: PathBuf) -> Result<Self> {
Ok(Files {
input: Self::verify_image_file(input, "input")?,
output: Self::verify_image_file(output, "output")?,
})
}
fn verify_image_file(path: PathBuf, label: &'static str) -> Result<PathBuf> {
ImageFormat::from_path(&path).with_context(|| {
format!("your {label} image must have a supported extension from this list:")
+ &ImageFormat::all()
.map(|format| {
format!(
"\n\t{:?} ({})",
format,
format
.extensions_str()
.iter()
.fold(String::new(), |acc, x| acc + &format!(".{x}, "))
.strip_suffix(", ")
.unwrap()
)
})
.reduce(|acc, x| acc + &x)
.unwrap()
})?;
Ok(path)
}
fn prompt() -> Result<Self> {
Files::try_new(
FileDialog::new()
.set_title("Input image")
.set_directory(working_dir())
.pick_file()
.context("no input image selected")?,
FileDialog::new()
.set_title("Output image")
.set_directory(working_dir())
.save_file()
.context("no output filename provided")?,
)
}
}
fn main() -> Result<()> {
let mut img = ImageReader::open("bmp/bigsample.bmp")?.decode()?.to_rgb8();
let mut equalizer =
pipei::<U12, _, _>(|i| bell_hz(1000.0 + 1000.0 * i as f32, 1.0, db_amp(0.0)));
img.to_vec()
.chunks_exact(3)
.map(|px: &[u8]| f32::from_ne_bytes(array::from_fn(|i| px[i % px.len()])))
.map(|x| equalizer.filter_mono(x))
.flat_map(|px| -> [u8; 3] {
let px = px.to_ne_bytes();
array::from_fn(move |i| px[i])
})
.zip(img.as_mut())
.for_each(|(filtered, original)| *original = filtered);
img.save("bmp/out.bmp")?;
let dp = DataPath::new(Files::prompt()?);
let img = ImageReader::open(dp.files.input)?
.decode()
.context("can't use this picture")?
.to_rgb8();
let (width, height) = (img.width(), img.height());
let processed: ImageBuffer<Rgb<u8>, Vec<u8>> = ImageBuffer::from_raw(
width,
height,
img.into_raw()
.par_chunks_exact(3)
.progress_count((width * height).into())
.with_style(ProgressStyle::with_template(
"[{eta}] {bar:40.green/red} {pos}/{len} pixels",
)?)
.map(|px: &[u8]| (px[2] as i32) | ((px[1] as i32) << 8) | ((px[0] as i32) << 16))
.map(|px| U24::new_unchecked(px))
.map(|x| uparc(x.to_sample()))
.flat_map(|sample: f32| {
let rgb: U24 = sample.to_sample();
let rgo = ((rgb) >> 8.into()) << 8.into();
let roo = ((rgo) >> 16.into()) << 16.into();
[
((roo) >> 16.into()).inner() as u8,
((rgo - roo) >> 8.into()).inner() as u8,
(rgb - rgo).inner() as u8,
]
})
.collect(),
)
.unwrap();
processed.save(dp.files.output)?;
// let bytes: Vec<u8> = (1u8..7).into_iter().collect();
// assert_eq!(
@ -37,3 +112,10 @@ fn main() -> Result<()> {
// );
Ok(())
}
fn working_dir() -> PathBuf {
picture_dir()
.or(download_dir())
.or(home_dir())
.unwrap_or("/".into())
}