Skip to main content

apple_cf/cg/
drawing.rs

1//! `CGColorSpace`, `CGColor`, and `CGImage` — the most-used pieces
2//! of CoreGraphics' drawing surface.
3//!
4//! These are RAII wrappers around `CFType`-style references with
5//! retain/release. Use them with [`CGContext`] for offscreen
6//! rasterisation, or for converting between formats via `ImageIO`.
7
8use core::ffi::c_void;
9use core::ptr;
10
11/// Reference-counted `CGColorSpaceRef`.
12pub struct CGColorSpace {
13    ptr: *mut c_void,
14}
15
16unsafe impl Send for CGColorSpace {}
17unsafe impl Sync for CGColorSpace {}
18
19impl Drop for CGColorSpace {
20    fn drop(&mut self) {
21        if !self.ptr.is_null() {
22            unsafe { CGColorSpaceRelease(self.ptr) };
23            self.ptr = ptr::null_mut();
24        }
25    }
26}
27
28impl Clone for CGColorSpace {
29    fn clone(&self) -> Self {
30        let p = unsafe { CGColorSpaceRetain(self.ptr) };
31        Self { ptr: p }
32    }
33}
34
35impl CGColorSpace {
36    /// Device RGB.
37    #[must_use]
38    pub fn device_rgb() -> Self {
39        Self {
40            ptr: unsafe { CGColorSpaceCreateDeviceRGB() },
41        }
42    }
43
44    /// Device gray.
45    #[must_use]
46    pub fn device_gray() -> Self {
47        Self {
48            ptr: unsafe { CGColorSpaceCreateDeviceGray() },
49        }
50    }
51
52    /// sRGB.
53    #[must_use]
54    pub fn srgb() -> Self {
55        unsafe {
56            let n = CFStringCreateWithCStringLite(b"kCGColorSpaceSRGB\0".as_ptr());
57            let p = CGColorSpaceCreateWithName(n);
58            CFReleaseLite(n);
59            Self { ptr: p }
60        }
61    }
62
63    /// Display P3.
64    #[must_use]
65    pub fn display_p3() -> Self {
66        unsafe {
67            let n = CFStringCreateWithCStringLite(b"kCGColorSpaceDisplayP3\0".as_ptr());
68            let p = CGColorSpaceCreateWithName(n);
69            CFReleaseLite(n);
70            Self { ptr: p }
71        }
72    }
73
74    /// Number of color components (`3` for RGB, `1` for gray, …).
75    #[must_use]
76    pub fn number_of_components(&self) -> usize {
77        unsafe { CGColorSpaceGetNumberOfComponents(self.ptr) }
78    }
79
80    /// Raw `CGColorSpaceRef` pointer.
81    #[must_use]
82    pub const fn as_ptr(&self) -> *mut c_void {
83        self.ptr
84    }
85}
86
87/// Reference-counted `CGImageRef` — an immutable bitmap.
88pub struct CGImage {
89    ptr: *mut c_void,
90}
91
92unsafe impl Send for CGImage {}
93unsafe impl Sync for CGImage {}
94
95impl Drop for CGImage {
96    fn drop(&mut self) {
97        if !self.ptr.is_null() {
98            unsafe { CGImageRelease(self.ptr) };
99            self.ptr = ptr::null_mut();
100        }
101    }
102}
103
104impl Clone for CGImage {
105    fn clone(&self) -> Self {
106        let p = unsafe { CGImageRetain(self.ptr) };
107        Self { ptr: p }
108    }
109}
110
111impl CGImage {
112    /// Wrap a raw `CGImageRef` pointer — takes ownership without
113    /// retaining.
114    ///
115    /// # Safety
116    ///
117    /// `ptr` must be a non-null `CGImageRef` whose ownership the
118    /// caller is transferring to the returned [`CGImage`].
119    #[must_use]
120    pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
121        Self { ptr }
122    }
123
124    /// Width in pixels.
125    #[must_use]
126    pub fn width(&self) -> usize {
127        unsafe { CGImageGetWidth(self.ptr) }
128    }
129
130    /// Height in pixels.
131    #[must_use]
132    pub fn height(&self) -> usize {
133        unsafe { CGImageGetHeight(self.ptr) }
134    }
135
136    /// Bits per component (`8`, `16`, `32`).
137    #[must_use]
138    pub fn bits_per_component(&self) -> usize {
139        unsafe { CGImageGetBitsPerComponent(self.ptr) }
140    }
141
142    /// Bits per pixel.
143    #[must_use]
144    pub fn bits_per_pixel(&self) -> usize {
145        unsafe { CGImageGetBitsPerPixel(self.ptr) }
146    }
147
148    /// Bytes per row.
149    #[must_use]
150    pub fn bytes_per_row(&self) -> usize {
151        unsafe { CGImageGetBytesPerRow(self.ptr) }
152    }
153
154    /// Raw `CGImageRef` pointer.
155    #[must_use]
156    pub const fn as_ptr(&self) -> *mut c_void {
157        self.ptr
158    }
159}
160
161#[link(name = "ApplicationServices", kind = "framework")]
162extern "C" {
163    fn CGColorSpaceCreateDeviceRGB() -> *mut c_void;
164    fn CGColorSpaceCreateDeviceGray() -> *mut c_void;
165    fn CGColorSpaceCreateWithName(name: *const c_void) -> *mut c_void;
166    fn CGColorSpaceRelease(cs: *mut c_void);
167    fn CGColorSpaceRetain(cs: *mut c_void) -> *mut c_void;
168    fn CGColorSpaceGetNumberOfComponents(cs: *mut c_void) -> usize;
169
170    fn CGImageGetWidth(image: *mut c_void) -> usize;
171    fn CGImageGetHeight(image: *mut c_void) -> usize;
172    fn CGImageGetBitsPerComponent(image: *mut c_void) -> usize;
173    fn CGImageGetBitsPerPixel(image: *mut c_void) -> usize;
174    fn CGImageGetBytesPerRow(image: *mut c_void) -> usize;
175    fn CGImageRelease(image: *mut c_void);
176    fn CGImageRetain(image: *mut c_void) -> *mut c_void;
177
178    fn CFStringCreateWithCString(
179        allocator: *const c_void,
180        bytes: *const u8,
181        encoding: u32,
182    ) -> *mut c_void;
183    fn CFRelease(cf: *const c_void);
184}
185
186#[allow(non_snake_case)]
187unsafe fn CFStringCreateWithCStringLite(bytes: *const u8) -> *const c_void {
188    CFStringCreateWithCString(ptr::null(), bytes, 0x0800_0100).cast_const()
189}
190
191#[allow(non_snake_case)]
192unsafe fn CFReleaseLite(p: *const c_void) {
193    CFRelease(p);
194}