apple_accelerate/
vimage.rs1use crate::bridge;
2use crate::error::{Error, Result};
3use core::ffi::c_void;
4use core::marker::PhantomData;
5
6pub mod vimage_flags {
8 pub const NO_FLAGS: u32 = 0;
9 pub const BACKGROUND_COLOR_FILL: u32 = 4;
10 pub const EDGE_EXTEND: u32 = 8;
11 pub const HIGH_QUALITY_RESAMPLING: u32 = 32;
12}
13
14fn vimage_result(status: isize) -> Result<()> {
15 if status == 0 {
16 Ok(())
17 } else {
18 Err(Error::VImageError(status))
19 }
20}
21
22pub struct ImageBuffer<'a> {
24 data: *mut u8,
25 width: usize,
26 height: usize,
27 row_bytes: usize,
28 _marker: PhantomData<&'a mut [u8]>,
29}
30
31impl<'a> ImageBuffer<'a> {
32 pub fn from_argb8888(data: &'a mut [u8], width: usize, height: usize) -> Result<Self> {
33 let expected = width
34 .checked_mul(height)
35 .and_then(|pixels| pixels.checked_mul(4))
36 .ok_or(Error::OperationFailed("image dimensions overflowed"))?;
37 if data.len() < expected {
38 return Err(Error::InvalidLength {
39 expected,
40 actual: data.len(),
41 });
42 }
43
44 Ok(Self {
45 data: data.as_mut_ptr(),
46 width,
47 height,
48 row_bytes: width * 4,
49 _marker: PhantomData,
50 })
51 }
52
53 pub fn from_planar8(data: &'a mut [u8], width: usize, height: usize) -> Result<Self> {
54 let expected = width
55 .checked_mul(height)
56 .ok_or(Error::OperationFailed("image dimensions overflowed"))?;
57 if data.len() < expected {
58 return Err(Error::InvalidLength {
59 expected,
60 actual: data.len(),
61 });
62 }
63
64 Ok(Self {
65 data: data.as_mut_ptr(),
66 width,
67 height,
68 row_bytes: width,
69 _marker: PhantomData,
70 })
71 }
72
73 fn data_ptr(&self) -> *mut c_void {
74 self.data.cast()
75 }
76
77 fn width(&self) -> usize {
78 self.width
79 }
80
81 fn height(&self) -> usize {
82 self.height
83 }
84
85 fn row_bytes(&self) -> usize {
86 self.row_bytes
87 }
88}
89
90pub fn rotate_argb8888(
91 src: &ImageBuffer<'_>,
92 dst: &mut ImageBuffer<'_>,
93 angle_radians: f32,
94 background_color: [u8; 4],
95 flags: u32,
96) -> Result<()> {
97 let status = unsafe {
99 bridge::acc_vimage_rotate_argb8888(
100 src.data_ptr(),
101 src.width(),
102 src.height(),
103 src.row_bytes(),
104 dst.data_ptr(),
105 dst.width(),
106 dst.height(),
107 dst.row_bytes(),
108 angle_radians,
109 background_color.as_ptr(),
110 flags,
111 )
112 };
113 vimage_result(status)
114}
115
116pub fn box_convolve_argb8888(
117 src: &ImageBuffer<'_>,
118 dst: &mut ImageBuffer<'_>,
119 kernel_height: u32,
120 kernel_width: u32,
121 background_color: [u8; 4],
122 flags: u32,
123) -> Result<()> {
124 let status = unsafe {
126 bridge::acc_vimage_box_convolve_argb8888(
127 src.data_ptr(),
128 src.width(),
129 src.height(),
130 src.row_bytes(),
131 dst.data_ptr(),
132 dst.width(),
133 dst.height(),
134 dst.row_bytes(),
135 kernel_height,
136 kernel_width,
137 background_color.as_ptr(),
138 flags,
139 )
140 };
141 vimage_result(status)
142}
143
144pub fn scale_argb8888(src: &ImageBuffer<'_>, dst: &mut ImageBuffer<'_>, flags: u32) -> Result<()> {
145 let status = unsafe {
147 bridge::acc_vimage_scale_argb8888(
148 src.data_ptr(),
149 src.width(),
150 src.height(),
151 src.row_bytes(),
152 dst.data_ptr(),
153 dst.width(),
154 dst.height(),
155 dst.row_bytes(),
156 flags,
157 )
158 };
159 vimage_result(status)
160}
161
162pub fn contrast_stretch_planar8(
163 src: &ImageBuffer<'_>,
164 dst: &mut ImageBuffer<'_>,
165 flags: u32,
166) -> Result<()> {
167 let status = unsafe {
169 bridge::acc_vimage_contrast_stretch_planar8(
170 src.data_ptr(),
171 src.width(),
172 src.height(),
173 src.row_bytes(),
174 dst.data_ptr(),
175 dst.width(),
176 dst.height(),
177 dst.row_bytes(),
178 flags,
179 )
180 };
181 vimage_result(status)
182}