1use std::ptr::{null, null_mut};
2
3use bitflags::bitflags;
4use cfg_if::cfg_if;
5use core_foundation::{
6 base::{CFTypeID, TCFType},
7 impl_CFTypeDescription, impl_TCFType,
8 string::{CFString, CFStringRef},
9};
10use libc::{c_void, size_t};
11#[cfg(feature = "objc")]
12use objc2::encode::{Encoding, RefEncode};
13
14use crate::{
15 base::CGFloat,
16 color_space::{CGColorRenderingIntent, CGColorSpace, CGColorSpaceRef},
17 data_provider::{CGDataProvider, CGDataProviderRef},
18 geometry::CGRect,
19};
20
21#[repr(C)]
22pub struct __CGImage(c_void);
23
24pub type CGImageRef = *mut __CGImage;
25
26pub const kCGImageAlphaNone: u32 = 0;
27pub const kCGImageAlphaPremultipliedLast: u32 = 1;
28pub const kCGImageAlphaPremultipliedFirst: u32 = 2;
29pub const kCGImageAlphaLast: u32 = 3;
30pub const kCGImageAlphaFirst: u32 = 4;
31pub const kCGImageAlphaNoneSkipLast: u32 = 5;
32pub const kCGImageAlphaNoneSkipFirst: u32 = 6;
33pub const kCGImageAlphaOnly: u32 = 7;
34
35pub const kCGImageByteOrderMask: u32 = 0x7000;
36pub const kCGImageByteOrderDefault: u32 = 0 << 12;
37pub const kCGImageByteOrder16Little: u32 = 1 << 12;
38pub const kCGImageByteOrder32Little: u32 = 2 << 12;
39pub const kCGImageByteOrder16Big: u32 = 3 << 12;
40pub const kCGImageByteOrder32Big: u32 = 4 << 12;
41
42pub const kCGImagePixelFormatMask: u32 = 0xF000;
43pub const kCGImagePixelFormatPacked: u32 = 0 << 16;
44pub const kCGImagePixelFormatRGB555: u32 = 1 << 16;
45pub const kCGImagePixelFormatRGB565: u32 = 2 << 16;
46pub const kCGImagePixelFormatRGB101010: u32 = 3 << 16;
47pub const kCGImagePixelFormatRGBCIF10: u32 = 4 << 16;
48
49cfg_if! {
50 if #[cfg(target_endian = "big")] {
51 pub const kCGImageByteOrder16Host: u32 = kCGImageByteOrder16Big;
52 pub const kCGImageByteOrder32Host: u32 = kCGImageByteOrder32Big;
53 } else {
54 pub const kCGImageByteOrder16Host: u32 = kCGImageByteOrder16Little;
55 pub const kCGImageByteOrder32Host: u32 = kCGImageByteOrder32Little;
56 }
57}
58
59extern "C" {
60 pub fn CGImageGetTypeID() -> CFTypeID;
61 pub fn CGImageCreate(
62 width: size_t,
63 height: size_t,
64 bitsPerComponent: size_t,
65 bitsPerPixel: size_t,
66 bytesPerRow: size_t,
67 space: CGColorSpaceRef,
68 bitmapInfo: u32,
69 provider: CGDataProviderRef,
70 decode: *const CGFloat,
71 shouldInterpolate: bool,
72 intent: CGColorRenderingIntent,
73 ) -> CGImageRef;
74 pub fn CGImageMaskCreate(
75 width: size_t,
76 height: size_t,
77 bitsPerComponent: size_t,
78 bitsPerPixel: size_t,
79 bytesPerRow: size_t,
80 provider: CGDataProviderRef,
81 decode: *const CGFloat,
82 shouldInterpolate: bool,
83 ) -> CGImageRef;
84 pub fn CGImageCreateCopy(image: CGImageRef) -> CGImageRef;
85 pub fn CGImageCreateWithJPEGDataProvider(
86 provider: CGDataProviderRef,
87 decode: *const CGFloat,
88 shouldInterpolate: bool,
89 intent: CGColorRenderingIntent,
90 ) -> CGImageRef;
91 pub fn CGImageCreateWithPNGDataProvider(
92 provider: CGDataProviderRef,
93 decode: *const CGFloat,
94 shouldInterpolate: bool,
95 intent: CGColorRenderingIntent,
96 ) -> CGImageRef;
97 pub fn CGImageCreateWithImageInRect(image: CGImageRef, rect: CGRect) -> CGImageRef;
98 pub fn CGImageCreateWithMask(image: CGImageRef, mask: CGImageRef) -> CGImageRef;
99 pub fn CGImageCreateWithMaskingColors(image: CGImageRef, components: *const CGFloat) -> CGImageRef;
100 pub fn CGImageCreateCopyWithColorSpace(image: CGImageRef, space: CGColorSpaceRef) -> CGImageRef;
101 pub fn CGImageRetain(image: CGImageRef) -> CGImageRef;
102 pub fn CGImageRelease(image: CGImageRef);
103 pub fn CGImageIsMask(image: CGImageRef) -> bool;
104 pub fn CGImageGetWidth(image: CGImageRef) -> size_t;
105 pub fn CGImageGetHeight(image: CGImageRef) -> size_t;
106 pub fn CGImageGetBitsPerComponent(image: CGImageRef) -> size_t;
107 pub fn CGImageGetBitsPerPixel(image: CGImageRef) -> size_t;
108 pub fn CGImageGetBytesPerRow(image: CGImageRef) -> size_t;
109 pub fn CGImageGetColorSpace(image: CGImageRef) -> CGColorSpaceRef;
110 pub fn CGImageGetAlphaInfo(image: CGImageRef) -> CGImageAlphaInfo;
111 pub fn CGImageGetDataProvider(image: CGImageRef) -> CGDataProviderRef;
112 pub fn CGImageGetDecode(image: CGImageRef) -> *const CGFloat;
113 pub fn CGImageGetShouldInterpolate(image: CGImageRef) -> bool;
114 pub fn CGImageGetRenderingIntent(image: CGImageRef) -> CGColorRenderingIntent;
115 pub fn CGImageGetBitmapInfo(image: CGImageRef) -> CGBitmapInfo;
116 pub fn CGImageGetByteOrderInfo(image: CGImageRef) -> CGImageByteOrderInfo;
117 pub fn CGImageGetPixelFormatInfo(image: CGImageRef) -> CGImagePixelFormatInfo;
118 pub fn CGImageGetUTType(image: CGImageRef) -> CFStringRef;
119}
120
121#[repr(u32)]
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123pub enum CGImageAlphaInfo {
124 #[doc(alias = "kCGImageAlphaNone")]
125 AlphaNone = kCGImageAlphaNone,
126 #[doc(alias = "kCGImageAlphaPremultipliedLast")]
127 AlphaPremultipliedLast = kCGImageAlphaPremultipliedLast,
128 #[doc(alias = "kCGImageAlphaPremultipliedFirst")]
129 AlphaPremultipliedFirst = kCGImageAlphaPremultipliedFirst,
130 #[doc(alias = "kCGImageAlphaLast")]
131 AlphaLast = kCGImageAlphaLast,
132 #[doc(alias = "kCGImageAlphaFirst")]
133 AlphaFirst = kCGImageAlphaFirst,
134 #[doc(alias = "kCGImageAlphaNoneSkipLast")]
135 AlphaNoneSkipLast = kCGImageAlphaNoneSkipLast,
136 #[doc(alias = "kCGImageAlphaNoneSkipFirst")]
137 AlphaNoneSkipFirst = kCGImageAlphaNoneSkipFirst,
138 #[doc(alias = "kCGImageAlphaOnly")]
139 AlphaOnly = kCGImageAlphaOnly,
140}
141
142#[repr(u32)]
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
144pub enum CGImageByteOrderInfo {
145 #[doc(alias = "kCGImageByteOrderMask")]
146 ByteOrderMask = kCGImageByteOrderMask,
147 #[doc(alias = "kCGImageByteOrderDefault")]
148 ByteOrderDefault = kCGImageByteOrderDefault,
149 #[doc(alias = "kCGImageByteOrder16Little")]
150 ByteOrder16Little = kCGImageByteOrder16Little,
151 #[doc(alias = "kCGImageByteOrder32Little")]
152 ByteOrder32Little = kCGImageByteOrder32Little,
153 #[doc(alias = "kCGImageByteOrder16Big")]
154 ByteOrder16Big = kCGImageByteOrder16Big,
155 #[doc(alias = "kCGImageByteOrder32Big")]
156 ByteOrder32Big = kCGImageByteOrder32Big,
157}
158
159#[repr(u32)]
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub enum CGImagePixelFormatInfo {
162 #[doc(alias = "kCGImagePixelFormatMask")]
163 PixelFormatMask = kCGImagePixelFormatMask,
164 #[doc(alias = "kCGImagePixelFormatPacked")]
165 PixelFormatPacked = kCGImagePixelFormatPacked,
166 #[doc(alias = "kCGImagePixelFormatRGB")]
167 PixelFormatRGB555 = kCGImagePixelFormatRGB555,
168 #[doc(alias = "kCGImagePixelFormatRGB")]
169 PixelFormatRGB565 = kCGImagePixelFormatRGB565,
170 #[doc(alias = "kCGImagePixelFormatRGB")]
171 PixelFormatRGB101010 = kCGImagePixelFormatRGB101010,
172 #[doc(alias = "kCGImagePixelFormatRGB")]
173 PixelFormatRGBCIF10 = kCGImagePixelFormatRGBCIF10,
174}
175
176bitflags! {
177 #[repr(C)]
178 #[derive(Clone, Copy, Debug, Default, PartialEq)]
179 pub struct CGBitmapInfo: u32 {
180 #[doc(alias = "kCGBitmapAlphaInfoMask")]
181 const AlphaInfoMask = 0x1F;
182 const AlphaNone = kCGImageAlphaNone;
183 const AlphaPremultipliedLast = kCGImageAlphaPremultipliedLast;
184 const AlphaPremultipliedFirst = kCGImageAlphaPremultipliedFirst;
185 const AlphaLast = kCGImageAlphaLast;
186 const AlphaFirst = kCGImageAlphaFirst;
187 const AlphaNoneSkipLast = kCGImageAlphaNoneSkipLast;
188 const AlphaNoneSkipFirst = kCGImageAlphaNoneSkipFirst;
189 const AlphaOnly = kCGImageAlphaOnly;
190 #[doc(alias = "kCGBitmapFloatInfoMask")]
191 const FloatInfoMask = 0xF00;
192 #[doc(alias = "kCGBitmapFloatComponents")]
193 const FloatComponents = 1 << 8;
194 #[doc(alias = "kCGBitmapByteOrderMask")]
195 const ByteOrderMask = kCGImageByteOrderMask;
196 #[doc(alias = "kCGBitmapByteOrderDefault")]
197 const ByteOrderDefault = kCGImageByteOrderDefault;
198 #[doc(alias = "kCGBitmapByteOrder16Little")]
199 const ByteOrder16Little = kCGImageByteOrder16Little;
200 #[doc(alias = "kCGBitmapByteOrder32Little")]
201 const ByteOrder32Little = kCGImageByteOrder32Little;
202 #[doc(alias = "kCGBitmapByteOrder16Big")]
203 const ByteOrder16Big = kCGImageByteOrder16Big;
204 #[doc(alias = "kCGBitmapByteOrder32Big")]
205 const ByteOrder32Big = kCGImageByteOrder32Big;
206 #[doc(alias = "kCGBitmapByteOrder16Host")]
207 const ByteOrder16Host = kCGImageByteOrder16Host;
208 #[doc(alias = "kCGBitmapByteOrder32Host")]
209 const ByteOrder32Host = kCGImageByteOrder32Host;
210 const PixelFormatMask = kCGImagePixelFormatMask;
211 const PixelFormatPacked = kCGImagePixelFormatPacked;
212 const PixelFormatRGB555 = kCGImagePixelFormatRGB555;
213 const PixelFormatRGB565 = kCGImagePixelFormatRGB565;
214 const PixelFormatRGB101010 = kCGImagePixelFormatRGB101010;
215 const PixelFormatRGBCIF10 = kCGImagePixelFormatRGBCIF10;
216 }
217}
218
219pub struct CGImage(CGImageRef);
220
221impl Drop for CGImage {
222 fn drop(&mut self) {
223 unsafe { CGImageRelease(self.0) }
224 }
225}
226
227impl_TCFType!(CGImage, CGImageRef, CGImageGetTypeID);
228impl_CFTypeDescription!(CGImage);
229
230impl CGImage {
231 pub fn new(
232 width: size_t,
233 height: size_t,
234 bits_per_component: size_t,
235 bits_per_pixel: size_t,
236 bytes_per_row: size_t,
237 space: Option<&CGColorSpace>,
238 bitmap_info: u32,
239 provider: Option<&CGDataProvider>,
240 decode: Option<&[CGFloat]>,
241 should_interpolate: bool,
242 intent: CGColorRenderingIntent,
243 ) -> Option<Self> {
244 unsafe {
245 let image = CGImageCreate(
246 width,
247 height,
248 bits_per_component,
249 bits_per_pixel,
250 bytes_per_row,
251 space.map_or(null_mut(), |s| s.as_concrete_TypeRef()),
252 bitmap_info,
253 provider.map_or(null(), |p| p.as_concrete_TypeRef()),
254 decode.map_or(null(), |d| d.as_ptr()),
255 should_interpolate,
256 intent,
257 );
258 if image.is_null() {
259 None
260 } else {
261 Some(TCFType::wrap_under_create_rule(image))
262 }
263 }
264 }
265
266 pub fn new_mask(
267 width: size_t,
268 height: size_t,
269 bits_per_component: size_t,
270 bits_per_pixel: size_t,
271 bytes_per_row: size_t,
272 provider: Option<&CGDataProvider>,
273 decode: Option<&[CGFloat]>,
274 should_interpolate: bool,
275 ) -> Option<Self> {
276 unsafe {
277 let image = CGImageMaskCreate(
278 width,
279 height,
280 bits_per_component,
281 bits_per_pixel,
282 bytes_per_row,
283 provider.map_or(null(), |p| p.as_concrete_TypeRef()),
284 decode.map_or(null(), |d| d.as_ptr()),
285 should_interpolate,
286 );
287 if image.is_null() {
288 None
289 } else {
290 Some(TCFType::wrap_under_create_rule(image))
291 }
292 }
293 }
294
295 pub fn from_jpeg_data_provider(
296 provider: &CGDataProvider,
297 decode: Option<&[CGFloat]>,
298 should_interpolate: bool,
299 intent: CGColorRenderingIntent,
300 ) -> Option<Self> {
301 unsafe {
302 let image =
303 CGImageCreateWithJPEGDataProvider(provider.as_concrete_TypeRef(), decode.map_or(null(), |d| d.as_ptr()), should_interpolate, intent);
304 if image.is_null() {
305 None
306 } else {
307 Some(TCFType::wrap_under_create_rule(image))
308 }
309 }
310 }
311
312 pub fn from_png_data_provider(
313 provider: &CGDataProvider,
314 decode: Option<&[CGFloat]>,
315 should_interpolate: bool,
316 intent: CGColorRenderingIntent,
317 ) -> Option<Self> {
318 unsafe {
319 let image =
320 CGImageCreateWithPNGDataProvider(provider.as_concrete_TypeRef(), decode.map_or(null(), |d| d.as_ptr()), should_interpolate, intent);
321 if image.is_null() {
322 None
323 } else {
324 Some(TCFType::wrap_under_create_rule(image))
325 }
326 }
327 }
328
329 pub fn new_copy(&self) -> Option<Self> {
330 unsafe {
331 let image = CGImageCreateCopy(self.as_concrete_TypeRef());
332 if image.is_null() {
333 None
334 } else {
335 Some(TCFType::wrap_under_create_rule(image))
336 }
337 }
338 }
339
340 pub fn new_copy_with_color_space(&self, space: &CGColorSpace) -> Option<Self> {
341 unsafe {
342 let image = CGImageCreateCopyWithColorSpace(self.as_concrete_TypeRef(), space.as_concrete_TypeRef());
343 if image.is_null() {
344 None
345 } else {
346 Some(TCFType::wrap_under_create_rule(image))
347 }
348 }
349 }
350
351 pub fn new_with_mask(&self, mask: &CGImage) -> Option<Self> {
352 unsafe {
353 let image = CGImageCreateWithMask(self.as_concrete_TypeRef(), mask.as_concrete_TypeRef());
354 if image.is_null() {
355 None
356 } else {
357 Some(TCFType::wrap_under_create_rule(image))
358 }
359 }
360 }
361
362 pub fn new_with_masking_colors(&self, components: &[CGFloat]) -> Option<Self> {
363 unsafe {
364 let color_space = self.color_space()?;
365 let num_components = color_space.number_of_components();
366 if components.len() != num_components * 2 {
367 return None;
368 }
369 let image = CGImageCreateWithMaskingColors(self.as_concrete_TypeRef(), components.as_ptr());
370 if image.is_null() {
371 None
372 } else {
373 Some(TCFType::wrap_under_create_rule(image))
374 }
375 }
376 }
377
378 pub fn cropped(&self, rect: CGRect) -> Option<Self> {
379 unsafe {
380 let image = CGImageCreateWithImageInRect(self.as_concrete_TypeRef(), rect);
381 if image.is_null() {
382 None
383 } else {
384 Some(TCFType::wrap_under_create_rule(image))
385 }
386 }
387 }
388
389 pub fn is_mask(&self) -> bool {
390 unsafe { CGImageIsMask(self.as_concrete_TypeRef()) }
391 }
392
393 pub fn width(&self) -> size_t {
394 unsafe { CGImageGetWidth(self.as_concrete_TypeRef()) }
395 }
396
397 pub fn height(&self) -> size_t {
398 unsafe { CGImageGetHeight(self.as_concrete_TypeRef()) }
399 }
400
401 pub fn bits_per_component(&self) -> size_t {
402 unsafe { CGImageGetBitsPerComponent(self.as_concrete_TypeRef()) }
403 }
404
405 pub fn bits_per_pixel(&self) -> size_t {
406 unsafe { CGImageGetBitsPerPixel(self.as_concrete_TypeRef()) }
407 }
408
409 pub fn bytes_per_row(&self) -> size_t {
410 unsafe { CGImageGetBytesPerRow(self.as_concrete_TypeRef()) }
411 }
412
413 pub fn color_space(&self) -> Option<CGColorSpace> {
414 unsafe {
415 let space = CGImageGetColorSpace(self.as_concrete_TypeRef());
416 if space.is_null() {
417 None
418 } else {
419 Some(TCFType::wrap_under_get_rule(space))
420 }
421 }
422 }
423
424 pub fn alpha_info(&self) -> CGImageAlphaInfo {
425 unsafe { CGImageGetAlphaInfo(self.as_concrete_TypeRef()) }
426 }
427
428 pub fn data_provider(&self) -> Option<CGDataProvider> {
429 unsafe {
430 let provider = CGImageGetDataProvider(self.as_concrete_TypeRef());
431 if provider.is_null() {
432 None
433 } else {
434 Some(TCFType::wrap_under_get_rule(provider))
435 }
436 }
437 }
438
439 pub fn should_interpolate(&self) -> bool {
440 unsafe { CGImageGetShouldInterpolate(self.as_concrete_TypeRef()) }
441 }
442
443 pub fn rendering_intent(&self) -> CGColorRenderingIntent {
444 unsafe { CGImageGetRenderingIntent(self.as_concrete_TypeRef()) }
445 }
446
447 pub fn bitmap_info(&self) -> CGBitmapInfo {
448 unsafe { CGImageGetBitmapInfo(self.as_concrete_TypeRef()) }
449 }
450
451 pub fn byte_order_info(&self) -> CGImageByteOrderInfo {
452 unsafe { CGImageGetByteOrderInfo(self.as_concrete_TypeRef()) }
453 }
454
455 pub fn pixel_format_info(&self) -> CGImagePixelFormatInfo {
456 unsafe { CGImageGetPixelFormatInfo(self.as_concrete_TypeRef()) }
457 }
458
459 pub fn ut_type(&self) -> Option<CFString> {
460 unsafe {
461 let ut_type = CGImageGetUTType(self.as_concrete_TypeRef());
462 if ut_type.is_null() {
463 None
464 } else {
465 Some(TCFType::wrap_under_get_rule(ut_type))
466 }
467 }
468 }
469}
470
471#[cfg(feature = "objc")]
472unsafe impl RefEncode for __CGImage {
473 const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct("CGImage", &[]));
474}