1use super::image_info;
2use crate::{prelude::*, EncodedOrigin, ISize, Matrix};
3use skia_bindings::{self as sb, SkYUVAInfo, SkYUVAInfo_Subsampling};
4use std::{fmt, ptr};
5
6pub type YUVAInfo = Handle<SkYUVAInfo>;
9unsafe_send_sync!(YUVAInfo);
10
11impl NativeDrop for SkYUVAInfo {
12 fn drop(&mut self) {
13 unsafe { sb::C_SkYUVAInfo_destruct(self) }
14 }
15}
16
17pub use sb::SkYUVAInfo_PlaneConfig as PlaneConfig;
29variant_name!(PlaneConfig::YUV);
30
31#[repr(i32)]
36#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
37pub enum Subsampling {
38 Unknown = SkYUVAInfo_Subsampling::kUnknown as _,
39 S444 = SkYUVAInfo_Subsampling::k444 as _,
40 S422 = SkYUVAInfo_Subsampling::k422 as _,
41 S420 = SkYUVAInfo_Subsampling::k420 as _,
42 S440 = SkYUVAInfo_Subsampling::k440 as _,
43 S411 = SkYUVAInfo_Subsampling::k411 as _,
44 S410 = SkYUVAInfo_Subsampling::k410 as _,
45}
46
47native_transmutable!(SkYUVAInfo_Subsampling, Subsampling, subsampling_layout);
48
49pub use sb::SkYUVAInfo_Siting as Siting;
53variant_name!(Siting::Centered);
54
55pub fn subsampling_factors(subsampling: Subsampling) -> (i32, i32) {
57 let mut factors: [i32; 2] = Default::default();
58 unsafe { sb::C_SkYUVAInfo_SubsamplingFactors(subsampling.into_native(), &mut factors[0]) };
59 #[allow(clippy::tuple_array_conversions)]
60 (factors[0], factors[1])
61}
62
63pub fn plane_subsampling_factors(
67 plane: PlaneConfig,
68 subsampling: Subsampling,
69 plane_index: usize,
70) -> (i32, i32) {
71 let mut factors: [i32; 2] = Default::default();
72 unsafe {
73 sb::C_SkYUVAInfo_PlaneSubsamplingFactors(
74 plane,
75 subsampling.into_native(),
76 plane_index.try_into().unwrap(),
77 &mut factors[0],
78 )
79 };
80 #[allow(clippy::tuple_array_conversions)]
81 (factors[0], factors[1])
82}
83
84pub fn plane_dimensions(
89 image_dimensions: impl Into<ISize>,
90 config: PlaneConfig,
91 subsampling: Subsampling,
92 origin: EncodedOrigin,
93) -> Vec<ISize> {
94 let mut plane_dimensions = [ISize::default(); YUVAInfo::MAX_PLANES];
95 let size: usize = unsafe {
96 SkYUVAInfo::PlaneDimensions(
97 image_dimensions.into().into_native(),
98 config,
99 subsampling.into_native(),
100 origin.into_native(),
101 plane_dimensions.native_mut().as_mut_ptr(),
102 )
103 }
104 .try_into()
105 .unwrap();
106
107 plane_dimensions[0..size].to_vec()
108}
109
110pub fn num_planes(config: PlaneConfig) -> usize {
112 unsafe { sb::C_SkYUVAInfo_NumPlanes(config) }
113 .try_into()
114 .unwrap()
115}
116
117pub fn num_channels_in_plane(config: PlaneConfig, i: usize) -> Option<usize> {
120 (i < num_planes(config)).if_true_then_some(|| {
121 unsafe { sb::C_SkYUVAInfo_NumChannelsInPlane(config, i.try_into().unwrap()) }
122 .try_into()
123 .unwrap()
124 })
125}
126
127pub fn has_alpha(config: PlaneConfig) -> bool {
129 unsafe { sb::SkYUVAInfo_HasAlpha(config) }
130}
131
132impl Default for YUVAInfo {
133 fn default() -> Self {
134 Self::construct(|yi| unsafe { sb::C_SkYUVAInfo_Construct(yi) })
135 }
136}
137
138impl NativePartialEq for YUVAInfo {
139 fn eq(&self, rhs: &Self) -> bool {
140 unsafe { sb::C_SkYUVAInfo_equals(self.native(), rhs.native()) }
141 }
142}
143
144impl fmt::Debug for YUVAInfo {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 f.debug_struct("YUVAInfo")
147 .field("dimensions", &self.dimensions())
148 .field("plane_config", &self.plane_config())
149 .field("subsampling", &self.subsampling())
150 .field("yuv_color_space", &self.yuv_color_space())
151 .field("origin", &self.origin())
152 .field("siting_xy", &self.siting_xy())
153 .finish()
154 }
155}
156
157impl YUVAInfo {
158 pub const MAX_PLANES: usize = sb::SkYUVAInfo_kMaxPlanes as _;
159
160 pub fn new(
163 dimensions: impl Into<ISize>,
164 config: PlaneConfig,
165 subsampling: Subsampling,
166 color_space: image_info::YUVColorSpace,
167 origin: impl Into<Option<EncodedOrigin>>,
168 siting_xy: impl Into<Option<(Siting, Siting)>>,
169 ) -> Option<Self> {
170 let origin = origin.into().unwrap_or(EncodedOrigin::TopLeft);
171 let (siting_x, siting_y) = siting_xy
172 .into()
173 .unwrap_or((Siting::Centered, Siting::Centered));
174
175 let n = unsafe {
176 SkYUVAInfo::new(
177 dimensions.into().into_native(),
178 config,
179 subsampling.into_native(),
180 color_space,
181 origin.into_native(),
182 siting_x,
183 siting_y,
184 )
185 };
186 Self::native_is_valid(&n).if_true_then_some(|| Self::from_native_c(n))
187 }
188
189 pub fn plane_config(&self) -> PlaneConfig {
190 self.native().fPlaneConfig
191 }
192
193 pub fn subsampling(&self) -> Subsampling {
194 Subsampling::from_native_c(self.native().fSubsampling)
195 }
196
197 pub fn plane_subsampling_factors(&self, plane_index: usize) -> (i32, i32) {
198 plane_subsampling_factors(self.plane_config(), self.subsampling(), plane_index)
199 }
200
201 pub fn dimensions(&self) -> ISize {
204 ISize::from_native_c(self.native().fDimensions)
205 }
206
207 pub fn width(&self) -> i32 {
208 self.dimensions().width
209 }
210
211 pub fn height(&self) -> i32 {
212 self.dimensions().height
213 }
214
215 pub fn yuv_color_space(&self) -> image_info::YUVColorSpace {
216 self.native().fYUVColorSpace
217 }
218
219 pub fn siting_xy(&self) -> (Siting, Siting) {
220 let n = self.native();
221 (n.fSitingX, n.fSitingY)
222 }
223
224 pub fn origin(&self) -> EncodedOrigin {
225 EncodedOrigin::from_native_c(self.native().fOrigin)
226 }
227
228 pub fn origin_matrix(&self) -> Matrix {
229 self.origin().to_matrix((self.width(), self.height()))
230 }
231
232 pub fn has_alpha(&self) -> bool {
233 has_alpha(self.plane_config())
234 }
235
236 pub fn plane_dimensions(&self) -> Vec<ISize> {
239 self::plane_dimensions(
240 self.dimensions(),
241 self.plane_config(),
242 self.subsampling(),
243 self.origin(),
244 )
245 }
246
247 pub fn compute_total_bytes(
251 &self,
252 row_bytes: &[usize; Self::MAX_PLANES],
253 plane_sizes: Option<&mut [usize; Self::MAX_PLANES]>,
254 ) -> usize {
255 unsafe {
256 self.native().computeTotalBytes(
257 row_bytes.as_ptr(),
258 plane_sizes
259 .map(|v| v.as_mut_ptr())
260 .unwrap_or(ptr::null_mut()),
261 )
262 }
263 }
264
265 pub fn num_planes(&self) -> usize {
266 num_planes(self.plane_config())
267 }
268
269 pub fn num_channels_in_plane(&self, i: usize) -> Option<usize> {
270 num_channels_in_plane(self.plane_config(), i)
271 }
272
273 pub fn with_subsampling(&self, subsampling: Subsampling) -> Option<Self> {
278 Self::try_construct(|info| unsafe {
279 sb::C_SkYUVAInfo_makeSubsampling(self.native(), subsampling.into_native(), info);
280 Self::native_is_valid(&*info)
281 })
282 }
283
284 pub fn with_dimensions(&self, dimensions: impl Into<ISize>) -> Option<Self> {
287 Self::try_construct(|info| unsafe {
288 sb::C_SkYUVAInfo_makeDimensions(self.native(), dimensions.into().native(), info);
289 Self::native_is_valid(&*info)
290 })
291 }
292
293 pub(crate) fn native_is_valid(info: &SkYUVAInfo) -> bool {
294 info.fPlaneConfig != PlaneConfig::Unknown
295 }
296}