@@ -12,6 +12,71 @@ use std::ffi::c_void;
1212#[ cfg( feature = "macos_15_2" ) ]
1313use crate :: cg:: CGRect ;
1414
15+ /// Image output format for saving screenshots
16+ ///
17+ /// # Examples
18+ ///
19+ /// ```no_run
20+ /// use screencapturekit::screenshot_manager::ImageFormat;
21+ ///
22+ /// // PNG for lossless quality
23+ /// let format = ImageFormat::Png;
24+ ///
25+ /// // JPEG with 80% quality
26+ /// let format = ImageFormat::Jpeg(0.8);
27+ ///
28+ /// // HEIC with 90% quality (smaller file size than JPEG)
29+ /// let format = ImageFormat::Heic(0.9);
30+ /// ```
31+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
32+ pub enum ImageFormat {
33+ /// PNG format (lossless)
34+ Png ,
35+ /// JPEG format with quality (0.0-1.0)
36+ Jpeg ( f32 ) ,
37+ /// TIFF format (lossless)
38+ Tiff ,
39+ /// GIF format
40+ Gif ,
41+ /// BMP format
42+ Bmp ,
43+ /// HEIC format with quality (0.0-1.0) - efficient compression
44+ Heic ( f32 ) ,
45+ }
46+
47+ impl ImageFormat {
48+ fn to_format_id ( self ) -> i32 {
49+ match self {
50+ Self :: Png => 0 ,
51+ Self :: Jpeg ( _) => 1 ,
52+ Self :: Tiff => 2 ,
53+ Self :: Gif => 3 ,
54+ Self :: Bmp => 4 ,
55+ Self :: Heic ( _) => 5 ,
56+ }
57+ }
58+
59+ fn quality ( self ) -> f32 {
60+ match self {
61+ Self :: Jpeg ( q) | Self :: Heic ( q) => q. clamp ( 0.0 , 1.0 ) ,
62+ _ => 1.0 ,
63+ }
64+ }
65+
66+ /// Get the typical file extension for this format
67+ #[ must_use]
68+ pub const fn extension ( & self ) -> & ' static str {
69+ match self {
70+ Self :: Png => "png" ,
71+ Self :: Jpeg ( _) => "jpg" ,
72+ Self :: Tiff => "tiff" ,
73+ Self :: Gif => "gif" ,
74+ Self :: Bmp => "bmp" ,
75+ Self :: Heic ( _) => "heic" ,
76+ }
77+ }
78+ }
79+
1580extern "C" fn image_callback (
1681 image_ptr : * const c_void ,
1782 error_ptr : * const i8 ,
@@ -199,15 +264,62 @@ impl CGImage {
199264 /// # }
200265 /// ```
201266 pub fn save_png ( & self , path : & str ) -> Result < ( ) , SCError > {
267+ self . save ( path, ImageFormat :: Png )
268+ }
269+
270+ /// Save the image to a file in the specified format
271+ ///
272+ /// # Arguments
273+ /// * `path` - The file path to save the image to
274+ /// * `format` - The output format (PNG, JPEG, TIFF, GIF, BMP, or HEIC)
275+ ///
276+ /// # Errors
277+ /// Returns an error if the image cannot be saved
278+ ///
279+ /// # Examples
280+ ///
281+ /// ```no_run
282+ /// # use screencapturekit::screenshot_manager::{SCScreenshotManager, ImageFormat};
283+ /// # use screencapturekit::stream::{content_filter::SCContentFilter, configuration::SCStreamConfiguration};
284+ /// # use screencapturekit::shareable_content::SCShareableContent;
285+ /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
286+ /// # let content = SCShareableContent::get()?;
287+ /// # let display = &content.displays()[0];
288+ /// # let filter = SCContentFilter::builder().display(display).exclude_windows(&[]).build();
289+ /// # let config = SCStreamConfiguration::new().with_width(1920).with_height(1080);
290+ /// let image = SCScreenshotManager::capture_image(&filter, &config)?;
291+ ///
292+ /// // Save as PNG (lossless)
293+ /// image.save("/tmp/screenshot.png", ImageFormat::Png)?;
294+ ///
295+ /// // Save as JPEG with 85% quality
296+ /// image.save("/tmp/screenshot.jpg", ImageFormat::Jpeg(0.85))?;
297+ ///
298+ /// // Save as HEIC with 90% quality (smaller file size)
299+ /// image.save("/tmp/screenshot.heic", ImageFormat::Heic(0.9))?;
300+ /// # Ok(())
301+ /// # }
302+ /// ```
303+ pub fn save ( & self , path : & str , format : ImageFormat ) -> Result < ( ) , SCError > {
202304 let c_path = std:: ffi:: CString :: new ( path)
203305 . map_err ( |_| SCError :: internal_error ( "Path contains null bytes" ) ) ?;
204306
205- let success = unsafe { crate :: ffi:: cgimage_save_png ( self . ptr , c_path. as_ptr ( ) ) } ;
307+ let success = unsafe {
308+ crate :: ffi:: cgimage_save_to_file (
309+ self . ptr ,
310+ c_path. as_ptr ( ) ,
311+ format. to_format_id ( ) ,
312+ format. quality ( ) ,
313+ )
314+ } ;
206315
207316 if success {
208317 Ok ( ( ) )
209318 } else {
210- Err ( SCError :: internal_error ( "Failed to save image as PNG" ) )
319+ Err ( SCError :: internal_error ( format ! (
320+ "Failed to save image as {}" ,
321+ format. extension( ) . to_uppercase( )
322+ ) ) )
211323 }
212324 }
213325}
0 commit comments