refactor: break up main into `imaging` and `graphics` modules
Diff
src/graphics.rs | 16 ++++++++++++++++
src/imaging.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.rs | 52 +++++++++++-----------------------------------------
3 files changed, 77 insertions(+), 41 deletions(-)
@@ -0,0 +1,16 @@
use screenshots::Screen;
pub struct Display;
impl Display {
pub fn get_displays() -> Vec<Screen> {
let mut screens = Screen::all().unwrap_or_else(|err| {
eprintln!("there was an error retrieving screens: {:?}", err);
vec![]
});
screens.sort_by(|first, second| first.display_info.x.cmp(&second.display_info.x));
screens
}
}
@@ -0,0 +1,50 @@
use screenshots::image::{ImageBuffer, Rgba};
#[derive(Default)]
pub struct ImageDimensions {
pub width: u32,
pub height: u32,
}
impl std::fmt::Display for ImageDimensions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("({}, {})", self.width, self.height))
}
}
pub struct Renderer;
impl Renderer {
pub fn stitch_horizontally(
images: Vec<ImageBuffer<Rgba<u8>, Vec<u8>>>,
) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
let dimensions = images
.iter()
.fold(ImageDimensions::default(), |t, buf| ImageDimensions {
width: t.width + buf.width(),
height: t.height.max(buf.height()),
});
let mut img_buf = ImageBuffer::new(dimensions.width, dimensions.height);
images
.iter()
.fold(ImageDimensions::default(), |offset, buf| {
for (x, y, pixel) in buf.enumerate_pixels() {
img_buf.put_pixel(offset.width + x, y, *pixel);
}
ImageDimensions {
width: offset.width + buf.width(),
height: offset.height,
}
});
img_buf
}
}
@@ -2,9 +2,11 @@ use std::path::PathBuf;
use chrono::{DateTime, Local, Utc};
use clap::Parser;
use screenshots::{image::ImageBuffer, Screen};
use imaging::Renderer;
mod cli;
mod graphics;
mod imaging;
fn main() {
let args = cli::Args::parse();
@@ -12,39 +14,14 @@ fn main() {
capture_all(args.out, args.filename_format.unwrap_or_default());
}
fn capture_all(out_dir: String, filename_format: String) {
let mut screens = Screen::all().unwrap_or_else(|err| {
eprintln!("there was an error retrieving screens: {:?}", err);
vec![]
});
screens.sort_by(|first, second| first.display_info.x.cmp(&second.display_info.x));
let captures: Vec<_> = screens
let captures: Vec<_> = graphics::Display::get_displays()
.iter()
.filter_map(|screen| screen.capture().ok())
.collect();
let dimensions = captures
.iter()
.fold(ImageDimensions::default(), |t, buf| ImageDimensions {
x: t.x + buf.width(),
y: t.y.max(buf.height()),
});
let mut img = ImageBuffer::new(dimensions.x, dimensions.y);
captures
.iter()
.fold(ImageDimensions::default(), |offset, buf| {
for (x, y, pixel) in buf.enumerate_pixels() {
img.put_pixel(offset.x + x, y, *pixel);
}
ImageDimensions {
x: offset.x + buf.width(),
y: offset.y,
}
});
let img = Renderer::stitch_horizontally(captures);
if !img.is_empty() {
let timestamp: DateTime<Local> = Utc::now().with_timezone(&Local);
@@ -61,18 +38,11 @@ fn capture_all(out_dir: String, filename_format: String) {
}
}
#[derive(Default)]
struct ImageDimensions {
pub x: u32,
pub y: u32,
}
impl std::fmt::Display for ImageDimensions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("({}, {})", self.x, self.y))
}
}
fn generate_filename(filename: &PathBuf) -> PathBuf {
let mut index = 0;
let mut new_filename = filename.clone();