Skip to main content
Glama
macos.rs4.63 kB
use super::{Screenshot, ScreenshotError}; use tauri::{Runtime, WebviewWindow}; /// macOS-specific screenshot implementation using WKWebView's takeSnapshot /// /// This implementation captures only the visible viewport, not the full document. /// It uses the native WKWebView takeSnapshot API to get a high-quality screenshot. pub fn capture_viewport<R: Runtime>( window: &WebviewWindow<R>, ) -> Result<Screenshot, ScreenshotError> { #[cfg(target_os = "macos")] { use block2::RcBlock; use objc2_app_kit::NSImage; use objc2_foundation::NSError; use objc2_web_kit::{WKSnapshotConfiguration, WKWebView}; use std::sync::mpsc; use std::sync::{Arc, Mutex}; let (tx, rx) = mpsc::channel::<Result<Screenshot, ScreenshotError>>(); let tx = Arc::new(Mutex::new(Some(tx))); // Use Tauri's with_webview to access the platform-specific webview window .with_webview(move |webview| { unsafe { // Get the WKWebView from Tauri's webview handle let wkwebview: &WKWebView = &*(webview.inner() as *const _ as *const WKWebView); // Create snapshot configuration (nil means capture visible viewport) let config = WKSnapshotConfiguration::new(); // Create completion handler block let tx_clone = tx.clone(); let handler = RcBlock::new(move |image: *mut NSImage, error: *mut NSError| { if let Some(tx) = tx_clone.lock().unwrap().take() { if !error.is_null() { let err = &*error; let desc = err.localizedDescription(); let error_string = desc.to_string(); let _ = tx.send(Err(ScreenshotError::CaptureFailed(error_string))); } else if !image.is_null() { let img = &*image; // Convert NSImage to PNG data match convert_nsimage_to_png(img) { Ok(data) => { let _ = tx.send(Ok(Screenshot { data })); } Err(e) => { let _ = tx.send(Err(e)); } } } else { let _ = tx.send(Err(ScreenshotError::CaptureFailed( "No image returned from snapshot".to_string(), ))); } } }); // Take snapshot wkwebview .takeSnapshotWithConfiguration_completionHandler(Some(&config), &handler); } }) .map_err(|e| { ScreenshotError::CaptureFailed(format!("Failed to access webview: {e}")) })?; // Wait for result match rx.recv_timeout(std::time::Duration::from_secs(10)) { Ok(result) => result, Err(_) => Err(ScreenshotError::Timeout), } } #[cfg(not(target_os = "macos"))] { Err(ScreenshotError::PlatformUnsupported) } } #[cfg(target_os = "macos")] unsafe fn convert_nsimage_to_png( image: &objc2_app_kit::NSImage, ) -> Result<Vec<u8>, ScreenshotError> { use objc2_app_kit::{NSBitmapImageFileType, NSBitmapImageRep}; use objc2_foundation::NSDictionary; // Get TIFF representation let tiff_data = image.TIFFRepresentation().ok_or_else(|| { ScreenshotError::EncodeFailed("Failed to get TIFF representation".to_string()) })?; // Create bitmap representation from TIFF data let bitmap = NSBitmapImageRep::imageRepWithData(&tiff_data).ok_or_else(|| { ScreenshotError::EncodeFailed("Failed to create bitmap representation".to_string()) })?; // Convert to PNG let properties = NSDictionary::new(); let png_data = bitmap .representationUsingType_properties(NSBitmapImageFileType::PNG, &properties) .ok_or_else(|| ScreenshotError::EncodeFailed("Failed to create PNG data".to_string()))?; // Convert NSData to Vec<u8> let length = png_data.len(); let bytes = png_data.bytes(); let data = std::slice::from_raw_parts(bytes.as_ptr(), length).to_vec(); Ok(data) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hypothesi/mcp-server-tauri'

If you have feedback or need assistance with the MCP directory API, please join our Discord server