1use core::ffi::c_void;
8use core::ptr;
9use std::ffi::CString;
10use std::io;
11use std::os::unix::ffi::OsStrExt;
12use std::path::Path;
13
14use crate::ffi as bridge_ffi;
15
16use super::ffi as cg_ffi;
17
18pub struct CGColorSpace {
20 ptr: *mut c_void,
21}
22
23unsafe impl Send for CGColorSpace {}
24unsafe impl Sync for CGColorSpace {}
25
26impl Drop for CGColorSpace {
27 fn drop(&mut self) {
28 if !self.ptr.is_null() {
29 unsafe { cg_ffi::CGColorSpaceRelease(self.ptr) };
30 self.ptr = ptr::null_mut();
31 }
32 }
33}
34
35impl Clone for CGColorSpace {
36 fn clone(&self) -> Self {
37 let p = unsafe { cg_ffi::CGColorSpaceRetain(self.ptr) };
38 Self { ptr: p }
39 }
40}
41
42impl CGColorSpace {
43 #[must_use]
50 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
51 Self { ptr }
52 }
53
54 #[must_use]
56 pub fn device_rgb() -> Self {
57 Self {
58 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceRGB() },
59 }
60 }
61
62 #[must_use]
64 pub fn device_gray() -> Self {
65 Self {
66 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceGray() },
67 }
68 }
69
70 #[must_use]
72 pub fn srgb() -> Self {
73 unsafe {
74 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceSRGB\0".as_ptr());
75 let p = cg_ffi::CGColorSpaceCreateWithName(n);
76 CFReleaseLite(n);
77 Self { ptr: p }
78 }
79 }
80
81 #[must_use]
83 pub fn display_p3() -> Self {
84 unsafe {
85 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceDisplayP3\0".as_ptr());
86 let p = cg_ffi::CGColorSpaceCreateWithName(n);
87 CFReleaseLite(n);
88 Self { ptr: p }
89 }
90 }
91
92 #[must_use]
94 pub fn number_of_components(&self) -> usize {
95 unsafe { cg_ffi::CGColorSpaceGetNumberOfComponents(self.ptr) }
96 }
97
98 #[must_use]
100 pub const fn as_ptr(&self) -> *mut c_void {
101 self.ptr
102 }
103}
104
105pub struct CGImage {
107 ptr: *mut c_void,
108}
109
110unsafe impl Send for CGImage {}
111unsafe impl Sync for CGImage {}
112
113impl Drop for CGImage {
114 fn drop(&mut self) {
115 if !self.ptr.is_null() {
116 unsafe { cg_ffi::CGImageRelease(self.ptr) };
117 self.ptr = ptr::null_mut();
118 }
119 }
120}
121
122impl Clone for CGImage {
123 fn clone(&self) -> Self {
124 let p = unsafe { cg_ffi::CGImageRetain(self.ptr) };
125 Self { ptr: p }
126 }
127}
128
129impl CGImage {
130 #[must_use]
137 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
138 Self { ptr }
139 }
140
141 #[must_use]
143 pub fn width(&self) -> usize {
144 unsafe { cg_ffi::CGImageGetWidth(self.ptr) }
145 }
146
147 #[must_use]
149 pub fn height(&self) -> usize {
150 unsafe { cg_ffi::CGImageGetHeight(self.ptr) }
151 }
152
153 #[must_use]
155 pub fn bits_per_component(&self) -> usize {
156 unsafe { cg_ffi::CGImageGetBitsPerComponent(self.ptr) }
157 }
158
159 #[must_use]
161 pub fn bits_per_pixel(&self) -> usize {
162 unsafe { cg_ffi::CGImageGetBitsPerPixel(self.ptr) }
163 }
164
165 #[must_use]
167 pub fn bytes_per_row(&self) -> usize {
168 unsafe { cg_ffi::CGImageGetBytesPerRow(self.ptr) }
169 }
170
171 pub fn save_png<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
178 let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| {
179 io::Error::new(
180 io::ErrorKind::InvalidInput,
181 "path contains an interior NUL byte",
182 )
183 })?;
184
185 if unsafe { bridge_ffi::cgimage_save_png(self.ptr, c_path.as_ptr()) } {
186 Ok(())
187 } else {
188 Err(io::Error::new(
189 io::ErrorKind::Other,
190 "cgimage_save_png returned false",
191 ))
192 }
193 }
194
195 #[must_use]
197 pub const fn as_ptr(&self) -> *mut c_void {
198 self.ptr
199 }
200}
201
202extern "C" {
203 fn CFStringCreateWithCString(
204 allocator: *const c_void,
205 bytes: *const u8,
206 encoding: u32,
207 ) -> *mut c_void;
208 fn CFRelease(cf: *const c_void);
209}
210
211#[allow(non_snake_case)]
212unsafe fn CFStringCreateWithCStringLite(bytes: *const u8) -> *const c_void {
213 CFStringCreateWithCString(ptr::null(), bytes, 0x0800_0100).cast_const()
214}
215
216#[allow(non_snake_case)]
217unsafe fn CFReleaseLite(p: *const c_void) {
218 CFRelease(p);
219}