Skip to content
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
79 changes: 79 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: CI & Deploy

on:
push:
branches:
- master
pull_request:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

jobs:
# --- JOB 1: TEST ---
test:
name: Run mdbook test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Install Rust
run: |
rustup set profile minimal
rustup toolchain install stable
rustup default stable

- name: Install latest mdbook
run: |
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
mkdir bin
curl -sSL $url | tar -xz --directory=bin
echo "$(pwd)/bin" >> $GITHUB_PATH

- name: Run tests
run: mdbook test

# --- JOB 2: DEPLOY ---
deploy:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
needs: test # This ensures Deploy ONLY runs if Test passes!
# This ensures Deploy ONLY runs on the main branch, not on PRs
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Install latest mdbook
run: |
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
mkdir bin
curl -sSL $url | tar -xz --directory=bin
echo "$(pwd)/bin" >> $GITHUB_PATH

- name: Build Book
run: mdbook build

- name: Setup Pages
uses: actions/configure-pages@v6

- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
path: "book" # The default mdbook output folder

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
/src/.*
/book
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
authors = ["Atliac"]
description = "An ergonomic Rust wrapper for Windows.Graphics.Capture API"
repository = "https://github.com/atliac/wgc"
documentation = "https://deepwiki.com/Atliac/wgc"
documentation = "https://books.atliac.com/wgc"
homepage = "https://github.com/atliac/wgc"
readme = "README.md"
keywords = ["windows", "screen-capture", "recording", "machine-learning"]
Expand Down
5 changes: 2 additions & 3 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Migration Guide

This document describes breaking API changes and how to update downstream code.
For the full history of changes, see [CHANGELOG.md](./CHANGELOG.md).

