Created
February 26, 2022 04:09
-
-
Save MetroWind/3996cfac0729e12ffba3ea0766e8b59b to your computer and use it in GitHub Desktop.
Image cutter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "jqm-cutter" | |
version = "0.1.0" | |
authors = ["MetroWind <chris.corsair@gmail.com>"] | |
edition = "2018" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
image = ">=0.24" | |
anyhow = ">=1" | |
clap = ">=3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(non_snake_case)] | |
use std::process::Command; | |
use image; | |
use image::Pixel; | |
use image::io::Reader as ImageReader; | |
use anyhow::Error as Error; | |
use clap; | |
fn findDarkestX(img: &image::RgbImage, y: u32, x_min: u32, x_max: u32) -> u32 | |
{ | |
let mut luma_min: u8 = 255; | |
let mut luma_min_x: u32 = 0; | |
for x in x_min..x_max | |
{ | |
let luma = img.get_pixel(x, y).to_luma().0[0]; | |
if luma < luma_min | |
{ | |
luma_min = luma; | |
luma_min_x = x; | |
} | |
} | |
return luma_min_x; | |
} | |
fn imageSize(img_file: &str) -> Result<(u32, u32), Error> | |
{ | |
let output = Command::new("identify").arg("-format").arg("%[fx:w]x%[fx:h]") | |
.arg(img_file).output()?; | |
let mut size = std::str::from_utf8(&output.stdout)?.split('x'); | |
let w: u32 = size.next().ok_or(Error::msg("Failed to find width"))?.parse()?; | |
let h: u32 = size.next().ok_or(Error::msg("Failed to find height"))?.parse()?; | |
Ok((w, h)) | |
} | |
fn verticalCut(img_file: &str, img_size: &(u32, u32), x: u32, file_left: &str, | |
file_right: &str) -> Result<(), Error> | |
{ | |
let mut child1 = Command::new("magick").arg(img_file).arg("-crop") | |
.arg(format!("{}x{}+0+0", x, img_size.1)).arg("+repage").arg(file_left) | |
.spawn()?; | |
let mut child2 = Command::new("magick").arg(img_file).arg("-crop") | |
.arg(format!("{}x{}+{}+0", img_size.0-x, img_size.1, x)).arg("+repage") | |
.arg(file_right).spawn()?; | |
child1.wait()?; | |
child2.wait()?; | |
Ok(()) | |
} | |
fn automaticCut(img_file: &str, img_size: &(u32, u32), | |
file_left: &str, file_right: &str) -> Result<(), Error> | |
{ | |
let img_raw = ImageReader::open(img_file)?.decode()?; | |
let img: &image::RgbImage = img_raw.as_rgb8() | |
.ok_or(Error::msg("Failed to open image"))?; | |
let x1 = findDarkestX(img, 80, img_size.0/2 - 150, img_size.0/2 + 150); | |
let x2 = findDarkestX(img, img_size.1 - 60, img_size.0/2 - 150, img_size.0/2 + 150); | |
verticalCut(img_file, &img_size, x1.min(x2), file_left, file_right) | |
} | |
fn preprocess(img_file: &str, out_file: &str) -> Result<(), Error> | |
{ | |
Command::new("magick") | |
.arg(img_file).arg("-set").arg("option:convolve:scale").arg("-100,100%") | |
.arg("-bias").arg("50%").arg("-morphology").arg("convolve") | |
.arg("Gaussian:0x50").arg("-level").arg("0x70%") | |
.arg("-define").arg("png:color-type=2").arg(out_file) | |
.spawn()?.wait()?; | |
Ok(()) | |
} | |
fn doIt(img_file: &str, file_left: &str, file_right: &str) -> Result<(), Error> | |
{ | |
let size = imageSize(img_file)?; | |
if size.0 <= size.1 | |
{ | |
println!("Skipping {}...", img_file); | |
return Ok(()) | |
} | |
preprocess(img_file, "temp.png")?; | |
automaticCut("temp.png", &size, file_left, file_right) | |
} | |
fn main() -> Result<(), Error> | |
{ | |
let opts = clap::Command::new("cutter") | |
.arg(clap::Arg::new("file").value_name("FILE") | |
.help("A file").multiple_occurrences(true)) | |
.get_matches(); | |
for f in opts.values_of("file").unwrap() | |
{ | |
println!("Processing {}...", f); | |
doIt(f, &format!("{}-left.png", f), &format!("{}-right.png", f))?; | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment