forked from michael/leanshot
window kinda works?
This commit is contained in:
parent
f9126c4f83
commit
201b2e480f
7 changed files with 142 additions and 32 deletions
|
@ -4,16 +4,38 @@ use gui::GUI;
|
|||
use options::{Options, Region};
|
||||
use xlib::Image;
|
||||
|
||||
use ImageExt;
|
||||
use Rectangle;
|
||||
|
||||
pub fn capture(opt: &Options) -> Result<Image, ScreenshotError> {
|
||||
let gui = GUI::new()?;
|
||||
|
||||
let window_to_capture = match opt.region {
|
||||
Region::Fullscreen | Region::Selection => gui.display.get_default_root_window()?,
|
||||
Region::ActiveWindow => gui.get_active_window()?,
|
||||
};
|
||||
// let window_to_capture = match opt.region {
|
||||
// Region::Fullscreen | Region::Selection => gui.display.get_default_root_window()?,
|
||||
// Region::ActiveWindow => gui.get_active_window()?,
|
||||
// };
|
||||
let window_to_capture = gui.display.get_default_root_window()?;
|
||||
|
||||
let capture = gui.capture_window(window_to_capture)?;
|
||||
println!("captured the window");
|
||||
let clip = match opt.region {
|
||||
Region::ActiveWindow => {
|
||||
let win = gui.get_active_window()?;
|
||||
let attr = win.get_attributes()?;
|
||||
let width = attr.get_width();
|
||||
let height = attr.get_height();
|
||||
let root = gui.display.get_default_root_window()?;
|
||||
let (x, y, _) = gui.display.translate_coordinates(win, 0, 0, root)?;
|
||||
Some(Rectangle {
|
||||
x: x as u32,
|
||||
y: y as u32,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
capture.write_png(&opt.outfile, clip)?;
|
||||
|
||||
// let final_capture = match opt.region {
|
||||
// Region::Fullscreen | Region::ActiveWindow => window_capture,
|
||||
|
|
|
@ -15,6 +15,12 @@ impl GUI {
|
|||
|
||||
/// Captures the window and produces a DynamicImage.
|
||||
pub fn capture_window(&self, window: Window) -> Result<Image, ScreenshotError> {
|
||||
let attr = window.get_attributes()?;
|
||||
let width = attr.get_width();
|
||||
let height = attr.get_height();
|
||||
let root = self.display.get_default_root_window()?;
|
||||
let (x, y, _) = self.display.translate_coordinates(window, 0, 0, root)?;
|
||||
println!("x={} y={} width={} height={}", x, y, width, height);
|
||||
window.get_image().map_err(|err| err.into())
|
||||
}
|
||||
|
||||
|
|
44
src/image.rs
44
src/image.rs
|
@ -6,23 +6,34 @@ use png::{self, Encoder, HasParameters};
|
|||
use xlib::{Image, ImageByteOrder};
|
||||
|
||||
use errors::ScreenshotError;
|
||||
use Rectangle;
|
||||
|
||||
pub trait ImageExt {
|
||||
fn to_data_buf(&self) -> Result<Vec<u8>, ScreenshotError>;
|
||||
fn write_png(&self, out: impl AsRef<Path>) -> Result<(), ScreenshotError>;
|
||||
fn to_data_buf(&self, rect: Rectangle) -> Result<Vec<u8>, ScreenshotError>;
|
||||
fn write_png(
|
||||
&self,
|
||||
out: impl AsRef<Path>,
|
||||
rect: Option<Rectangle>,
|
||||
) -> Result<(), ScreenshotError>;
|
||||
}
|
||||
|
||||
impl ImageExt for Image {
|
||||
/// Converts the image buffer into RGB(A).
|
||||
fn to_data_buf(&self) -> Result<Vec<u8>, ScreenshotError> {
|
||||
let size = self.get_size();
|
||||
fn to_data_buf(&self, rect: Rectangle) -> Result<Vec<u8>, ScreenshotError> {
|
||||
let (full_width, _) = (self.get_width() as usize, self.get_height() as usize);
|
||||
let bytes_per_row = 4 * rect.width as usize;
|
||||
let size = bytes_per_row * rect.height as usize;
|
||||
let mut buf = vec![1; size];
|
||||
let sbuf = self.buffer(); // source buffer
|
||||
let mut sx = 0usize; // source idx
|
||||
let mut dx = 0usize; // dest idx
|
||||
let mut rx = rect.y as usize;
|
||||
if let ImageByteOrder::LSBFirst = self.get_byte_order()? {
|
||||
// LSBFirst
|
||||
while dx < size {
|
||||
while rx < rect.height as usize {
|
||||
let mut sx = (rx * full_width + rect.x as usize) * 4; // source idx
|
||||
let mut dx = rx * bytes_per_row; // dest idx
|
||||
let edx = (rx + 1) * bytes_per_row;
|
||||
// println!("sx={} dx={} edx={}", sx,dx,edx);
|
||||
while dx < edx {
|
||||
buf[dx] = sbuf.get_byte(sx + 2).unwrap() as u8;
|
||||
buf[dx + 1] = sbuf.get_byte(sx + 1).unwrap() as u8;
|
||||
buf[dx + 2] = sbuf.get_byte(sx).unwrap() as u8;
|
||||
|
@ -34,19 +45,32 @@ impl ImageExt for Image {
|
|||
sx += 4;
|
||||
dx += 4;
|
||||
}
|
||||
rx += 1;
|
||||
}
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn write_png(&self, out: impl AsRef<Path>) -> Result<(), ScreenshotError> {
|
||||
fn write_png(
|
||||
&self,
|
||||
out: impl AsRef<Path>,
|
||||
rect: Option<Rectangle>,
|
||||
) -> Result<(), ScreenshotError> {
|
||||
let rect = rect.unwrap_or_else(|| Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: self.get_width(),
|
||||
height: self.get_height(),
|
||||
});
|
||||
|
||||
let file = File::create(out.as_ref())?;
|
||||
let ref mut out = BufWriter::new(file);
|
||||
|
||||
let mut encoder = Encoder::new(out, self.get_width(), self.get_height());
|
||||
let mut encoder = Encoder::new(out, rect.width, rect.height);
|
||||
encoder.set(png::ColorType::RGBA).set(png::BitDepth::Eight);
|
||||
let mut writer = encoder.write_header()?;
|
||||
|
||||
let data = self.to_data_buf()?;
|
||||
let data = self.to_data_buf(rect)?;
|
||||
writer.write_image_data(data.as_slice())?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ extern crate screenshot;
|
|||
extern crate structopt;
|
||||
|
||||
use failure::Error;
|
||||
use screenshot::{capture, ImageExt, Options};
|
||||
use screenshot::{capture, Options};
|
||||
use structopt::StructOpt;
|
||||
|
||||
pub fn main() -> Result<(), Error> {
|
||||
let opt = Options::from_args();
|
||||
let image = capture(&opt)?;
|
||||
image.write_png(opt.outfile).map_err(|err| err.into())
|
||||
// let image = capture(&opt)?;
|
||||
capture(&opt).map(|_| ()).map_err(|err| err.into())
|
||||
}
|
||||
|
|
|
@ -18,27 +18,76 @@ impl Display {
|
|||
pub fn connect(display_name: impl AsRef<str>) -> Result<Display, X11Error> {
|
||||
let display_name = CString::new(display_name.as_ref()).unwrap();
|
||||
let inner = unsafe { x::XOpenDisplay(display_name.as_ptr()) };
|
||||
if inner.is_null() {
|
||||
return Err(X11Error::DisplayOpenError);
|
||||
}
|
||||
Ok(Display { inner })
|
||||
}
|
||||
|
||||
/// Returns the root window for the given screen.
|
||||
pub fn get_root_window(&self, screen: i32) -> Result<Window, X11Error> {
|
||||
let inner = unsafe { x::XRootWindow(self.inner, screen) };
|
||||
if inner == 0 {
|
||||
return Err(X11Error::GetWindowError);
|
||||
}
|
||||
let window = Window {
|
||||
display: self.inner,
|
||||
inner: unsafe { x::XRootWindow(self.inner, screen) },
|
||||
inner,
|
||||
};
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
/// Returns the root window for the default screen.
|
||||
pub fn get_default_root_window(&self) -> Result<Window, X11Error> {
|
||||
let inner = unsafe { x::XDefaultRootWindow(self.inner) };
|
||||
if inner == 0 {
|
||||
return Err(X11Error::GetWindowError);
|
||||
}
|
||||
let window = Window {
|
||||
display: self.inner,
|
||||
inner: unsafe { x::XDefaultRootWindow(self.inner) },
|
||||
inner,
|
||||
};
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
/// Translate coordinates relative to w1 to coordinates relative to w2.
|
||||
/// If the coordinates are contained in a mapped child of the destination window, the third return
|
||||
/// value will hold that child window.
|
||||
pub fn translate_coordinates(
|
||||
&self,
|
||||
w1: Window,
|
||||
x: i32,
|
||||
y: i32,
|
||||
w2: Window,
|
||||
) -> Result<(i32, i32, Option<Window>), X11Error> {
|
||||
let mut rx = 0;
|
||||
let mut ry = 0;
|
||||
let mut child_return: x::Window = 0;
|
||||
let status = unsafe {
|
||||
x::XTranslateCoordinates(
|
||||
self.inner,
|
||||
w1.inner,
|
||||
w2.inner,
|
||||
x,
|
||||
y,
|
||||
&mut rx,
|
||||
&mut ry,
|
||||
&mut child_return,
|
||||
)
|
||||
};
|
||||
if status == 0 {
|
||||
return Err(X11Error::TranslateCoordinatesError);
|
||||
}
|
||||
let child = match child_return {
|
||||
0 => None,
|
||||
val => Some(Window {
|
||||
display: self.inner,
|
||||
inner: val,
|
||||
}),
|
||||
};
|
||||
Ok((rx, ry, child))
|
||||
}
|
||||
|
||||
/// eturns the focus window and the current focus state.
|
||||
pub fn get_input_focus(&self) -> Result<(Window, i32), X11Error> {
|
||||
let mut focus_return: x::Window = 0;
|
||||
|
|
|
@ -2,12 +2,21 @@
|
|||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum X11Error {
|
||||
#[fail(display = "failed to open display")]
|
||||
DisplayOpenError,
|
||||
|
||||
#[fail(display = "failed to get attributes")]
|
||||
GetAttributesError,
|
||||
|
||||
#[fail(display = "failed to get window")]
|
||||
GetWindowError,
|
||||
|
||||
#[fail(display = "invalid byte order")]
|
||||
InvalidByteOrder,
|
||||
|
||||
#[fail(display = "failed to translate coordinates")]
|
||||
TranslateCoordinatesError,
|
||||
|
||||
#[fail(display = "error")]
|
||||
Error,
|
||||
}
|
|
@ -10,11 +10,11 @@ extern crate libc;
|
|||
extern crate x11;
|
||||
|
||||
mod display;
|
||||
mod error;
|
||||
mod errors;
|
||||
mod image;
|
||||
mod window;
|
||||
|
||||
pub use display::Display;
|
||||
pub use error::X11Error;
|
||||
pub use errors::X11Error;
|
||||
pub use image::{Image, ImageByteOrder, PixBuffer};
|
||||
pub use window::{Window, WindowAttributes};
|
||||
|
|
Loading…
Reference in a new issue