use core::ffi::c_void;
use core::ptr;
use std::ffi::CString;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use crate::ffi as bridge_ffi;
use super::ffi as cg_ffi;
pub struct CGColorSpace {
ptr: *mut c_void,
}
unsafe impl Send for CGColorSpace {}
unsafe impl Sync for CGColorSpace {}
impl Drop for CGColorSpace {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { cg_ffi::CGColorSpaceRelease(self.ptr) };
self.ptr = ptr::null_mut();
}
}
}
impl Clone for CGColorSpace {
fn clone(&self) -> Self {
let p = unsafe { cg_ffi::CGColorSpaceRetain(self.ptr) };
Self { ptr: p }
}
}
impl CGColorSpace {
#[must_use]
pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
Self { ptr }
}
#[must_use]
pub fn device_rgb() -> Self {
Self {
ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceRGB() },
}
}
#[must_use]
pub fn device_gray() -> Self {
Self {
ptr: unsafe { cg_ffi::CGColorSpaceCreateDeviceGray() },
}
}
#[must_use]
pub fn srgb() -> Self {
unsafe {
let n = CFStringCreateWithCStringLite(b"kCGColorSpaceSRGB\0".as_ptr());
let p = cg_ffi::CGColorSpaceCreateWithName(n);
CFReleaseLite(n);
Self { ptr: p }
}
}
#[must_use]
pub fn display_p3() -> Self {
unsafe {
let n = CFStringCreateWithCStringLite(b"kCGColorSpaceDisplayP3\0".as_ptr());
let p = cg_ffi::CGColorSpaceCreateWithName(n);
CFReleaseLite(n);
Self { ptr: p }
}
}
#[must_use]
pub fn number_of_components(&self) -> usize {
unsafe { cg_ffi::CGColorSpaceGetNumberOfComponents(self.ptr) }
}
#[must_use]
pub const fn as_ptr(&self) -> *mut c_void {
self.ptr
}
}
pub struct CGImage {
ptr: *mut c_void,
}
unsafe impl Send for CGImage {}
unsafe impl Sync for CGImage {}
impl Drop for CGImage {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { cg_ffi::CGImageRelease(self.ptr) };
self.ptr = ptr::null_mut();
}
}
}
impl Clone for CGImage {
fn clone(&self) -> Self {
let p = unsafe { cg_ffi::CGImageRetain(self.ptr) };
Self { ptr: p }
}
}
impl CGImage {
#[must_use]
pub const unsafe fn from_raw(ptr: *mut c_void) -> Self {
Self { ptr }
}
#[must_use]
pub fn width(&self) -> usize {
unsafe { cg_ffi::CGImageGetWidth(self.ptr) }
}
#[must_use]
pub fn height(&self) -> usize {
unsafe { cg_ffi::CGImageGetHeight(self.ptr) }
}
#[must_use]
pub fn bits_per_component(&self) -> usize {
unsafe { cg_ffi::CGImageGetBitsPerComponent(self.ptr) }
}
#[must_use]
pub fn bits_per_pixel(&self) -> usize {
unsafe { cg_ffi::CGImageGetBitsPerPixel(self.ptr) }
}
#[must_use]
pub fn bytes_per_row(&self) -> usize {
unsafe { cg_ffi::CGImageGetBytesPerRow(self.ptr) }
}
pub fn save_png<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"path contains an interior NUL byte",
)
})?;
if unsafe { bridge_ffi::cgimage_save_png(self.ptr, c_path.as_ptr()) } {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Other,
"cgimage_save_png returned false",
))
}
}
#[must_use]
pub const fn as_ptr(&self) -> *mut c_void {
self.ptr
}
}
extern "C" {
fn CFStringCreateWithCString(
allocator: *const c_void,
bytes: *const u8,
encoding: u32,
) -> *mut c_void;
fn CFRelease(cf: *const c_void);
}
#[allow(non_snake_case)]
unsafe fn CFStringCreateWithCStringLite(bytes: *const u8) -> *const c_void {
CFStringCreateWithCString(ptr::null(), bytes, 0x0800_0100).cast_const()
}
#[allow(non_snake_case)]
unsafe fn CFReleaseLite(p: *const c_void) {
CFRelease(p);
}