Add module output.rs for image file path

- Modularity
- Avoid code duplication
- FIx comments in `core.rs`
This commit is contained in:
Candifloss 2025-12-08 16:12:03 +05:30
parent 31900b4a17
commit eea3c757c0
4 changed files with 45 additions and 43 deletions

View File

@ -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(

View File

@ -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
View 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)
}

View File

@ -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(())
} }