instinx/src/lib.rs

182 lines
5.4 KiB
Rust

use std::io::BufWriter;
use image::{
codecs::jpeg::JpegEncoder, DynamicImage::*, EncodableLayout, ExtendedColorType::*, ImageBuffer,
};
use photon_rs::{
multiple::watermark,
native::open_image,
transform::{resize, SamplingFilter},
PhotonImage,
};
// TODO: Add option for 4:5 export and 1:1 export
pub fn process_image(path: &std::path::Path) -> PhotonImage {
let mut image = open_image(path.to_str().expect("to parse path to string"))
.expect("to open image with Photon");
println!("opened image");
let padding = 36;
let intended_size_in_frame = 1080 - padding;
let mut background = PhotonImage::new_from_byteslice({
let mut image =
Image::create(1080, 1080, false, Format::RGB8).expect("to be able to create an image");
image.fill(Color::WHITE);
image.save_jpg_to_buffer().to_vec()
});
let width = image.get_width();
let height = image.get_height();
let biggest_dimension = std::cmp::max(width, height);
println!("Original dimensions {width}x{height}");
let scaled_other_dimension = if width == biggest_dimension {
(height as f32 / (width as f32 / intended_size_in_frame as f32)) as u32
} else {
(width as f32 / (height as f32 / intended_size_in_frame as f32)) as u32
};
let image = if width == biggest_dimension {
println!("Width is bigger, setting to {intended_size_in_frame}x{scaled_other_dimension}");
resize(
&mut image,
intended_size_in_frame,
scaled_other_dimension,
SamplingFilter::Lanczos3,
)
} else {
println!("Height is bigger, setting to {scaled_other_dimension}x{intended_size_in_frame}");
resize(
&mut image,
scaled_other_dimension,
intended_size_in_frame,
SamplingFilter::Lanczos3,
)
};
if width == biggest_dimension {
watermark(
&mut background,
&image,
(1080 - intended_size_in_frame) / 2,
(1080 - scaled_other_dimension) / 2,
);
} else {
watermark(
&mut background,
&image,
(1080 - scaled_other_dimension) / 2,
(1080 - intended_size_in_frame) / 2,
);
}
// println!("done!");
background
}
pub fn save_image(image: PhotonImage, path: &str) {
let raw_pixels = image.get_raw_pixels();
let width = image.get_width();
let height = image.get_height();
println!("attempting to make image buffer");
let buffer = ImageBuffer::from_vec(width, height, raw_pixels)
.expect("to be able to build an image buffer");
let image = ImageRgba8(buffer).into_rgb8();
println!("attempting to save to {path:#?}");
let file = std::fs::File::create(path).expect("to able to create a file");
let ref mut buff = BufWriter::new(file);
let mut encoder = JpegEncoder::new_with_quality(buff, 100);
encoder
.encode(&image.as_bytes(), width, height, Rgb8)
.expect("to encode the JPEG to a file");
println!("saved to {path:#?}");
}
use godot::{
engine::{image::Format, Image},
prelude::*,
};
struct PhotoProcessingExtension;
#[gdextension]
unsafe impl ExtensionLibrary for PhotoProcessingExtension {}
#[derive(GodotClass)]
#[class(base=Node)]
struct PhotoProcess {
base: Base<Node>,
}
#[godot_api]
impl INode for PhotoProcess {
fn init(base: Base<Node>) -> Self {
Self { base }
}
}
#[godot_api]
impl PhotoProcess {
#[signal]
fn done_with_photo(path: GString);
#[func]
fn process_files(&mut self, files: PackedStringArray) {
godot_print!("attempting to process files: {files:#?}! ✨");
let mut threads = vec![];
let instance_id = self.base().instance_id();
for file in files.to_vec() {
godot_print!("attempting to process file: {file:#?}! 🤔");
let file = file.to_string().clone();
threads.push(std::thread::spawn(move || {
let path = std::path::Path::new(&file);
println!(
"🎞️ Processing {:?}",
path.file_name().expect("to turn path into a filename")
);
let image = process_image(path);
println!("Done processing!");
let mut new_file_path = std::path::PathBuf::from(path);
new_file_path.set_file_name(format!(
"{} - instagram compatible.jpg",
path.file_name()
.expect("to get path filename")
.to_str()
.expect("to convert filename to string")
.replace(".jpg", "")
));
save_image(
image,
new_file_path
.to_str()
.expect("to turn new_path into a string"),
);
Gd::<Node>::from_instance_id(instance_id).call_deferred(
"emit_signal".into(),
&[
Variant::from("done_with_photo"),
Variant::from(new_file_path.to_str().unwrap()),
],
);
println!("🖼️ done w/ file, wrote to: {new_file_path:#?}");
}));
}
// for handle in threads {
// handle.join().expect("to join threads");
// }
}
}