core_graphics2/
bitmap_context.rs

1use std::{mem, ptr::null_mut, slice};
2
3use core_foundation::base::TCFType;
4use libc::{c_void, size_t};
5
6use crate::{
7    color_space::{CGColorSpace, CGColorSpaceRef},
8    context::{CGContext, CGContextRef},
9    image::{CGBitmapInfo, CGImage, CGImageAlphaInfo, CGImageRef},
10};
11
12pub type CGBitmapContextReleaseDataCallback = extern "C" fn(*mut c_void, *mut c_void);
13
14extern "C" {
15    pub fn CGBitmapContextCreateWithData(
16        data: *mut c_void,
17        width: size_t,
18        height: size_t,
19        bitsPerComponent: size_t,
20        bytesPerRow: size_t,
21        space: CGColorSpaceRef,
22        bitmapInfo: u32,
23        releaseCallback: CGBitmapContextReleaseDataCallback,
24        releaseInfo: *mut c_void,
25    ) -> CGContextRef;
26    pub fn CGBitmapContextCreate(
27        data: *mut c_void,
28        width: size_t,
29        height: size_t,
30        bitsPerComponent: size_t,
31        bytesPerRow: size_t,
32        space: CGColorSpaceRef,
33        bitmapInfo: u32,
34    ) -> CGContextRef;
35    pub fn CGBitmapContextGetData(context: CGContextRef) -> *mut c_void;
36    pub fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
37    pub fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
38    pub fn CGBitmapContextGetBitsPerComponent(context: CGContextRef) -> size_t;
39    pub fn CGBitmapContextGetBitsPerPixel(context: CGContextRef) -> size_t;
40    pub fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
41    pub fn CGBitmapContextGetColorSpace(context: CGContextRef) -> CGColorSpaceRef;
42    pub fn CGBitmapContextGetAlphaInfo(context: CGContextRef) -> CGImageAlphaInfo;
43    pub fn CGBitmapContextGetBitmapInfo(context: CGContextRef) -> CGBitmapInfo;
44    pub fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
45}
46
47pub trait BitmapData {
48    unsafe fn ptr(&self) -> *const u8;
49    unsafe fn mut_ptr(&self) -> *mut u8;
50    fn width(&self) -> usize;
51    fn height(&self) -> usize;
52    fn bytes_per_row(&self) -> usize;
53}
54
55impl CGContext {
56    pub fn new_bitmap_context(
57        width: size_t,
58        height: size_t,
59        bits_per_component: size_t,
60        bytes_per_row: size_t,
61        space: Option<&CGColorSpace>,
62        bitmap_info: u32,
63    ) -> Option<Self> {
64        unsafe {
65            let context = CGBitmapContextCreate(
66                null_mut(),
67                width,
68                height,
69                bits_per_component,
70                bytes_per_row,
71                space.map_or(null_mut(), |s| s.as_concrete_TypeRef()),
72                bitmap_info,
73            );
74            if context.is_null() {
75                None
76            } else {
77                Some(TCFType::wrap_under_create_rule(context))
78            }
79        }
80    }
81
82    pub unsafe fn new_bitmap_context_with_data(
83        data: &mut [u8],
84        width: size_t,
85        height: size_t,
86        bits_per_component: size_t,
87        bytes_per_row: size_t,
88        space: Option<&CGColorSpace>,
89        bitmap_info: u32,
90    ) -> Option<Self> {
91        if data.len() < height * bytes_per_row {
92            return None;
93        }
94        unsafe {
95            let context = CGBitmapContextCreate(
96                data.as_mut_ptr() as *mut c_void,
97                width,
98                height,
99                bits_per_component,
100                bytes_per_row,
101                space.map_or(null_mut(), |s| s.as_concrete_TypeRef()),
102                bitmap_info,
103            );
104            if context.is_null() {
105                None
106            } else {
107                Some(TCFType::wrap_under_create_rule(context))
108            }
109        }
110    }
111
112    pub fn new_bitmap_context_with_bitmap_data(
113        bitmap_data: Box<Box<dyn BitmapData>>,
114        bits_per_component: size_t,
115        space: Option<&CGColorSpace>,
116        bitmap_info: u32,
117    ) -> Option<Self> {
118        let (width, height, bytes_per_row) = (bitmap_data.width() as size_t, bitmap_data.height() as size_t, bitmap_data.bytes_per_row() as size_t);
119        unsafe {
120            let ptr = bitmap_data.mut_ptr() as *mut c_void;
121            let info = mem::transmute::<Box<Box<dyn BitmapData>>, &mut c_void>(bitmap_data);
122            let context = CGBitmapContextCreateWithData(
123                ptr,
124                width,
125                height,
126                bits_per_component,
127                bytes_per_row,
128                space.map_or(null_mut(), |s| s.as_concrete_TypeRef()),
129                bitmap_info,
130                release,
131                info,
132            );
133            if context.is_null() {
134                drop(mem::transmute::<*mut c_void, Box<Box<dyn BitmapData>>>(info));
135                return None;
136            } else {
137                return Some(TCFType::wrap_under_create_rule(context));
138            }
139        }
140
141        extern "C" fn release(release_info: *mut c_void, _: *mut c_void) {
142            unsafe { drop(mem::transmute::<*mut c_void, Box<Box<dyn BitmapData>>>(release_info)) }
143        }
144    }
145
146    pub fn new_image(&self) -> Option<CGImage> {
147        unsafe {
148            let image = CGBitmapContextCreateImage(self.as_concrete_TypeRef());
149            if image.is_null() {
150                None
151            } else {
152                Some(TCFType::wrap_under_create_rule(image))
153            }
154        }
155    }
156
157    pub fn data(&mut self) -> &mut [u8] {
158        unsafe { slice::from_raw_parts_mut(CGBitmapContextGetData(self.as_concrete_TypeRef()) as *mut u8, self.height() * self.bytes_per_row()) }
159    }
160
161    pub fn width(&self) -> usize {
162        unsafe { CGBitmapContextGetWidth(self.as_concrete_TypeRef()) }
163    }
164
165    pub fn height(&self) -> usize {
166        unsafe { CGBitmapContextGetHeight(self.as_concrete_TypeRef()) }
167    }
168
169    pub fn bits_per_component(&self) -> usize {
170        unsafe { CGBitmapContextGetBitsPerComponent(self.as_concrete_TypeRef()) }
171    }
172
173    pub fn bits_per_pixel(&self) -> usize {
174        unsafe { CGBitmapContextGetBitsPerPixel(self.as_concrete_TypeRef()) }
175    }
176
177    pub fn bytes_per_row(&self) -> usize {
178        unsafe { CGBitmapContextGetBytesPerRow(self.as_concrete_TypeRef()) }
179    }
180
181    pub fn color_space(&self) -> CGColorSpace {
182        unsafe { TCFType::wrap_under_get_rule(CGBitmapContextGetColorSpace(self.as_concrete_TypeRef())) }
183    }
184
185    pub fn alpha_info(&self) -> CGImageAlphaInfo {
186        unsafe { CGBitmapContextGetAlphaInfo(self.as_concrete_TypeRef()) }
187    }
188
189    pub fn bitmap_info(&self) -> CGBitmapInfo {
190        unsafe { CGBitmapContextGetBitmapInfo(self.as_concrete_TypeRef()) }
191    }
192}