Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: scale problem #88

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 8 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions libwayshot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ thiserror = "1"
wayland-client = "0.31.1"
wayland-protocols = { version = "0.31.0", features = ["client", "unstable"] }
wayland-protocols-wlr = { version = "0.2.0", features = ["client"] }
tempfile = "3.10.0"
99 changes: 71 additions & 28 deletions libwayshot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ mod screencopy;

use std::{
collections::HashSet,
f64,
fs::File,
io::Write,
os::fd::AsFd,
sync::atomic::{AtomicBool, Ordering},
thread,
Expand Down Expand Up @@ -395,30 +397,25 @@ impl WayshotConnection {

pub fn capture_frame_copies(
&self,
output_capture_regions: &Vec<(OutputInfo, Option<EmbeddedRegion>)>,
output_capture_regions: &[(OutputInfo, Option<EmbeddedRegion>)],
cursor_overlay: bool,
) -> Result<Vec<(FrameCopy, FrameGuard, OutputInfo)>> {
let frame_copies = thread::scope(|scope| -> Result<_> {
let join_handles = output_capture_regions
.into_iter()
.iter()
.map(|(output_info, capture_region)| {
scope.spawn(move || {
self.capture_frame_copy(
cursor_overlay,
&output_info,
capture_region.clone(),
)
.map(|(frame_copy, frame_guard)| {
(frame_copy, frame_guard, output_info.clone())
})
self.capture_frame_copy(cursor_overlay, output_info, *capture_region)
.map(|(frame_copy, frame_guard)| {
(frame_copy, frame_guard, output_info.clone())
})
})
})
.collect::<Vec<_>>();

join_handles
.into_iter()
.map(|join_handle| join_handle.join())
.flatten()
.flat_map(|join_handle| join_handle.join())
.collect::<Result<_>>()
})?;

Expand Down Expand Up @@ -457,8 +454,9 @@ impl WayshotConnection {
));
}
};
let shm = self.globals.bind::<WlShm, _, _>(&qh, 1..=1, ())?;

