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

feat: windows支持app_name #95

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 21 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy

- name: Cargo fmt
Expand All @@ -40,3 +41,23 @@ jobs:

- name: Test
run: cargo test
publish:
name: Publish
runs-on: ubuntu-latest
needs:
- lint
steps:
- uses: actions/checkout@v3

- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy

- name: Publish
if: github.event_name != 'pull_request'
env:
CARGO_TOKEN: ${{ secrets.CARGO_TOKEN }}
run: cargo publish --registry crates-io --token $NPM_TOKEN
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "xcap"
version = "0.0.2"
version = "0.0.3"
edition = "2021"
description = "A cross-platform screen capture library"
description = "XCap is a cross-platform screen capture library written in Rust. It supports Linux (X11, Wayland), MacOS, and Windows. XCap supports screenshot and video recording (to be implemented)."
license = "Apache-2.0"
documentation = "https://docs.rs/xcap"
homepage = "https://github.com/nashaofu/xcap"
Expand All @@ -13,6 +13,7 @@ keywords = ["screen", "monitor", "window", "capture", "image"]

[dependencies]
image = "0.24"
log = "0.4"
thiserror = "1.0"

[target.'cfg(target_os = "macos")'.dependencies]
Expand All @@ -26,6 +27,9 @@ windows = { version = "0.52", features = [
"Win32_Graphics_Dwm",
"Win32_UI_WindowsAndMessaging",
"Win32_Storage_Xps",
"Win32_System_Threading",
"Win32_System_ProcessStatus",
"Win32_Storage_FileSystem",
] }

[target.'cfg(target_os="linux")'.dependencies]
Expand Down
131 changes: 131 additions & 0 deletions README-zh_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# XCap

[English](README.md) | 简体中文

XCap 是一个使用 Rust 编写的跨平台的屏幕捕获库,它支持 Linux(X11,Wayland)、MacOS 与 Windows。XCap 支持截图与视频录制(待实现)。

## 功能

- 跨平台: 支持 Linux(X11,Wayland)、MacOS 与 Windows。
- 支持多种截图模式: 可以对屏幕与窗口进行截图。
- 支持视频录制:支持对屏幕或窗口进行录制(待实现)。

### 实现状态

| 功能 | Linux(X11) | Linux(Wayland) | MacOS | Windows |
| -------- | ---------- | -------------- | ----- | ------- |
| 屏幕截图 | ✅ | ⛔ | ✅ | ✅ |
| 窗口截图 | ✅ | ⛔ | ✅ | ✅ |
| 屏幕录制 | 🛠️ | 🛠️ | 🛠️ | 🛠️ |
| 窗口录制 | 🛠️ | 🛠️ | 🛠️ | 🛠️ |

- ✅: 功能可用
- ⛔: 功能可用,但在一些特殊场景下未完全支持
- 🛠️: 待开发

## 例子

- 屏幕截图

```rust
use std::time::Instant;
use xcap::Monitor;

fn normalized(filename: &str) -> String {
filename
.replace("|", "")
.replace("\\", "")
.replace(":", "")
.replace("/", "")
}

fn main() {
let start = Instant::now();
let monitors = Monitor::all().unwrap();

for monitor in monitors {
let image = monitor.capture_image().unwrap();

image
.save(format!("target/monitor-{}.png", normalized(monitor.name())))
.unwrap();
}

println!("运行耗时: {:?}", start.elapsed());
}
```

- 窗口截图

```rust
use std::time::Instant;
use xcap::Window;

fn normalized(filename: &str) -> String {
filename
.replace("|", "")
.replace("\\", "")
.replace(":", "")
.replace("/", "")
}

fn main() {
let start = Instant::now();
let windows = Window::all().unwrap();

let mut i = 0;

for window in windows {
// 最小化的窗口不能截屏
if window.is_minimized() {
continue;
}

println!(
"Window: {:?} {:?} {:?}",
window.title(),
(window.x(), window.y(), window.width(), window.height()),
(window.is_minimized(), window.is_maximized())
);

let image = window.capture_image().unwrap();
image
.save(format!(
"target/window-{}-{}.png",
i,
normalized(window.title())
))
.unwrap();

i += 1;
}

println!("运行耗时: {:?}", start.elapsed());
}
```

## Linux 系统要求

在 Linux 上,需要安装 `libxcb`, `libxrandr`与 `dbus`.

Debian/Ubuntu:

```sh
apt-get install libxcb1 libxrandr2 libdbus-1-3
```

Alpine:

```sh
apk add libxcb libxrandr dbus
```

ArchLinux:

```sh
pacman -S libxcb libxrandr dbus
```

## License

本项目采用 Apache 许可证。详情请查看 [LICENSE](./LICENSE) 文件。
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
# 📷 XCap
# XCap

XCap is a cross-platform screen capture library for MacOS, Windows, Linux (X11, Wayland) written in Rust. It provides a simple API for capturing screen capture of a screen or a specific area of a screen.
English | [简体中文](README-zh_CN.md)

XCap is a cross-platform screen capture library written in Rust. It supports Linux (X11, Wayland), MacOS, and Windows. XCap supports screenshot and video recording (to be implemented).

## Features

- Cross-platform support: Windows Mac and Linux.
- Multiple capture modes: screen window.
- Video capture、audio capture soon.
- Cross-platform: Supports Linux (X11, Wayland), MacOS, and Windows.
- Supports multiple screenshot modes: Can take screenshots of the screen and windows.
- Supports video recording: Supports recording of the screen or window (to be implemented).

