polyscope_render/
screenshot.rs1use image::{ImageBuffer, Rgba};
4use std::path::Path;
5
6#[derive(Debug, Clone, Default)]
8pub struct ScreenshotOptions {
9 pub transparent_background: bool,
11}
12
13pub fn save_image(
24 filename: &str,
25 data: &[u8],
26 width: u32,
27 height: u32,
28) -> Result<(), ScreenshotError> {
29 let path = Path::new(filename);
30 let extension = path
31 .extension()
32 .and_then(|e| e.to_str())
33 .map(str::to_lowercase)
34 .unwrap_or_default();
35
36 let mut rgba_data = data.to_vec();
38 for chunk in rgba_data.chunks_exact_mut(4) {
39 chunk.swap(0, 2); }
41
42 let img: ImageBuffer<Rgba<u8>, Vec<u8>> =
45 ImageBuffer::from_raw(width, height, rgba_data).ok_or(ScreenshotError::InvalidImageData)?;
46
47 match extension.as_str() {
48 "png" => {
49 img.save_with_format(path, image::ImageFormat::Png)?;
50 }
51 "jpg" | "jpeg" => {
52 let rgb_img = image::DynamicImage::ImageRgba8(img).to_rgb8();
54 rgb_img.save_with_format(path, image::ImageFormat::Jpeg)?;
55 }
56 _ => {
57 return Err(ScreenshotError::UnsupportedFormat(extension));
58 }
59 }
60
61 Ok(())
62}
63
64pub fn save_to_buffer(data: &[u8], width: u32, height: u32) -> Result<Vec<u8>, ScreenshotError> {
74 let mut rgba_data = data.to_vec();
76 for chunk in rgba_data.chunks_exact_mut(4) {
77 chunk.swap(0, 2); }
79
80 let img: ImageBuffer<Rgba<u8>, Vec<u8>> =
82 ImageBuffer::from_raw(width, height, rgba_data).ok_or(ScreenshotError::InvalidImageData)?;
83
84 let mut buffer = std::io::Cursor::new(Vec::new());
85 img.write_to(&mut buffer, image::ImageFormat::Png)?;
86
87 Ok(buffer.into_inner())
88}
89
90#[derive(Debug, thiserror::Error)]
92pub enum ScreenshotError {
93 #[error("Failed to save image: {0}")]
94 IoError(#[from] std::io::Error),
95
96 #[error("Image encoding error: {0}")]
97 ImageError(#[from] image::ImageError),
98
99 #[error("Unsupported image format: {0}")]
100 UnsupportedFormat(String),
101
102 #[error("Invalid image data")]
103 InvalidImageData,
104
105 #[error("GPU buffer mapping failed")]
106 BufferMapFailed,
107}