Skip to content

Instantly share code, notes, and snippets.

@MetroWind
Created February 26, 2022 04:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MetroWind/3996cfac0729e12ffba3ea0766e8b59b to your computer and use it in GitHub Desktop.
Save MetroWind/3996cfac0729e12ffba3ea0766e8b59b to your computer and use it in GitHub Desktop.
Image cutter
[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"
#![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