Add module output.rs for image file path
- Modularity - Avoid code duplication - FIx comments in `core.rs`
This commit is contained in:
parent
31900b4a17
commit
eea3c757c0
@ -52,7 +52,7 @@ impl XContext {
|
|||||||
///
|
///
|
||||||
/// `ctxt` – connection + screen info\
|
/// `ctxt` – connection + screen info\
|
||||||
/// `x_coord,y_coord` – top-left corner of the rectangle\
|
/// `x_coord,y_coord` – top-left corner of the rectangle\
|
||||||
/// `w,h` – size of the rectangle
|
/// `width,height` – size of the rectangle
|
||||||
///
|
///
|
||||||
/// Returns: a `Vec<u8>` containing RGBA pixel data.
|
/// Returns: a `Vec<u8>` containing RGBA pixel data.
|
||||||
pub fn capture_rect(
|
pub fn capture_rect(
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
mod core;
|
mod core;
|
||||||
|
mod output;
|
||||||
|
|
||||||
use chrono::Local;
|
|
||||||
use core::{XContext, capture_rect, save_png};
|
use core::{XContext, capture_rect, save_png};
|
||||||
use std::fs;
|
use output::make_screenshot_path;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
// Create a connection to the X11 server and read screen information.
|
// Create a connection to the X11 server and read screen information.
|
||||||
@ -12,31 +12,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
// We pass (0,0) as the top-left corner and use the screen width/height.
|
// We pass (0,0) as the top-left corner and use the screen width/height.
|
||||||
let img = capture_rect(&ctx, 0, 0, ctx.width, ctx.height)?;
|
let img = capture_rect(&ctx, 0, 0, ctx.width, ctx.height)?;
|
||||||
|
|
||||||
// Build the output file path.
|
// Output file path
|
||||||
// Example:
|
let path = make_screenshot_path()?;
|
||||||
// ~/Pictures/Screenshots/screenshot_20250116094530.png
|
|
||||||
//
|
|
||||||
// Using a timestamp prevents overwriting old screenshots.
|
|
||||||
let timestamp = Local::now().format("%Y%m%d%H%M%S").to_string();
|
|
||||||
|
|
||||||
// Start from the user's home directory (fallback: current dir).
|
|
||||||
let mut path = dirs::home_dir().unwrap_or_else(|| ".".into());
|
|
||||||
path.push("Pictures");
|
|
||||||
path.push("Screenshots");
|
|
||||||
|
|
||||||
// Make sure the directory exists.
|
|
||||||
fs::create_dir_all(&path)?;
|
|
||||||
|
|
||||||
// Add the actual filename.
|
|
||||||
path.push(format!("screenshot_{timestamp}.png"));
|
|
||||||
|
|
||||||
// Convert path to string for save_png().
|
|
||||||
let path_str = path.to_string_lossy();
|
let path_str = path.to_string_lossy();
|
||||||
|
|
||||||
// Write the captured RGBA image to a PNG file.
|
// Write the captured RGBA image to a PNG file.
|
||||||
save_png(&path_str, ctx.width, ctx.height, &img)?;
|
save_png(&path_str, ctx.width, ctx.height, &img)?;
|
||||||
|
|
||||||
println!("Saved {path_str}");
|
println!("Saved screenshot: {path_str}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/output.rs
Normal file
26
src/output.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use chrono::Local;
|
||||||
|
use dirs::home_dir;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Build the full output path:
|
||||||
|
/// ```
|
||||||
|
/// ~/Pictures/Screenshots/screenshot_YYYYMMDDHHMMSS.png
|
||||||
|
/// ```
|
||||||
|
/// The directory is created automatically if it doesn't exist.
|
||||||
|
pub fn make_screenshot_path() -> anyhow::Result<PathBuf> {
|
||||||
|
let timestamp = Local::now().format("%Y%m%d%H%M%S").to_string();
|
||||||
|
|
||||||
|
// Get $HOME (fallback: current working directory)
|
||||||
|
let mut path = home_dir().unwrap_or_else(|| ".".into());
|
||||||
|
path.push("Pictures");
|
||||||
|
path.push("Screenshots");
|
||||||
|
|
||||||
|
// Ensure the directory exists.
|
||||||
|
fs::create_dir_all(&path)?;
|
||||||
|
|
||||||
|
// Add filename.
|
||||||
|
path.push(format!("screenshot_{timestamp}.png"));
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
mod core;
|
mod core;
|
||||||
|
mod output;
|
||||||
|
|
||||||
use core::{XContext, capture_rect, save_png};
|
use core::{XContext, capture_rect, save_png};
|
||||||
|
use output::make_screenshot_path;
|
||||||
|
|
||||||
use chrono::Local;
|
use std::convert::TryFrom;
|
||||||
use std::fs;
|
|
||||||
use x11rb::protocol::xproto::{AtomEnum, ConnectionExt, GetGeometryReply, Window};
|
use x11rb::protocol::xproto::{AtomEnum, ConnectionExt, GetGeometryReply, Window};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@ -11,34 +12,27 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let ctx = XContext::new()?;
|
let ctx = XContext::new()?;
|
||||||
|
|
||||||
// Try to get the currently active window using EWMH (_NET_ACTIVE_WINDOW).
|
// Try to get the currently active window using EWMH (_NET_ACTIVE_WINDOW).
|
||||||
let window = get_active_window(&ctx).unwrap_or_else(|| {
|
let window = get_active_window(&ctx)
|
||||||
eprintln!("Could not get active window. Falling back to input focus.");
|
.or_else(|| get_focused_window(&ctx))
|
||||||
get_focused_window(&ctx).unwrap_or(ctx.root)
|
.unwrap_or(ctx.root);
|
||||||
});
|
|
||||||
|
|
||||||
// Read the size and position of that window.
|
// Read the size and position of that window.
|
||||||
let geom = get_window_geometry(&ctx, window)?;
|
let geom = get_window_geometry(&ctx, window)?;
|
||||||
|
|
||||||
let x = u16::try_from(geom.x.max(0)).unwrap();
|
let x = u16::try_from(geom.x.max(0))?;
|
||||||
let y = u16::try_from(geom.y.max(0)).unwrap();
|
let y = u16::try_from(geom.y.max(0))?;
|
||||||
|
|
||||||
// Capture only the window rectangle.
|
// Capture only the window rectangle.
|
||||||
let img = capture_rect(&ctx, x, y, geom.width, geom.height)?;
|
let img = capture_rect(&ctx, x, y, geom.width, geom.height)?;
|
||||||
|
|
||||||
// Build output path: ~/Pictures/Screenshots/window_TIMESTAMP.png
|
// Get output file path
|
||||||
let timestamp = Local::now().format("%Y%m%d%H%M%S").to_string();
|
let path = make_screenshot_path()?;
|
||||||
|
|
||||||
let mut path = dirs::home_dir().unwrap_or_else(|| ".".into());
|
|
||||||
path.push("Pictures");
|
|
||||||
path.push("Screenshots");
|
|
||||||
fs::create_dir_all(&path)?;
|
|
||||||
path.push(format!("window_{timestamp}.png"));
|
|
||||||
|
|
||||||
let path_str = path.to_string_lossy();
|
let path_str = path.to_string_lossy();
|
||||||
|
|
||||||
|
// Save image to path
|
||||||
save_png(&path_str, geom.width, geom.height, &img)?;
|
save_png(&path_str, geom.width, geom.height, &img)?;
|
||||||
|
|
||||||
println!("Saved {path_str}");
|
println!("Saved screenshot: {path_str}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user