# wgc_python **Repository Path**: vencons/wgc_python ## Basic Information - **Project Name**: wgc_python - **Description**: ๐Ÿš€ ไธ“ไธบ Python ่‡ชๅŠจๅŒ–ๆ‰“้€ ็š„้ซ˜ๆ€ง่ƒฝๆˆชๅ›พๅบ“ | 180+ FPS | ๆ”ฏๆŒๅŽๅฐ/้ฎๆŒก | ๅฏๆš‚ๅœ ้›ถๅŠŸ่€—ๅพ…ๆœบ;๐Ÿš€ High-performance capture library for Python automation | 180+ FPS | Background/Occluded Support | Pausable (Pause/Resume) Zero-Power Standby - **Primary Language**: C++ - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-08-19 - **Last Updated**: 2026-08-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # wgc_python English | [็ฎ€ไฝ“ไธญๆ–‡](README.md) > **๐Ÿš€ Window Capture Library Built for Python Automation** > 180+ FPS Performance ยท Zero-Resource Standby ยท Capture Behind Windows ยท Minimalist API --- ## Why wgc_python? ### ๐ŸŽฏ Designed for Automation Scenarios Are you struggling with these problems? - **mss/BitBlt**: Cannot capture occluded or background windows - **PrintWindow**: Performance bottleneck, fixed 26ms+ latency - **Other WGC wrappers**: Continuous resource consumption, huge overhead for frequent start/stop (50ms+) **wgc_python solves this dilemma with its innovative Pause/Resume mechanism:** ```python # Traditional approach: Either waste resources or suffer latency start_capture() # 50ms overhead get_frame() # Get screenshot stop_capture() # Destroy session (50ms) # wgc_python approach: One-time init, on-demand capture, zero-overhead standby with WindowCapture("Window", "Class") as cap: while running: frame = cap.capture_one() # auto Resume โ†’ wait โ†’ copy โ†’ Pause # Process image... ``` ### ๐Ÿ“Š Performance Comparison | Solution | FPS | Background Capture | CPU Usage | Toggle Overhead | GPU When Paused | |----------|-----|-------------------|-----------|----------------|-----------------| | python-mss / BitBlt | ~60 | โŒ | High | Low | N/A (no pause) | | PrintWindow | ~38 | โœ… | Medium | Low | N/A (per-call) | | Other WGC wrappers | 180+ | โœ… | High (continuous) | Very High (50ms+) | High (can't truly pause) | | **wgc_python** | **180+** | โœ… | **Near Zero (when paused)** | **<1ฮผs (atomic flag)** | **Zero (no D3D ops)** | ### โœจ Core Advantages #### 1. Extreme Performance - **180+ FPS** high frame rate capture, 5x faster than PrintWindow - **Double-buffered Staging Texture**: GPU async copy, read/write non-blocking - **Zero-copy path**: `np.ndarray(strides=...)` directly from GPU-mapped memory #### 2. Smart Resource Management - **Pause/Resume <1ฮผs soft-pause**: Atomic flag only, no WGC session teardown - **capture_one() auto management**: Resume โ†’ wait โ†’ copy โ†’ Pause, zero GPU driver overhead between captures - **Session Reuse**: No frequent D3D device creation/destruction #### 3. Minimalist API - **capture_one()**: One-line on-demand capture, returns numpy array - **get_frame()**: Zero-copy raw pointer path (advanced) - **Thread safe**: C++ handles all multi-threading complexity #### 4. Multi-Instance Capture - Create multiple capture sessions simultaneously within one process - Each session has its own D3D11 device, staging textures, and WinRT session โ€” fully isolated - Supports concurrent capture of the same window #### 5. Client Area Precision (No Title Bar by Default) - **Default `client_area_only=True`**: captures only window client area, automatically crops title bar and borders - **Set `client_area_only=False`**: captures entire window including title bar and borders, for UI recording - DPI-aware: automatic high-DPI scaling correction for pixel-perfect cropping - GPU-level cropping via `CopySubresourceRegion`, no wasted bandwidth or CPU #### 6. Capture Behind Windows - Supports capturing occluded, minimized, and background windows - Perfect for games, desktop apps, and various scenarios --- ## Quick Start ### Installation ```bash pip install wgc-python ``` ### Basic Usage ```python from wgc_python import WindowCapture, enumerate_windows # Enumerate all windows for title, class_name in enumerate_windows(): print(f"{title} ({class_name})") # On-demand capture (recommended โ€” zero-resource standby) with WindowCapture("Window Title", "WindowClass") as cap: frame = cap.capture_one() # BGRA numpy array, shape (h, w, 4) if frame is not None: print(f"Captured: {frame.shape}") # Client area demo # Default client_area_only=True: content only, no title bar/borders cap_client = WindowCapture("Notepad", "Notepad") # content only cap_full = WindowCapture("Notepad", "Notepad", client_area_only=False) # with title bar frame_client = cap_client.capture_one() # edit area only frame_full = cap_full.capture_one() # title bar + menu + edit area cap_client.close() cap_full.close() ``` ### Best Practice for Automation ```python from wgc_python import WindowCapture cap = WindowCapture("Game Window", "UnityWndClass") while True: frame = cap.capture_one(timeout=1.0) if frame is not None: # frame is BGRA numpy array, ready for OpenCV/template matching pass time.sleep(1) cap.close() ``` ### Zero-Copy Advanced Usage ```python from wgc_python import WindowCapture import numpy as np import ctypes with WindowCapture("Window", "Class") as cap: cap.resume() r = cap.get_frame() # (ptr, w, h, row_pitch) โ€” GPU mapped pointer if r: ptr, w, h, rp = r arr = np.ndarray((h, w, 4), dtype=np.uint8, buffer=(ctypes.c_ubyte * (h * rp)).from_address(ptr), strides=(rp, 4, 1)) # arr is a zero-copy view into GPU-mapped memory cap.release_frame() cap.pause() ``` ### Real-time Display ```python from wgc_python import WindowCapture import cv2 with WindowCapture("Window Title", "WindowClass") as cap: while True: frame = cap.capture_one() if frame is not None: cv2.imshow("Capture", cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)) if cv2.waitKey(1) & 0xFF == ord('q'): break cv2.destroyAllWindows() ``` --- ## API Reference ```python from wgc_python import ( WindowCapture, # Window capture class (context manager support) enumerate_windows, # Enumerate all visible windows get_last_error, # Get last error message (thread-safe) get_active_capture_count, # Get active capture count ) # WindowCapture methods: # cap = WindowCapture(title, class_name, client_area_only=True) # # cap.capture_one(timeout=0.5) -> np.ndarray | None โ˜… recommended # Auto Resume โ†’ wait for frame โ†’ copy to numpy โ†’ Pause # WGC fully dormant between captures, zero GPU driver overhead # # cap.get_frame() -> (ptr, w, h, row_pitch) | None # cap.release_frame() # Release GPU mapping # cap.pause() # Pause capture (zero-resource standby) # cap.resume() # Resume capture # cap.stop() # Stop frame arrival # cap.close() # Destroy session # cap.is_capturing() -> bool # cap.is_paused() -> bool # cap.get_frame_count() -> int # cap.handle -> int (DLL handle) ``` --- ## Technical Architecture ``` WGC Capture โ†’ GPU Surface Texture โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ FrameArrived โ”‚ โ”‚ if pausing โ†’ โ†‘ โ”‚ โ† Paused: return directly, zero D3D ops โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ CopyResource (GPU async copy) โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Double-buffered Staging โ”‚ โ”‚ [0] Write โ†โ†’ [1] Read โ”‚ โ”‚ m_textureInUse anti-collide โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ Map (permanently mapped GPU memory) โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€ Zero-Copy Output โ”€โ”€โ”€โ”€โ” โ”‚ get_frame() โ”‚ โ”‚ raw ptr โ†’ numpy zero-copy โ”‚ โ”‚ requires release_frame() โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€ One-Click Capture โ”€โ”€โ”€โ” โ”‚ capture_one() โ”‚ โ”‚ auto Pause/Resume โ”‚ โ”‚ returns numpy array โ”‚ โ”‚ zero GPU overhead when idle โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### How Pause/Resume Works ``` User calls cap.pause() โ”‚ m_isPaused = true โ—„โ”€โ”€โ”€โ”€ atomic flag, <1ฮผs m_readableStagingIndex = -1 โ”‚ โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ FrameArrived Callback (WGC still fires)โ”‚ โ”‚ โ”‚ โ”‚ lock(mutex); โ”‚ โ”‚ if (m_isPaused) return; // โ† pure CPU, skipโ”‚ โ”‚ // โ†“ below runs only after resume โ†“ โ”‚ โ”‚ CopyResource(staging, frame); โ”‚ โ”‚ m_readableStagingIndex = idx; โ”‚ โ”‚ unlock(mutex); โ”‚ โ””โ”€โ”€โ”€โ”€โ–ฒโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ User calls cap.resume() MapFrame checks readableStagingIndex m_isPaused = false <0 โ†’ no frame ready โ†’ returns false No WGC session destroy / no D3D device recreate / no callback re-register โ†’ zero-latency resume, no spikes ``` --- ## File Structure ``` wgc_python/ โ”œโ”€โ”€ wgc_python/ # Python package โ”‚ โ”œโ”€โ”€ __init__.py # Python API (ctypes FFI) โ”‚ โ””โ”€โ”€ wgc_python.dll # Compiled DLL โ”œโ”€โ”€ wgc_python_dll/ # C++ DLL Project โ”‚ โ”œโ”€โ”€ WGCWindowCapture.h/cpp # Capture core (double-buffered + zero-copy) โ”‚ โ”œโ”€โ”€ WGCExport.h/cpp # DLL exports (thread-safe error handling) โ”‚ โ”œโ”€โ”€ D3DInterop.cpp # D3D11 device interop โ”‚ โ”œโ”€โ”€ WindowEnumerator.h/cpp # Window enumeration โ”‚ โ”œโ”€โ”€ pch.h # Precompiled header โ”‚ โ””โ”€โ”€ packages/ # NuGet packages โ”œโ”€โ”€ test.py # Functional tests โ”œโ”€โ”€ test_mt.py # Multi-threaded on-demand capture example โ”œโ”€โ”€ pyproject.toml # pip build config โ”œโ”€โ”€ BUILD.md / BUILD_EN.md # Build instructions (CN/EN) โ”œโ”€โ”€ README.md / README_EN.md # Usage docs (CN/EN) โ”œโ”€โ”€ CONTRIBUTING.md # Contributing guide โ”œโ”€โ”€ CODE_OF_CONDUCT.md # Code of conduct โ”œโ”€โ”€ LICENSE # MIT License โ””โ”€โ”€ requirements.txt # Python dependencies ``` --- ## Build DLL See [BUILD.md](BUILD.md) --- ## Troubleshooting | Issue | Solution | |-------|----------| | DLL not found | Ensure `wgc_python.dll` is in the correct location | | Capture failed | Check if window is visible, Windows version >= 1903 | | Non-ASCII path save failed | Use `cv2.imencode` + `open().write()` instead of `cv2.imwrite` | | Missing dependencies | `pip install numpy opencv-python` | --- ## Use Cases - โœ… Game AI / Automation Scripts - โœ… RPA Process Automation - โœ… Screen Recording / Streaming - โœ… UI Automation Testing - โœ… Computer Vision Applications --- ## Acknowledgments This project is based on [robmikh/Win32CaptureSample](https://github.com/robmikh/Win32CaptureSample). --- ## License MIT License