### Implementation Status

| Feature | Linux(X11) | Linux(Wayland) | MacOS | Windows |
| ---------------- | ---------- | -------------- | ----- | ------- |
| Screen Capture | ✅ | ⛔ | ✅ | ✅ |
| Window Capture | ✅ | ⛔ | ✅ | ✅ |
| Screen Recording | 🛠️ | 🛠️ | 🛠️ | 🛠️ |
| Window Recording | 🛠️ | 🛠️ | 🛠️ | 🛠️ |

- ✅: Feature available
- ⛔: Feature available, but not fully supported in some special scenarios
- 🛠️: To be developed

## Example
## Examples

- Monitor capture
- Screen Capture

```rust
use xcap::Monitor;
use std::time::Instant;
use xcap::Monitor;

fn normalized(filename: &str) -> String {
filename
Expand All @@ -40,11 +55,11 @@ fn main() {
}
```

- Window capture
- Window Capture

```rust
use xcap::Window;
use std::time::Instant;
use xcap::Window;

fn normalized(filename: &str) -> String {
filename
Expand Down Expand Up @@ -89,7 +104,7 @@ fn main() {
}
```

## Linux Requirements
## Linux System Requirements

On Linux, you need to install `libxcb`, `libxrandr`, and `dbus`.

Expand All @@ -113,4 +128,4 @@ pacman -S libxcb libxrandr dbus

## License

This project is licensed under the Apache License. See the [LICENSE](../LICENSE) file for details.
This project is licensed under the Apache License. See the [LICENSE](./LICENSE) file for details.
5 changes: 3 additions & 2 deletions examples/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ fn main() {

for monitor in monitors {
println!(
"Monitor: {} {} {:?} {:?}",
"Monitor:\n id: {}\n name: {}\n position: {:?}\n size: {:?}\n state:{:?}\n",
monitor.id(),
monitor.name(),
(monitor.x(), monitor.y(), monitor.width(), monitor.height()),
(monitor.x(), monitor.y()),
(monitor.width(), monitor.height()),
(
monitor.rotation(),
monitor.scale_factor(),
Expand Down
5 changes: 3 additions & 2 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ fn main() {

for window in windows {
println!(
"Window: {} {} {} {:?} {:?} {:?}",
"Window:\n id: {}\n title: {}\n app_name: {}\n monitor: {:?}\n position: {:?}\n size {:?}\n state {:?}\n",
window.id(),
window.title(),
window.app_name(),
window.current_monitor().name(),
(window.x(), window.y(), window.width(), window.height()),
(window.x(), window.y()),
(window.width(), window.height()),
(window.is_minimized(), window.is_maximized())
);
}
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
mod error;
mod monitor;
mod utils;
mod window;

#[cfg(target_os = "macos")]
Expand Down
10 changes: 4 additions & 6 deletions src/linux/xorg_capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ use xcb::{
Connection,
};

use crate::{
error::{XCapError, XCapResult},
utils::image::vec_to_rgba_image,
};
use crate::error::{XCapError, XCapResult};

fn get_pixel8_rgba(
bytes: &[u8],
Expand Down Expand Up @@ -97,7 +94,6 @@ pub fn xorg_capture(
let bytes = get_image_reply.data();
let depth = get_image_reply.depth();

let mut rgba = vec![0u8; (width * height * 4) as usize];
let pixmap_format = setup
.pixmap_formats()
.iter()
Expand All @@ -115,6 +111,7 @@ pub fn xorg_capture(
_ => return Err(XCapError::new(format!("Unsupported {} depth", depth))),
};

let mut rgba = vec![0u8; (width * height * 4) as usize];
for y in 0..height {
for x in 0..width {
let index = ((y * width + x) * 4) as usize;
Expand All @@ -127,5 +124,6 @@ pub fn xorg_capture(
}
}

vec_to_rgba_image(width, height, rgba)
RgbaImage::from_raw(width, height, rgba)
.ok_or_else(|| XCapError::new("RgbaImage::from_raw failed"))
}
28 changes: 17 additions & 11 deletions src/macos/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use core_graphics::{
};
use image::RgbaImage;

use crate::{
error::{XCapError, XCapResult},
utils::image::{bgra_to_rgba_image, remove_extra_data},
};
use crate::error::{XCapError, XCapResult};

pub fn capture(
cg_rect: CGRect,
Expand All @@ -20,12 +17,21 @@ pub fn capture(

let width = cg_image.width();
let height = cg_image.height();
let clean_buf = remove_extra_data(
width,
height,
cg_image.bytes_per_row(),
Vec::from(cg_image.data().bytes()),
);
let bytes = Vec::from(cg_image.data().bytes());

// Some platforms e.g. MacOS can have extra bytes at the end of each row.
// See
// https://github.com/nashaofu/xcap/issues/29
// https://github.com/nashaofu/xcap/issues/38
let mut buffer = Vec::with_capacity(width * height * 4);
for row in bytes.chunks_exact(cg_image.bytes_per_row()) {
buffer.extend_from_slice(&row[..width * 4]);
}

for bgra in buffer.chunks_exact_mut(4) {
bgra.swap(0, 2);
}

bgra_to_rgba_image(width as u32, height as u32, clean_buf)
RgbaImage::from_raw(width as u32, height as u32, buffer)
.ok_or_else(|| XCapError::new("RgbaImage::from_raw failed"))
}
Loading
Loading