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 {}
27unsafe impl Sync for CGColorSpace {}
28
29impl Drop for CGColorSpace {
30 fn drop(&mut self) {
31 if !self.ptr.is_null() {
32 unsafe { cg_ffi::CGColorSpaceRelease(self.ptr) };
33 self.ptr = ptr::null_mut();
34 }
35 }
36}
37
38impl Clone for CGColorSpace {
39 fn clone(&self) -> Self {
40 let p = unsafe { cg_ffi::CGColorSpaceRetain(self.ptr) };
41 Self { ptr: p }
42 }
43}
44
45impl std::fmt::Debug for CGColorSpace {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 f.debug_struct("CGColorSpace")
48 .field("ptr", &self.ptr)
49 .finish()
50 }
51}
52
53impl CGColorSpace {
54 #[must_use]
61 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
62 Self { ptr }
63 }
64
65 #[must_use]
67 pub fn device_rgb() -> Self {
68 Self {
69 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceRGB() },
70 }
71 }
72
73 #[must_use]
75 pub fn device_gray() -> Self {
76 Self {
77 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceGray() },
78 }
79 }
80
81 #[must_use]
83 pub fn srgb() -> Self {
84 unsafe {
85 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceSRGB\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 display_p3() -> Self {
95 unsafe {
96 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceDisplayP3\0".as_ptr());
97 let p = cg_ffi::CGColorSpaceCreateWithName(n);
98 CFReleaseLite(n);
99 Self { ptr: p }
100 }
101 }
102
103 #[must_use]
105 pub fn number_of_components(&self) -> usize {
106 unsafe { cg_ffi::CGColorSpaceGetNumberOfComponents(self.ptr) }
107 }
108
109 #[must_use]
111 pub const fn as_ptr(&self) -> *mut c_void {
112 self.ptr
113 }
114}
115
116pub struct CGImage {
118 ptr: *mut c_void,
119}
120
121unsafe impl Send for CGImage {}
125unsafe impl Sync for CGImage {}
126
127impl Drop for CGImage {
128 fn drop(&mut self) {
129 if !self.ptr.is_null() {
130 unsafe { cg_ffi::CGImageRelease(self.ptr) };
131 self.ptr = ptr::null_mut();
132 }
133 }
134}
135
136impl Clone for CGImage {
137 fn clone(&self) -> Self {
138 let p = unsafe { cg_ffi::CGImageRetain(self.ptr) };
139 Self { ptr: p }
140 }
141}
142
143impl std::fmt::Debug for CGImage {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.debug_struct("CGImage").field("ptr", &self.ptr).finish()
146 }
147}
148
149impl CGImage {
150 #[must_use]
157 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
158 Self { ptr }
159 }
160
161 #[must_use]
163 pub fn width(&self) -> usize {
164 unsafe { cg_ffi::CGImageGetWidth(self.ptr) }
165 }
166
167 #[must_use]
169 pub fn height(&self) -> usize {
170 unsafe { cg_ffi::CGImageGetHeight(self.ptr) }
171 }
172
173 #[must_use]
175 pub fn bits_per_component(&self) -> usize {
176 unsafe { cg_ffi::CGImageGetBitsPerComponent(self.ptr) }
177 }
178
179 #[must_use]
181 pub fn bits_per_pixel(&self) -> usize {
182 unsafe { cg_ffi::CGImageGetBitsPerPixel(self.ptr) }
183 }
184
185 #[must_use]
187 pub fn bytes_per_row(&self) -> usize {
188 unsafe { cg_ffi::CGImageGetBytesPerRow(self.ptr) }
189 }
190
191 pub fn save_png<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
198 let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| {
199 io::Error::new(
200 io::ErrorKind::InvalidInput,
201 "path contains an interior NUL byte",
202 )
203 })?;
204
205 if unsafe { bridge_ffi::cgimage_save_png(self.ptr, c_path.as_ptr()) } {
206 Ok(())
207 } else {
208 Err(io::Error::new(
209 io::ErrorKind::Other,
210 "cgimage_save_png returned false",
211 ))
212 }
213 }
214
215 #[must_use]
217 pub const fn as_ptr(&self) -> *mut c_void {
218 self.ptr
219 }
220}
221
222extern "C" {
223 fn CFStringCreateWithCString(
224 allocator: *const c_void,
225 bytes: *const u8,
226 encoding: u32,
227 ) -> *mut c_void;
228 fn CFRelease(cf: *const c_void);
229}
230
231#[allow(non_snake_case)]
232unsafe fn CFStringCreateWithCStringLite(bytes: *const u8) -> *const c_void {
233 CFStringCreateWithCString(ptr::null(), bytes, 0x0800_0100).cast_const()
234}
235
236#[allow(non_snake_case)]
237unsafe fn CFReleaseLite(p: *const c_void) {
238 CFRelease(p);
239}