{"id":49448596,"url":"https://github.com/sunsided/miniscreenshot","last_synced_at":"2026-05-05T05:01:51.312Z","repository":{"id":354702066,"uuid":"1223237354","full_name":"sunsided/miniscreenshot","owner":"sunsided","description":"A pluggable, multi-crate Rust workspace for taking screenshots of windowed applications or the entire desktop","archived":false,"fork":false,"pushed_at":"2026-04-29T23:09:46.000Z","size":83,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T01:00:42.763Z","etag":null,"topics":["game-programming","rust","screenshot","skia","softbuffer","vello","wayland","wgpu"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/miniscreenshot","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sunsided.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-28T06:13:25.000Z","updated_at":"2026-04-29T23:00:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"39c2082b-24af-4f72-83be-624eb59ad7a5","html_url":"https://github.com/sunsided/miniscreenshot","commit_stats":null,"previous_names":["sunsided/miniscreenshot"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/sunsided/miniscreenshot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fminiscreenshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fminiscreenshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fminiscreenshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fminiscreenshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sunsided","download_url":"https://codeload.github.com/sunsided/miniscreenshot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sunsided%2Fminiscreenshot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32481556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"ssl_error","status_checked_at":"2026-04-30T13:12:06.837Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["game-programming","rust","screenshot","skia","softbuffer","vello","wayland","wgpu"],"created_at":"2026-04-30T00:12:58.979Z","updated_at":"2026-05-02T02:01:01.604Z","avatar_url":"https://github.com/sunsided.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# miniscreenshot\n\nA pluggable, multi-crate Rust workspace for taking screenshots of windowed\napplications or the entire desktop.\n\n---\n\n## Crate overview\n\n| Crate | Description |\n|-------|-------------|\n| [`miniscreenshot`](https://crates.io/crates/miniscreenshot) | **Core** — `Screenshot` type, PNG / PPM / PGM encoding, `Capture` / `CaptureAsync` / `MultiCapture` traits |\n| [`miniscreenshot-softbuffer`](https://crates.io/crates/miniscreenshot-softbuffer) | [`softbuffer`](https://crates.io/crates/softbuffer) integration + re-export. Enable the `winit` feature to re-export [`winit`](https://crates.io/crates/winit) alongside softbuffer. |\n| [`miniscreenshot-wgpu`](https://crates.io/crates/miniscreenshot-wgpu) | [`wgpu`](https://crates.io/crates/wgpu) texture readback + re-export |\n| [`miniscreenshot-wayland`](https://crates.io/crates/miniscreenshot-wayland) | Wayland `wlr-screencopy-v1` system capture + re-exports |\n| [`miniscreenshot-x11`](https://crates.io/crates/miniscreenshot-x11) | X11 (XGetImage / MIT-SHM) system capture + re-exports |\n| [`miniscreenshot-portal`](https://crates.io/crates/miniscreenshot-portal) | XDG Desktop Portal (ashpd) system capture; works on GNOME, KDE, wlroots, and inside Flatpak/Snap |\n| [`miniscreenshot-skia`](https://crates.io/crates/miniscreenshot-skia) | [`skia-safe`](https://crates.io/crates/skia-safe) re-export + surface screenshot helper |\n| [`miniscreenshot-vello`](https://crates.io/crates/miniscreenshot-vello) | [`vello`](https://crates.io/crates/vello) re-export + pixel readback support |\n| [`miniscreenshot-minifb`](https://crates.io/crates/miniscreenshot-minifb) | [`minifb`](https://crates.io/crates/minifb) re-export + pixel buffer screenshot helper |\n| [`miniscreenshot-desktop`](https://crates.io/crates/miniscreenshot-desktop) | **Umbrella** — auto-selects Wayland → X11 → Portal for \"just take a screenshot\" |\n\n---\n\n## Design goals\n\n* **Pluggable** — each rendering backend is a separate crate. Applications depend\n  only on what they use.\n* **No version conflicts** — every driver crate re-exports its underlying\n  library (e.g., `miniscreenshot_wgpu::wgpu`). Depending on a driver crate\n  is sufficient; no separate `wgpu`/`winit`/… dependency required.\n* **Low-friction output formats** — PNG (default), PPM and PGM are supported\n  out of the box. Format is inferred from the file extension.\n* **System screenshots** — Linux Wayland via `zwlr_screencopy_manager_v1`\n  (wlroots-based compositors: Sway, Hyprland, …), X11 via `XGetImage` with\n  an MIT-SHM fast path, and XDG Desktop Portal via `ashpd` (GNOME, KDE,\n  Flatpak, Snap).\n\n---\n\n## Quick start\n\n### Core crate\n\n```toml\n[dependencies]\nminiscreenshot = \"0.2\"\n```\n\n```rust\nuse miniscreenshot::Screenshot;\n\n// Build from raw RGBA8 pixel data\nlet data = vec![255u8, 0, 0, 255]; // 1×1 red pixel\nlet shot = Screenshot::from_rgba(1, 1, data);\n\n// Save — format inferred from extension (.png / .ppm / .pgm)\nshot.save(\"screenshot.png\").unwrap();\n\n// Or encode to bytes explicitly\nlet png_bytes: Vec\u003cu8\u003e = shot.encode_png().unwrap();\nlet ppm_bytes: Vec\u003cu8\u003e = shot.encode_ppm();   // lossless, trivial format\nlet pgm_bytes: Vec\u003cu8\u003e = shot.encode_pgm();   // grayscale\n```\n\n### Desktop umbrella (just take a screenshot)\n\n```toml\n[dependencies]\nminiscreenshot-desktop = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_desktop::take;\n\nlet shot = take().expect(\"screenshot\");\nshot.save(\"desktop.png\").unwrap();\n```\n\nThe `take()` function auto-selects the best backend: Wayland → X11 → Portal.\n\n### softbuffer backend\n\n```toml\n[dependencies]\nminiscreenshot-softbuffer = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_softbuffer::{softbuffer, capture};\n\n// softbuffer stores pixels as u32 XRGB8888 values\nlet pixels: \u0026[u32] = /* buffer.deref() from softbuffer */ \u0026[];\nlet shot = capture(pixels, width, height);\nshot.save(\"screenshot.png\").unwrap();\n```\n\n### softbuffer + winit pairing\n\nWhen you want to create a `softbuffer::Surface` from a `winit::Window`, enable\nthe `winit` feature. This re-exports `winit` alongside `softbuffer` at the same\nversion, avoiding dependency conflicts.\n\n```toml\n[dependencies]\nminiscreenshot-softbuffer = { version = \"0.2\", features = [\"winit\"] }\n```\n\n```rust\nuse miniscreenshot_softbuffer::winit::window::Window;\nuse miniscreenshot_softbuffer::softbuffer;\nuse std::rc::Rc;\n\n// Rc\u003cWindow\u003e implements the raw-handle traits softbuffer needs.\nlet window: Rc\u003cWindow\u003e = /* create window */;\nlet ctx = softbuffer::Context::new(window.clone()).unwrap();\nlet surface = softbuffer::Surface::new(\u0026ctx, window.clone()).unwrap();\n```\n\nSee the `softbuffer_winit_scene_screenshot` example for a complete demo.\n\n### wgpu backend\n\n```toml\n[dependencies]\nminiscreenshot-wgpu = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_wgpu::{wgpu, capture};\n\n// `texture` must have been created with TextureUsages::COPY_SRC\nlet shot = capture(\u0026device, \u0026queue, \u0026texture).unwrap();\nshot.save(\"screenshot.png\").unwrap();\n```\n\n### Wayland system screenshot\n\n```toml\n[dependencies]\nminiscreenshot-wayland = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_wayland::WaylandCapture;\n\nlet mut cap = WaylandCapture::connect().expect(\"connect to Wayland\");\nprintln!(\"{} output(s) found\", cap.output_count());\n\n// Capture first monitor\nlet shot = cap.capture_output(0).expect(\"capture\");\nshot.save(\"screenshot.png\").unwrap();\n\n// Or capture all monitors at once\nlet shots = cap.capture_all().expect(\"capture all\");\n```\n\n\u003e **Compositor requirements:** Requires a Wayland compositor that implements\n\u003e `zwlr_screencopy_manager_v1` (wlroots-based — Sway, Hyprland, weston, cage,\n\u003e labwc, …). GNOME-on-Wayland and KWin do **not** implement this protocol and\n\u003e will return `WaylandCaptureError::NoScreencopyManager`. Use\n\u003e `miniscreenshot-portal` instead on these compositors.\n\n### X11 system screenshot\n\n```toml\n[dependencies]\nminiscreenshot-x11 = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_x11::X11Capture;\n\nlet mut cap = X11Capture::connect().expect(\"connect to X11\");\nprintln!(\"{} screen(s) found\", cap.screen_count());\n\n// Capture first screen\nlet shot = cap.capture_screen(0).expect(\"capture\");\nshot.save(\"screenshot.png\").unwrap();\n\n// Or capture all screens at once\nlet shots = cap.capture_all().expect(\"capture all\");\n```\n\n\u003e **Server requirements:** Requires a reachable X11 server (`$DISPLAY` set).\n\u003e Uses MIT-SHM when available for a fast-path capture; otherwise falls back to\n\u003e a plain `XGetImage` transfer over the wire.\n\n### Screenshot portal (GNOME / KDE / Flatpak)\n\n```toml\n[dependencies]\nminiscreenshot-portal = \"0.2\"\n```\n\nBlocking usage (default):\n\n```rust\nuse miniscreenshot_portal::PortalCapture;\n\nlet mut cap = PortalCapture::connect().expect(\"connect to portal\");\nlet shot = cap.capture_interactive().expect(\"capture\");\nshot.save(\"screenshot.png\").unwrap();\n```\n\nAsync usage:\n\n```toml\n[dependencies]\nminiscreenshot-portal = { version = \"0.2\", default-features = false, features = [\"tokio\"] }\n```\n\n```rust\nuse miniscreenshot_portal::PortalCapture;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let mut cap = PortalCapture::connect_async().await;\n    let shot = cap.capture_interactive_async().await?;\n    shot.save(\"screenshot.png\")?;\n    Ok(())\n}\n```\n\n\u003e **Portal requirements:** Requires a running desktop session with\n\u003e `$XDG_RUNTIME_DIR` and a portal implementation (`xdg-desktop-portal` +\n\u003e a backend such as `xdg-desktop-portal-gnome`, `-kde`, `-wlr`, or `-gtk`).\n\u003e GNOME always shows a confirmation dialog; KDE and wlroots may or may not\n\u003e depending on backend policy. Works inside Flatpak and Snap sandboxes.\n\u003e Use this crate on GNOME or KWin instead of `miniscreenshot-wayland`.\n\n### minifb (prototyping window)\n\n```toml\n[dependencies]\nminiscreenshot-minifb = \"0.2\"\n```\n\n```rust\nuse miniscreenshot_minifb::capture;\n\n// minifb stores pixels as u32 in 0RGB8888 format\nlet pixels: \u0026[u32] = /* buffer passed to Window::update_with_buffer() */ \u0026[];\nlet shot = capture(pixels, width as u32, height as u32).unwrap();\nshot.save(\"screenshot.png\").unwrap();\n```\n\nFull window example:\n\n```rust\nuse miniscreenshot_minifb::minifb;\nuse miniscreenshot_minifb::capture;\n\nfn main() {\n    let (width, height) = (640, 480);\n    let mut buffer = vec![0u32; width * height];\n\n    // Fill buffer with content...\n    for y in 0..height {\n        for x in 0..width {\n            let idx = y * width + x;\n            buffer[idx] = ((x as u32) \u003c\u003c 16) | ((y as u32) \u003c\u003c 8) | ((x ^ y) as u32 \u0026 0xFF);\n        }\n    }\n\n    let mut window = minifb::Window::new(\n        \"Demo\",\n        width,\n        height,\n        minifb::WindowOptions::default(),\n    )\n    .expect(\"failed to create window\");\n\n    window.update_with_buffer(\u0026buffer, width, height).unwrap();\n\n    // Capture the displayed buffer as a Screenshot\n    let shot = capture(\u0026buffer, width as u32, height as u32).unwrap();\n    shot.save(\"screenshot.png\").unwrap();\n    println!(\"saved screenshot\");\n}\n```\n\n### Capture trait\n\nAll system-capture driver crates (`-wayland`, `-x11`, `-portal`) implement\nthe core `Capture` trait, making backends interchangeable:\n\n```rust\nuse miniscreenshot::Capture;\n\nfn take_and_save\u003cC: Capture\u003e(cap: \u0026mut C)\nwhere C::Error: std::fmt::Debug\n{\n    let shot = cap.capture().unwrap();\n    shot.save(\"output.png\").unwrap();\n}\n```\n\n#### Closures as Capture\n\nA blanket implementation allows any `FnMut() -\u003e Result\u003cScreenshot, E\u003e` to be\nused as a `Capture`. This means free functions like `miniscreenshot_wgpu::capture`\ncan be used directly:\n\n```rust\nuse miniscreenshot::Capture;\n\nfn take_and_save\u003cC: Capture\u003e(cap: \u0026mut C)\nwhere C::Error: std::fmt::Debug\n{\n    let shot = cap.capture().unwrap();\n    shot.save(\"output.png\").unwrap();\n}\n\n// Usage with a wgpu closure:\nlet mut cap = || miniscreenshot_wgpu::capture(\u0026device, \u0026queue, \u0026texture);\ntake_and_save(\u0026mut cap);\n```\n\n#### MultiCapture\n\nFor backends with multiple outputs (monitors), the `MultiCapture` super-trait\nprovides `source_count()`, `capture_index()`, and `capture_all()`:\n\n```rust\nuse miniscreenshot::{Capture, MultiCapture};\n\nfn capture_all_screens\u003cC: MultiCapture\u003e(cap: \u0026mut C)\nwhere C::Error: std::fmt::Debug\n{\n    println!(\"{} screen(s) found\", cap.source_count());\n    let shots = cap.capture_all().unwrap();\n    for (i, shot) in shots.iter().enumerate() {\n        shot.save(\u0026format!(\"screen_{i}.png\")).unwrap();\n    }\n}\n```\n\n---\n\n## Optional features\n\n```toml\n# Winit (for softbuffer + winit integration)\nminiscreenshot-softbuffer = { version = \"0.2\", features = [\"winit\"] }\n```\n\n### Portal features\n\n`miniscreenshot-portal` exposes runtime and API-surface features. Enabling\na runtime (`tokio` or `async-std`) automatically enables the async API surface.\n\n```toml\n# Default: tokio runtime + blocking API + async API\nminiscreenshot-portal = \"0.2\"\n\n# Async-only with tokio (no blocking convenience methods)\nminiscreenshot-portal = { version = \"0.2\", default-features = false, features = [\"tokio\"] }\n\n# Async-only with async-std\nminiscreenshot-portal = { version = \"0.2\", default-features = false, features = [\"async-std\"] }\n```\n\nThe `tokio` and `async-std` runtime features are mutually exclusive. The\n`blocking` API-surface feature is independent. The `async` API surface is\nimplied by whichever runtime you select, but can also be enabled standalone\nif you want to provide your own executor.\n\n---\n\n## Output formats\n\n| Format | Method | Notes |\n|--------|--------|-------|\n| PNG | `encode_png()` / `save(\"file.png\")` | Lossless, widely supported |\n| PPM | `encode_ppm()` / `save(\"file.ppm\")` | Binary P6, trivial to parse |\n| PGM | `encode_pgm()` / `save(\"file.pgm\")` | Binary P5 grayscale (BT.601 luma) |\n\n---\n\n## Examples\n\nEach crate ships with a self-contained `examples/\u003ccrate_short\u003e_scene_screenshot.rs` that\nrenders a scene (or synthesises a buffer) and saves a PNG.\n\n| Crate | Command | Headless? |\n|-------|---------|-----------|\n| `miniscreenshot` (core) | `cargo run -p miniscreenshot --example core_scene_screenshot` | Yes |\n| `miniscreenshot-softbuffer` | `cargo run -p miniscreenshot-softbuffer --example softbuffer_scene_screenshot` | Yes |\n| `miniscreenshot-softbuffer` (winit) | `cargo run -p miniscreenshot-softbuffer --example softbuffer_winit_scene_screenshot --features winit` | No (needs a display) |\n| `miniscreenshot-wgpu` | `cargo run -p miniscreenshot-wgpu --example wgpu_scene_screenshot` | Yes |\n| `miniscreenshot-wayland` | `cargo run -p miniscreenshot-wayland --example wayland_scene_screenshot` | No (needs wlroots-based Wayland compositor) |\n| `miniscreenshot-x11` | `cargo run -p miniscreenshot-x11 --example x11_scene_screenshot` | No (needs `$DISPLAY` / X11 server) |\n| `miniscreenshot-portal` | `cargo run -p miniscreenshot-portal --example portal_scene_screenshot` | No (needs desktop session with portal) |\n| `miniscreenshot-portal` (async) | `cargo run -p miniscreenshot-portal --example portal_async_scene_screenshot --features async` | No (needs desktop session with portal) |\n| `miniscreenshot-skia` | `cargo run -p miniscreenshot-skia --example skia_scene_screenshot` | Yes |\n| `miniscreenshot-vello` | `cargo run -p miniscreenshot-vello --example vello_scene_screenshot` | Yes |\n| `miniscreenshot-minifb` | `cargo run -p miniscreenshot-minifb --example minifb_scene_screenshot` | Yes |\n\nBuild all examples at once:\n\n```bash\ntask examples:build\n```\n\nBuild and run all headless examples:\n\n```bash\ntask examples\n```\n\n---\n\n## License\n\nLicensed under either of [Apache License 2.0](LICENSE-APACHE) or\n[MIT License](LICENSE-MIT) at your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fminiscreenshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsunsided%2Fminiscreenshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsunsided%2Fminiscreenshot/lists"}