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 CGColorSpace {
46 #[must_use]
53 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
54 Self { ptr }
55 }
56
57 #[must_use]
59 pub fn device_rgb() -> Self {
60 Self {
61 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceRGB() },
62 }
63 }
64
65 #[must_use]
67 pub fn device_gray() -> Self {
68 Self {
69 ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceGray() },
70 }
71 }
72
73 #[must_use]
75 pub fn srgb() -> Self {
76 unsafe {
77 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceSRGB\0".as_ptr());
78 let p = cg_ffi::CGColorSpaceCreateWithName(n);
79 CFReleaseLite(n);
80 Self { ptr: p }
81 }
82 }
83
84 #[must_use]
86 pub fn display_p3() -> Self {
87 unsafe {
88 let n = CFStringCreateWithCStringLite(b"kCGColorSpaceDisplayP3\0".as_ptr());
89 let p = cg_ffi::CGColorSpaceCreateWithName(n);
90 CFReleaseLite(n);
91 Self { ptr: p }
92 }
93 }
94
95 #[must_use]
97 pub fn number_of_components(&self) -> usize {
98 unsafe { cg_ffi::CGColorSpaceGetNumberOfComponents(self.ptr) }
99 }
100
101 #[must_use]
103 pub const fn as_ptr(&self) -> *mut c_void {
104 self.ptr
105 }
106}
107
108pub struct CGImage {
110 ptr: *mut c_void,
111}
112
113unsafe impl Send for CGImage {}
117unsafe impl Sync for CGImage {}
118
119impl Drop for CGImage {
120 fn drop(&mut self) {
121 if !self.ptr.is_null() {
122 unsafe { cg_ffi::CGImageRelease(self.ptr) };
123 self.ptr = ptr::null_mut();
124 }
125 }
126}
127
128impl Clone for CGImage {
129 fn clone(&self) -> Self {
130 let p = unsafe { cg_ffi::CGImageRetain(self.ptr) };
131 Self { ptr: p }
132 }
133}
134
135impl CGImage {
136 #[must_use]
143 pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
144 Self { ptr }
145 }
146
147 #[must_use]
149 pub fn width(&self) -> usize {
150 unsafe { cg_ffi::CGImageGetWidth(self.ptr) }
151 }
152
153 #[must_use]
155 pub fn height(&self) -> usize {
156 unsafe { cg_ffi::CGImageGetHeight(self.ptr) }
157 }
158
159 #[must_use]
161 pub fn bits_per_component(&self) -> usize {
162 unsafe { cg_ffi::CGImageGetBitsPerComponent(self.ptr) }
163 }
164
165 #[must_use]
167 pub fn bits_per_pixel(&self) -> usize {
168 unsafe { cg_ffi::CGImageGetBitsPerPixel(self.ptr) }
169 }
170
171 #[must_use]
173 pub fn bytes_per_row(&self) -> usize {
174 unsafe { cg_ffi::CGImageGetBytesPerRow(self.ptr) }
175 }
176
177 pub fn save_png<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
184 let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| {
185 io::Error::new(
186 io::ErrorKind::InvalidInput,
187 "path contains an interior NUL byte",
188 )
189 })?;
190
191 if unsafe { bridge_ffi::cgimage_save_png(self.ptr, c_path.as_ptr()) } {
192 Ok(())
193 } else {
194 Err(io::Error::new(
195 io::ErrorKind::Other,
196 "cgimage_save_png returned false",
197 ))
198 }
199 }
200
201 #[must_use]
203 pub const fn as_ptr(&self) -> *mut c_void {
204 self.ptr
205 }
206}
207
208extern "C" {
209 fn CFStringCreateWithCString(
210 allocator: *const c_void,
211 bytes: *const u8,
212 encoding: u32,
213 ) -> *mut c_void;
214 fn CFRelease(cf: *const c_void);
215}
216
217#[allow(non_snake_case)]
218unsafe fn CFStringCreateWithCStringLite(bytes: *const u8) -> *const c_void {
219 CFStringCreateWithCString(ptr::null(), bytes, 0x0800_0100).cast_const()
220}
221
222#[allow(non_snake_case)]
223unsafe fn CFReleaseLite(p: *const c_void) {
224 CFRelease(p);
225}