- [v1.x → v2.0](#v1x--v20)

Expand All @@ -14,7 +13,7 @@ For the full history of changes, see [CHANGELOG.md](./CHANGELOG.md).
| 1 | `Frame::read_pixels(Option<FrameSize>)` split into `Frame::pixels()` and `Frame::pixels_fitted(FrameSize)` | Rename calls (see [below](#1-frameread_pixels--framepixels--framepixels_fitted)) |
| 2 | `WgcSettings` is now `#[non_exhaustive]` | Build it from `WgcSettings::default()` and assign fields (see [below](#2-wgcsettings-is-now-non_exhaustive)) |
| 3 | The `tracing` Cargo feature was removed; `tracing` is a required dependency | Drop `--features tracing` and `features = ["tracing"]` |
| 4 | The `tutorial` example was removed | Use the [examples](./examples/) and [DeepWiki docs](https://deepwiki.com/Atliac/wgc) |
| 4 | The `tutorial` example was removed | Use the [examples](./examples/) and [tutorial docs](https://books.atliac.com/wgc) |

### 1. `Frame::read_pixels` → `Frame::pixels` / `Frame::pixels_fitted`

Expand Down Expand Up @@ -178,7 +177,7 @@ RUST_LOG=wgc=debug cargo run --example save_image
- Read the [save_image](./examples/save_image.rs) example, which now demonstrates both
`pixels()` (native size) and `pixels_fitted()` (letterboxed scaling).
- Read the [show_image](./examples/show_image.rs) example for a continuous capture loop.
- Consult the [DeepWiki documentation](https://deepwiki.com/Atliac/wgc) for a
- Consult the [tutorial documentation](https://books.atliac.com/wgc) for a
narrative walkthrough of the crate.


Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Rust CI](https://github.com/Atliac/wgc/actions/workflows/ci.yml/badge.svg)](https://github.com/Atliac/wgc/actions/workflows/ci.yml)
[![Stability: Stable](https://img.shields.io/badge/stability-stable-brightgreen)](https://github.com/atliac/wgc)
[![Maintenance: Active](https://img.shields.io/badge/maintenance-active-blue)](https://github.com/atliac/wgc)
[![Doc: DeepWiki](https://img.shields.io/badge/Doc-DeepWiki-blue)](https://deepwiki.com/Atliac/wgc)
[![Docs: Tutorial](https://img.shields.io/badge/Docs-Tutorial-blue)](https://books.atliac.com/wgc)

A simple and ergonomic Rust wrapper for Windows.Graphics.Capture API, enabling screen/window capture on Windows 10/11.

Expand Down Expand Up @@ -65,8 +65,8 @@ Check out the [examples](./examples/) directory for more detailed usage examples

## Documentation

- [Tutorial](https://books.atliac.com/wgc): narrative documentation and architecture overview.
- [Migration guide](./MIGRATION.md): how to upgrade from `wgc` 1.x to 2.0.
- [DeepWiki](https://deepwiki.com/Atliac/wgc): narrative documentation and architecture overview.
- [docs.rs](https://docs.rs/wgc): API reference.

## License
Expand Down
14 changes: 14 additions & 0 deletions book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[book]
authors = ["Atliac"]
language = "en"
src = "docs"
title = "wgc Tutorial"

[build]
build-dir = "book"
create-missing = true

[output.html]
default-theme = "rust"
git-repository-url = "https://github.com/Atliac/wgc"
edit-url-template = "https://github.com/Atliac/wgc/edit/main/docs/{path}"
8 changes: 8 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Summary

[Introduction](index.md)
[Getting Started](getting_started.md)
[Selecting Targets](selecting_targets.md)
[Configuration & Capabilities](configuration.md)
[Capturing Frames](capturing_frames.md)
[Examples & Practical Use](examples.md)
81 changes: 81 additions & 0 deletions docs/capturing_frames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Capturing Frames

`Wgc` is an iterator over captured frames. When iterating over `Wgc`, each step yields a `Result<Frame, WgcError>`.

## The `Frame` Type

Each `Frame` provides information about the captured frame and methods for extracting raw pixel data or accessing the underlying Direct3D surface texture.

### Frame Properties

- `frame.size()`: Returns `FrameSize { width, height }` of the captured frame in pixels.
- `frame.system_relative_time()`: Returns the capture timestamp (`Duration` since system startup via QueryPerformanceCounter).

### Accessing Pixels

#### 1. Native Size Pixels (`pixels`)

Reads the raw pixel buffer at the captured frame's native resolution.

```rust,ignore
use wgc::*;

fn main() -> anyhow::Result<()> {
let item = new_item_with_picker(None)?;
let wgc = Wgc::new(item, Default::default())?;

for frame in wgc.take(1) {
let frame = frame?;
let size = frame.size()?;
let pixels: Vec<u8> = frame.pixels()?;

println!("Read {} bytes (width: {}, height: {})", pixels.len(), size.width, size.height);
}
Ok(())
}
```

#### 2. Resolution-Fitted Pixels (`pixels_fitted`)

Scales the frame to fit a target `FrameSize` while preserving aspect ratio. Any remaining space is letterboxed with gray borders. This is ideal for Machine Learning (e.g. YOLO/ResNet) and computer vision pipelines that require constant input dimensions.

```rust,ignore
use wgc::*;

fn main() -> anyhow::Result<()> {
let item = new_item_with_picker(None)?;
let wgc = Wgc::new(item, Default::default())?;
let target_size = FrameSize { width: 512, height: 512 };

for frame in wgc.take(1) {
let frame = frame?;
let fitted_pixels: Vec<u8> = frame.pixels_fitted(target_size)?;

// Guaranteed buffer length: width * height * 4 (RGBA8/BGRA8)
assert_eq!(fitted_pixels.len(), (512 * 512 * 4) as usize);
}
Ok(())
}
```

### Direct3D 11 Surface Access (Zero-Copy)

For low-latency GPU workflows (e.g., Direct3D rendering, video encoding with NVENC/AMF, or Direct2D drawing), you can access the underlying `ID3D11Texture2D` texture directly:

```rust,ignore
use wgc::*;

fn main() -> anyhow::Result<()> {
let item = new_item_with_picker(None)?;
let wgc = Wgc::new(item, Default::default())?;

for frame in wgc.take(1) {
let frame = frame?;

// Direct3D 11 surface access
let surface = frame.surface()?; // Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface
let texture = frame.texture()?; // windows::Win32::Graphics::Direct3D11::ID3D11Texture2D
}
Ok(())
}
```
76 changes: 76 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Configuration & Capabilities

`wgc` allows fine-grained customization of capture sessions using `WgcSettings`. Additionally, runtime capability functions in `wgc::capabilities` let you check which features are supported on the host Windows system.

## `WgcSettings` Configuration

`WgcSettings` controls frame formats, buffer queue length, scaling interpolation, and optional capture features.

```rust,ignore
use std::time::Duration;
use wgc::settings::{FrameInterpolationMode, PixelFormat, WgcSettings};

let mut settings = WgcSettings::default();

// 1. Pixel Format (RGBA8 or BGRA8)
settings.pixel_format = PixelFormat::RGBA8;

// 2. Buffer Queue Length (number of frames queued in memory)
settings.frame_queue_length = 2;

// 3. Scaling Interpolation Mode (for fitted letterbox scaling)
settings.frame_interpolation_mode = FrameInterpolationMode::Linear;

// 4. Optional Windows 10/11 features (must check capabilities first!)
settings.capture_cursor = Some(false); // Hide mouse cursor
settings.display_border = Some(false); // Hide yellow capture border
settings.include_secondary_windows = Some(true); // Include popups/child windows
settings.min_update_interval = Some(Duration::from_millis(16)); // Throttle frame rate (~60 FPS)
```

### Interpolation Modes

When using resolution scaling / letterboxing (`pixels_fitted`), you can set `frame_interpolation_mode` to one of the following:

- `NearestNeighbor`: Fastest processing, lower visual fidelity.
- `Linear`: Balanced performance and quality (default).
- `Cubic`: Smooth 16-sample interpolation.
- `MultiSampleLinear`: Anti-aliasing for small scale-downs.
- `HighQualityCubic`: Best visual quality for significant downscaling.

---

## Checking System Capabilities

Windows Graphics Capture added several settings in newer Windows updates (such as hiding the capture border or cursor). Attempting to enable an unsupported setting on older Windows builds will result in a runtime error.

You can inspect capabilities using the `capabilities` module:

```rust,ignore
use wgc::capabilities;

fn main() -> anyhow::Result<()> {
if !capabilities::is_wgc_supported()? {
println!("Windows Graphics Capture is not supported on this OS.");
return Ok(());
}

if capabilities::is_cursor_configurable()? {
println!("Cursor capture toggling is supported!");
}

if capabilities::is_border_configurable()? {
println!("Border visibility toggling is supported!");
}

if capabilities::is_dirty_region_mode_configurable()? {
println!("Dirty region tracking is supported!");
}

if capabilities::is_min_update_interval_configurable()? {
println!("Minimum update interval configuration is supported!");
}

Ok(())
}
```
Loading