skia_safe/core/
yuva_pixmaps.rs1use crate::{ColorType, Data, ImageInfo, Pixmap, YUVAInfo, YUVColorSpace, prelude::*};
2use skia_bindings::{self as sb, SkYUVAPixmapInfo, SkYUVAPixmaps};
3use std::{ffi::c_void, fmt, ptr};
4use yuva_pixmap_info::SupportedDataTypes;
5
6pub use yuva_pixmap_info::DataType;
8variant_name!(DataType::Float16);
9
10pub type YUVAPixmapInfo = Handle<SkYUVAPixmapInfo>;
13unsafe_send_sync!(YUVAPixmapInfo);
14
15impl NativeDrop for SkYUVAPixmapInfo {
16 fn drop(&mut self) {
17 unsafe { sb::C_SkYUVAPixmapInfo_destruct(self) }
18 }
19}
20
21impl NativePartialEq for SkYUVAPixmapInfo {
22 fn eq(&self, rhs: &Self) -> bool {
23 unsafe { sb::C_SkYUVAPixmapInfo_equals(self, rhs) }
24 }
25}
26
27impl fmt::Debug for YUVAPixmapInfo {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 let plane_infos: Vec<_> = self.plane_infos().collect();
30 let row_bytes: Vec<_> = self.row_bytes_iter().collect();
31 f.debug_struct("YUVAPixmapInfo")
32 .field("yuva_info", &self.yuva_info())
33 .field("plane_infos", &plane_infos)
34 .field("row_bytes", &row_bytes)
35 .field("data_type", &self.data_type())
36 .finish()
37 }
38}
39
40impl YUVAPixmapInfo {
41 pub const MAX_PLANES: usize = sb::SkYUVAInfo_kMaxPlanes as _;
42 pub const DATA_TYPE_CNT: usize = DataType::Last as _;
43
44 pub fn new(
52 info: &YUVAInfo,
53 color_types: &[ColorType],
54 row_bytes: Option<&[usize]>,
55 ) -> Option<Self> {
56 if color_types.len() != info.num_planes() {
57 return None;
58 }
59 if let Some(rb) = row_bytes {
60 if rb.len() != color_types.len() {
61 return None;
62 }
63 }
64 let mut color_types_array = [ColorType::Unknown; Self::MAX_PLANES];
65 color_types_array[..color_types.len()].copy_from_slice(color_types);
66
67 let mut row_bytes_array = [0; Self::MAX_PLANES];
68 let row_bytes_ptr = {
69 if let Some(row_bytes) = row_bytes {
70 row_bytes_array[..row_bytes.len()].copy_from_slice(row_bytes);
71 row_bytes_array.as_ptr()
72 } else {
73 ptr::null()
74 }
75 };
76
77 let info = unsafe {
78 SkYUVAPixmapInfo::new(
79 info.native(),
80 color_types_array.native().as_ptr(),
81 row_bytes_ptr,
82 )
83 };
84 Self::native_is_valid(&info).then(|| Self::from_native_c(info))
85 }
86
87 pub fn from_data_type(
90 info: &YUVAInfo,
91 data_type: DataType,
92 row_bytes: Option<&[usize]>,
93 ) -> Option<Self> {
94 let mut row_bytes_array = [0; Self::MAX_PLANES];
95 let row_bytes_ptr = {
96 if let Some(row_bytes) = row_bytes {
97 row_bytes_array[..row_bytes.len()].copy_from_slice(row_bytes);
98 row_bytes_array.as_ptr()
99 } else {
100 ptr::null()
101 }
102 };
103
104 let info = unsafe { SkYUVAPixmapInfo::new1(info.native(), data_type, row_bytes_ptr) };
105
106 Self::native_is_valid(&info).then(|| Self::from_native_c(info))
107 }
108
109 pub fn yuva_info(&self) -> &YUVAInfo {
110 YUVAInfo::from_native_ref(&self.native().fYUVAInfo)
111 }
112
113 pub fn yuv_color_space(&self) -> YUVColorSpace {
114 self.yuva_info().yuv_color_space()
115 }
116
117 pub fn num_planes(&self) -> usize {
119 self.yuva_info().num_planes()
120 }
121
122 pub fn data_type(&self) -> DataType {
124 self.native().fDataType
125 }
126
127 pub fn row_bytes(&self, i: usize) -> Option<usize> {
131 (i < self.num_planes()).then(|| unsafe {
132 sb::C_SkYUVAPixmapInfo_rowBytes(self.native(), i.try_into().unwrap())
133 })
134 }
135
136 pub fn row_bytes_iter(&self) -> impl Iterator<Item = usize> + use<'_> {
138 (0..self.num_planes()).map(move |i| self.row_bytes(i).unwrap())
139 }
140
141 pub fn plane_info(&self, i: usize) -> Option<&ImageInfo> {
145 (i < self.num_planes()).then(|| {
146 ImageInfo::from_native_ref(unsafe {
147 &*sb::C_SkYUVAPixmapInfo_planeInfo(self.native(), i.try_into().unwrap())
148 })
149 })
150 }
151
152 pub fn plane_infos(&self) -> impl Iterator<Item = &ImageInfo> {
154 (0..self.num_planes()).map(move |i| self.plane_info(i).unwrap())
155 }
156
157 pub fn compute_total_bytes(
161 &self,
162 plane_sizes: Option<&mut [usize; Self::MAX_PLANES]>,
163 ) -> usize {
164 unsafe {
165 self.native().computeTotalBytes(
166 plane_sizes
167 .map(|ps| ps.as_mut_ptr())
168 .unwrap_or(ptr::null_mut()),
169 )
170 }
171 }
172
173 #[allow(clippy::missing_safety_doc)]
177 pub unsafe fn init_pixmaps_from_single_allocation(
178 &self,
179 memory: *mut c_void,
180 ) -> Option<[Pixmap; Self::MAX_PLANES]> {
181 unsafe {
182 let mut pixmaps: [Pixmap; Self::MAX_PLANES] = Default::default();
184 self.native()
185 .initPixmapsFromSingleAllocation(memory, pixmaps[0].native_mut())
186 .then_some(pixmaps)
187 }
188 }
189
190 pub fn is_supported(&self, data_types: &SupportedDataTypes) -> bool {
192 unsafe { self.native().isSupported(data_types.native()) }
193 }
194
195 pub(crate) fn new_if_valid(
196 set_pixmap_info: impl Fn(&mut SkYUVAPixmapInfo) -> bool,
197 ) -> Option<Self> {
198 let mut pixmap_info = Self::new_invalid();
199 let r = set_pixmap_info(&mut pixmap_info);
200 (r && Self::native_is_valid(&pixmap_info))
201 .then(|| YUVAPixmapInfo::from_native_c(pixmap_info))
202 }
203
204 fn native_is_valid(info: *const SkYUVAPixmapInfo) -> bool {
207 unsafe { sb::C_SkYUVAPixmapInfo_isValid(info) }
208 }
209
210 fn new_invalid() -> SkYUVAPixmapInfo {
212 construct(|pi| unsafe { sb::C_SkYUVAPixmapInfo_Construct(pi) })
213 }
214}
215
216pub type YUVAPixmaps = Handle<SkYUVAPixmaps>;
219unsafe_send_sync!(YUVAPixmaps);
220
221impl NativeDrop for SkYUVAPixmaps {
222 fn drop(&mut self) {
223 unsafe { sb::C_SkYUVAPixmaps_destruct(self) }
224 }
225}
226
227impl NativeClone for SkYUVAPixmaps {
228 fn clone(&self) -> Self {
229 construct(|pixmaps| unsafe { sb::C_SkYUVAPixmaps_MakeCopy(self, pixmaps) })
230 }
231}
232
233impl fmt::Debug for YUVAPixmaps {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 f.debug_struct("YUVAPixmaps")
236 .field("planes", &self.planes())
237 .field("yuva_info", &self.yuva_info())
238 .field("data_type", &self.data_type())
239 .finish()
240 }
241}
242
243impl YUVAPixmaps {
244 pub const MAX_PLANES: usize = YUVAPixmapInfo::MAX_PLANES;
245
246 pub fn recommended_rgba_color_type(dt: DataType) -> ColorType {
247 ColorType::from_native_c(unsafe { sb::SkYUVAPixmaps::RecommendedRGBAColorType(dt) })
248 }
249
250 pub fn allocate(info: &YUVAPixmapInfo) -> Option<Self> {
252 Self::try_construct(|pixmaps| unsafe {
253 sb::C_SkYUVAPixmaps_Allocate(pixmaps, info.native());
254 Self::native_is_valid(pixmaps)
255 })
256 }
257
258 pub fn from_data(info: &YUVAPixmapInfo, data: impl Into<Data>) -> Option<Self> {
261 Self::try_construct(|pixmaps| unsafe {
262 sb::C_SkYUVAPixmaps_FromData(pixmaps, info.native(), data.into().into_ptr());
263 Self::native_is_valid(pixmaps)
264 })
265 }
266
267 #[allow(clippy::missing_safety_doc)]
271 pub unsafe fn from_external_memory(info: &YUVAPixmapInfo, memory: *mut c_void) -> Option<Self> {
272 unsafe {
273 Self::try_construct(|pixmaps| {
274 sb::C_SkYUVAPixmaps_FromExternalMemory(pixmaps, info.native(), memory);
275 Self::native_is_valid(pixmaps)
276 })
277 }
278 }
279
280 #[allow(clippy::missing_safety_doc)]
285 pub unsafe fn from_external_pixmaps(
286 info: &YUVAInfo,
287 pixmaps: &[Pixmap; Self::MAX_PLANES],
288 ) -> Option<Self> {
289 unsafe {
290 Self::try_construct(|pms| {
291 sb::C_SkYUVAPixmaps_FromExternalPixmaps(pms, info.native(), pixmaps[0].native());
292 Self::native_is_valid(pms)
293 })
294 }
295 }
296
297 pub fn yuva_info(&self) -> &YUVAInfo {
298 YUVAInfo::from_native_ref(&self.native().fYUVAInfo)
299 }
300
301 pub fn data_type(&self) -> DataType {
302 self.native().fDataType
303 }
304
305 pub fn pixmaps_info(&self) -> YUVAPixmapInfo {
306 YUVAPixmapInfo::construct(|info| unsafe {
307 sb::C_SkYUVAPixmaps_pixmapsInfo(self.native(), info)
308 })
309 }
310
311 pub fn num_planes(&self) -> usize {
313 self.yuva_info().num_planes()
314 }
315
316 pub fn planes(&self) -> &[Pixmap] {
318 unsafe {
319 let planes = Pixmap::from_native_ptr(sb::C_SkYUVAPixmaps_planes(self.native()));
320 safer::from_raw_parts(planes, self.num_planes())
321 }
322 }
323
324 pub fn plane(&self, i: usize) -> &Pixmap {
328 &self.planes()[i]
329 }
330
331 pub(crate) fn native_is_valid(pixmaps: *const SkYUVAPixmaps) -> bool {
332 unsafe { sb::C_SkYUVAPixmaps_isValid(pixmaps) }
333 }
334}
335
336pub mod yuva_pixmap_info {
337 use crate::{ColorType, prelude::*};
338 use skia_bindings::{self as sb, SkYUVAPixmapInfo_SupportedDataTypes};
339 use std::fmt;
340
341 pub use crate::yuva_info::PlaneConfig;
342 pub use crate::yuva_info::Subsampling;
343
344 pub use skia_bindings::SkYUVAPixmapInfo_DataType as DataType;
347
348 pub type SupportedDataTypes = Handle<SkYUVAPixmapInfo_SupportedDataTypes>;
349 unsafe_send_sync!(SupportedDataTypes);
350
351 impl NativeDrop for SkYUVAPixmapInfo_SupportedDataTypes {
352 fn drop(&mut self) {
353 unsafe { sb::C_SkYUVAPixmapInfo_SupportedDataTypes_destruct(self) }
354 }
355 }
356
357 impl Default for SupportedDataTypes {
358 fn default() -> Self {
360 Self::construct(|sdt| unsafe {
361 sb::C_SkYUVAPixmapInfo_SupportedDataTypes_Construct(sdt)
362 })
363 }
364 }
365
366 impl fmt::Debug for SupportedDataTypes {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 f.debug_struct("SupportedDataType")
369 .field("data_type_support", &self.native().fDataTypeSupport)
370 .finish()
371 }
372 }
373
374 impl SupportedDataTypes {
375 pub fn all() -> Self {
377 Self::construct(|sdt| unsafe { sb::C_SkYUVAPixmapInfo_SupportedDataTypes_All(sdt) })
378 }
379
380 pub fn supported(&self, pc: PlaneConfig, dt: DataType) -> bool {
383 unsafe { sb::C_SkYUVAPixmapInfo_SupportedDataTypes_supported(self.native(), pc, dt) }
384 }
385
386 pub fn enable_data_type(&mut self, dt: DataType, num_channels: usize) {
389 unsafe {
390 self.native_mut()
391 .enableDataType(dt, num_channels.try_into().unwrap())
392 }
393 }
394 }
395
396 pub fn default_color_type_for_data_type(dt: DataType, num_channels: usize) -> ColorType {
399 ColorType::from_native_c(unsafe {
400 sb::C_SkYUVAPixmapInfo_DefaultColorTypeForDataType(dt, num_channels.try_into().unwrap())
401 })
402 }
403
404 pub fn num_channels_and_data_type(color_type: ColorType) -> (usize, DataType) {
409 let mut data_type = DataType::Float16;
410 let channels = unsafe {
411 sb::C_SkYUVAPixmapInfo_NumChannelsAndDataType(color_type.into_native(), &mut data_type)
412 };
413 (channels.try_into().unwrap(), data_type)
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use crate::{ColorType, YUVAPixmaps};
420
421 #[test]
422 fn recommended_color_type() {
423 assert_eq!(
424 YUVAPixmaps::recommended_rgba_color_type(super::DataType::Float16),
425 ColorType::RGBAF16
426 );
427 }
428}