for (frame_copy, frame_guard, output_info) in frames {
for (frame_copy, _frame_guard, output_info) in frames {
tracing::span!(
tracing::Level::DEBUG,
"overlay_frames::surface",
Expand All @@ -476,11 +474,44 @@ impl WayshotConnection {
output_info.wl_output.clone(),
);

let file = tempfile::tempfile().unwrap();
let image: DynamicImage = frame_copy.try_into()?;
let image = {
if output_info.region.size != frame_copy.frame_format.size {
image::imageops::resize(
&image,
output_info.region.size.width,
output_info.region.size.height,
image::imageops::FilterType::Triangle,
)
} else {
image.into_rgba8()
}
};

init_overlay(&image, &file);
let pool = shm.create_pool(
file.as_fd(),
(output_info.region.size.width * output_info.region.size.height * 4) as i32,
&qh,
(),
);

let buffer = pool.create_buffer(
0,
output_info.region.size.width as i32,
output_info.region.size.height as i32,
(output_info.region.size.width * 4) as i32,
frame_copy.frame_format.format,
&qh,
(),
);

layer_surface.set_exclusive_zone(-1);
layer_surface.set_anchor(Anchor::Top | Anchor::Left);
layer_surface.set_size(
frame_copy.frame_format.size.width,
frame_copy.frame_format.size.height,
output_info.region.size.width,
output_info.region.size.height,
);

debug!("Committing surface creation changes.");
Expand All @@ -492,8 +523,8 @@ impl WayshotConnection {
}

surface.set_buffer_transform(output_info.transform);
surface.set_buffer_scale(output_info.scale);
surface.attach(Some(&frame_guard.buffer), 0, 0);
surface.set_buffer_scale(1);
surface.attach(Some(&buffer), 0, 0);

debug!("Committing surface with attached buffer.");
surface.commit();
Expand All @@ -515,12 +546,12 @@ impl WayshotConnection {
let outputs_capture_regions: &Vec<(OutputInfo, Option<EmbeddedRegion>)> =
&match region_capturer {
RegionCapturer::Outputs(ref outputs) => outputs
.into_iter()
.iter()
.map(|output_info| (output_info.clone(), None))
.collect(),
RegionCapturer::Region(capture_region) => self
.get_all_outputs()
.into_iter()
.iter()
.filter_map(|output_info| {
tracing::span!(
tracing::Level::DEBUG,
Expand All @@ -547,7 +578,7 @@ impl WayshotConnection {
.collect(),
RegionCapturer::Freeze(_) => self
.get_all_outputs()
.into_iter()
.iter()
.map(|output_info| (output_info.clone(), None))
.collect(),
};
Expand All @@ -565,7 +596,7 @@ impl WayshotConnection {
thread::scope(|scope| {
let rotate_join_handles = frames
.into_iter()
.map(|(frame_copy, _, _)| {
.map(|(frame_copy, _, output_info)| {
scope.spawn(move || {
let image = (&frame_copy).try_into()?;
Ok((
Expand All @@ -576,15 +607,15 @@ impl WayshotConnection {
frame_copy.frame_format.size.height,
),
frame_copy,
output_info,
))
})
})
.collect::<Vec<_>>();

rotate_join_handles
.into_iter()
.map(|join_handle| join_handle.join())
.flatten()
.flat_map(|join_handle| join_handle.join())
.fold(
None,
|composite_image: Option<Result<_>>, image: Result<_>| {
Expand All @@ -598,12 +629,15 @@ impl WayshotConnection {

Some(|| -> Result<_> {
let mut composite_image = composite_image?;
let (image, frame_copy) = image?;
let (image, frame_copy, output_info) = image?;
let change = frame_copy.frame_format.size.width as f64
/ output_info.region.size.width as f64;
let real_select_region = capture_region.region_change(change);
let (x, y) = (
frame_copy.region.inner.position.x as i64
- capture_region.inner.position.x as i64,
- real_select_region.inner.position.x as i64,
frame_copy.region.inner.position.y as i64
- capture_region.inner.position.y as i64,
- real_select_region.inner.position.y as i64,
);
tracing::span!(
tracing::Level::DEBUG,
Expand Down Expand Up @@ -660,18 +694,27 @@ impl WayshotConnection {
/// Take a screenshot from all of the specified outputs.
pub fn screenshot_outputs(
&self,
outputs: &Vec<OutputInfo>,
outputs: &[OutputInfo],
cursor_overlay: bool,
) -> Result<DynamicImage> {
if outputs.is_empty() {
return Err(Error::NoOutputs);
}

self.screenshot_region_capturer(RegionCapturer::Outputs(outputs.clone()), cursor_overlay)
self.screenshot_region_capturer(RegionCapturer::Outputs(outputs.to_vec()), cursor_overlay)
}

/// Take a screenshot from all accessible outputs.
pub fn screenshot_all(&self, cursor_overlay: bool) -> Result<DynamicImage> {
self.screenshot_outputs(self.get_all_outputs(), cursor_overlay)
}
}

fn init_overlay(origin_image: &image::ImageBuffer<image::Rgba<u8>, Vec<u8>>, tmp: &File) {
let mut buf = std::io::BufWriter::new(tmp);

for index in origin_image.pixels() {
buf.write_all(&index.0).unwrap();
}
buf.flush().unwrap();
}
25 changes: 24 additions & 1 deletion libwayshot/src/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ pub struct LogicalRegion {
pub inner: Region,
}

impl LogicalRegion {
pub(crate) fn region_change(&self, change: f64) -> Self {
Self {
inner: self.inner.region_change(change),
}
}
}

/// An embedded region is a region entirely inside of another (often an output).
///
/// It can only be contained inside of another and cannot exceed its bounds.
Expand Down Expand Up @@ -63,6 +71,21 @@ pub struct Region {
pub size: Size,
}

impl Region {
fn region_change(&self, change: f64) -> Self {
Self {
position: Position {
x: (self.position.x as f64 * change) as i32,
y: (self.position.y as f64 * change) as i32,
},
size: Size {
width: (self.size.width as f64 * change) as u32,
height: (self.size.height as f64 * change) as u32,
},
}
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
pub struct Position {
/// X coordinate.
Expand Down Expand Up @@ -113,7 +136,7 @@ impl EmbeddedRegion {
};

Some(Self {
relative_to: relative_to,
relative_to,
inner: Region {
position: Position { x: x1, y: y1 },
size: Size { width, height },
Expand Down
2 changes: 1 addition & 1 deletion wayshot/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct Cli {

/// Arguments to call slurp with for selecting a region
#[arg(short, long, value_name = "SLURP_ARGS")]
pub slurp: Option<String>,
pub slurp: bool,

/// Enable cursor in screenshots
#[arg(short, long)]
Expand Down
8 changes: 2 additions & 6 deletions wayshot/src/wayshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,11 @@ fn main() -> Result<()> {
return Ok(());
}

let image_buffer = if let Some(slurp_region) = cli.slurp {
let slurp_region = slurp_region.clone();
let image_buffer = if cli.slurp {
wayshot_conn.screenshot_freeze(
Box::new(move || {
|| -> Result<LogicalRegion> {
let slurp_output = Command::new("slurp")
.args(slurp_region.split(" "))
.output()?
.stdout;
let slurp_output = Command::new("slurp").arg("-d").output()?.stdout;

utils::parse_geometry(&String::from_utf8(slurp_output)?)
}()
Expand Down
Loading