yuvutils_rs/geometry.rs
1/*
2 * Copyright (c) Radzivon Bartoshyk, 1/2025. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::YuvError;
30use fast_transpose::{
31 rotate180_plane, rotate180_plane16, rotate180_plane16_with_alpha, rotate180_plane_with_alpha,
32 rotate180_rgb, rotate180_rgb16, rotate180_rgba, rotate180_rgba16, transpose_plane,
33 transpose_plane16, transpose_plane16_with_alpha, transpose_plane_with_alpha, transpose_rgb,
34 transpose_rgb16, transpose_rgba, transpose_rgba16, FlipMode, FlopMode, TransposeError,
35};
36
37/// Declares rotation mode, 90, 180, 270
38#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
39pub enum RotationMode {
40 Rotate90,
41 Rotate180,
42 Rotate270,
43}
44
45#[inline]
46pub(crate) fn map_ft_result(result: Result<(), TransposeError>) -> Result<(), YuvError> {
47 match result {
48 Ok(_) => Ok(()),
49 Err(err) => match err {
50 TransposeError::MismatchDimensions => Err(YuvError::ImageDimensionsNotMatch),
51 TransposeError::InvalidArraySize => Err(YuvError::ImagesSizesNotMatch),
52 },
53 }
54}
55
56/// Rotates RGBA 8 bit image.
57///
58/// This rotates any 4 channels image, channel order does not matter.
59///
60/// # Arguments
61///
62/// * `src`: Source image
63/// * `src_stride`: Source image stride
64/// * `dst`: Destination image
65/// * `dst_stride`: Destination image stride
66/// * `width`: Image width
67/// * `height`: Image Height
68/// * `mode`: Refer to [RotationMode] for mode info
69///
70/// returns: Result<(), [YuvError]>
71///
72pub fn rotate_rgba(
73 src: &[u8],
74 src_stride: usize,
75 dst: &mut [u8],
76 dst_stride: usize,
77 width: usize,
78 height: usize,
79 mode: RotationMode,
80) -> Result<(), YuvError> {
81 let rs = match mode {
82 RotationMode::Rotate90 => transpose_rgba(
83 src,
84 src_stride,
85 dst,
86 dst_stride,
87 width,
88 height,
89 FlipMode::NoFlip,
90 FlopMode::NoFlop,
91 ),
92 RotationMode::Rotate180 => rotate180_rgba(src, src_stride, dst, dst_stride, width, height),
93 RotationMode::Rotate270 => transpose_rgba(
94 src,
95 src_stride,
96 dst,
97 dst_stride,
98 width,
99 height,
100 FlipMode::Flip,
101 FlopMode::Flop,
102 ),
103 };
104 map_ft_result(rs)
105}
106
107/// Rotates RGB 8 bit image.
108///
109/// This rotates any 3 channels image, channel order does not matter.
110///
111/// # Arguments
112///
113/// * `src`: Source image
114/// * `src_stride`: Source image stride
115/// * `dst`: Destination image
116/// * `dst_stride`: Destination image stride
117/// * `width`: Image width
118/// * `height`: Image Height
119/// * `mode`: Refer to [RotationMode] for mode info
120///
121/// returns: Result<(), [YuvError]>
122///
123pub fn rotate_rgb(
124 src: &[u8],
125 src_stride: usize,
126 dst: &mut [u8],
127 dst_stride: usize,
128 width: usize,
129 height: usize,
130 mode: RotationMode,
131) -> Result<(), YuvError> {
132 let rs = match mode {
133 RotationMode::Rotate90 => transpose_rgb(
134 src,
135 src_stride,
136 dst,
137 dst_stride,
138 width,
139 height,
140 FlipMode::NoFlip,
141 FlopMode::NoFlop,
142 ),
143 RotationMode::Rotate180 => rotate180_rgb(src, src_stride, dst, dst_stride, width, height),
144 RotationMode::Rotate270 => transpose_rgb(
145 src,
146 src_stride,
147 dst,
148 dst_stride,
149 width,
150 height,
151 FlipMode::Flip,
152 FlopMode::Flop,
153 ),
154 };
155 map_ft_result(rs)
156}
157
158/// Rotates CbCr 8 bit image.
159///
160/// This rotates any 2 channels image, channel order does not matter.
161///
162/// # Arguments
163///
164/// * `src`: Source image
165/// * `src_stride`: Source image stride
166/// * `dst`: Destination image
167/// * `dst_stride`: Destination image stride
168/// * `width`: Image width
169/// * `height`: Image Height
170/// * `mode`: Refer to [RotationMode] for mode info
171///
172/// returns: Result<(), [YuvError]>
173///
174pub fn rotate_cbcr(
175 src: &[u8],
176 src_stride: usize,
177 dst: &mut [u8],
178 dst_stride: usize,
179 width: usize,
180 height: usize,
181 mode: RotationMode,
182) -> Result<(), YuvError> {
183 let rs = match mode {
184 RotationMode::Rotate90 => transpose_plane_with_alpha(
185 src,
186 src_stride,
187 dst,
188 dst_stride,
189 width,
190 height,
191 FlipMode::NoFlip,
192 FlopMode::NoFlop,
193 ),
194 RotationMode::Rotate180 => {
195 rotate180_plane_with_alpha(src, src_stride, dst, dst_stride, width, height)
196 }
197 RotationMode::Rotate270 => transpose_plane_with_alpha(
198 src,
199 src_stride,
200 dst,
201 dst_stride,
202 width,
203 height,
204 FlipMode::Flip,
205 FlopMode::Flop,
206 ),
207 };
208 map_ft_result(rs)
209}
210
211/// Rotates Planar 8 bit image.
212///
213/// This rotates planar image.
214///
215/// # Arguments
216///
217/// * `src`: Source image
218/// * `src_stride`: Source image stride
219/// * `dst`: Destination image
220/// * `dst_stride`: Destination image stride
221/// * `width`: Image width
222/// * `height`: Image Height
223/// * `mode`: Refer to [RotationMode] for mode info
224///
225/// returns: Result<(), [YuvError]>
226///
227pub fn rotate_plane(
228 src: &[u8],
229 src_stride: usize,
230 dst: &mut [u8],
231 dst_stride: usize,
232 width: usize,
233 height: usize,
234 mode: RotationMode,
235) -> Result<(), YuvError> {
236 let rs = match mode {
237 RotationMode::Rotate90 => transpose_plane(
238 src,
239 src_stride,
240 dst,
241 dst_stride,
242 width,
243 height,
244 FlipMode::NoFlip,
245 FlopMode::NoFlop,
246 ),
247 RotationMode::Rotate180 => rotate180_plane(src, src_stride, dst, dst_stride, width, height),
248 RotationMode::Rotate270 => transpose_plane(
249 src,
250 src_stride,
251 dst,
252 dst_stride,
253 width,
254 height,
255 FlipMode::Flip,
256 FlopMode::Flop,
257 ),
258 };
259 map_ft_result(rs)
260}
261
262/// Rotates RGBA 8+ bit image.
263///
264/// This rotates any 4 channels image, channel order does not matter.
265///
266/// # Arguments
267///
268/// * `src`: Source image
269/// * `src_stride`: Source image stride
270/// * `dst`: Destination image
271/// * `dst_stride`: Destination image stride
272/// * `width`: Image width
273/// * `height`: Image Height
274/// * `mode`: Refer to [RotationMode] for mode info
275///
276/// returns: Result<(), [YuvError]>
277///
278pub fn rotate_rgba16(
279 src: &[u16],
280 src_stride: usize,
281 dst: &mut [u16],
282 dst_stride: usize,
283 width: usize,
284 height: usize,
285 mode: RotationMode,
286) -> Result<(), YuvError> {
287 let rs = match mode {
288 RotationMode::Rotate90 => transpose_rgba16(
289 src,
290 src_stride,
291 dst,
292 dst_stride,
293 width,
294 height,
295 FlipMode::NoFlip,
296 FlopMode::NoFlop,
297 ),
298 RotationMode::Rotate180 => {
299 rotate180_rgba16(src, src_stride, dst, dst_stride, width, height)
300 }
301 RotationMode::Rotate270 => transpose_rgba16(
302 src,
303 src_stride,
304 dst,
305 dst_stride,
306 width,
307 height,
308 FlipMode::Flip,
309 FlopMode::Flop,
310 ),
311 };
312 map_ft_result(rs)
313}
314
315/// Rotates RGB 8+ bit image.
316///
317/// This rotates any 3 channels image, channel order does not matter.
318///
319/// # Arguments
320///
321/// * `src`: Source image
322/// * `src_stride`: Source image stride
323/// * `dst`: Destination image
324/// * `dst_stride`: Destination image stride
325/// * `width`: Image width
326/// * `height`: Image Height
327/// * `mode`: Refer to [RotationMode] for mode info
328///
329/// returns: Result<(), [YuvError]>
330///
331pub fn rotate_rgb16(
332 src: &[u16],
333 src_stride: usize,
334 dst: &mut [u16],
335 dst_stride: usize,
336 width: usize,
337 height: usize,
338 mode: RotationMode,
339) -> Result<(), YuvError> {
340 let rs = match mode {
341 RotationMode::Rotate90 => transpose_rgb16(
342 src,
343 src_stride,
344 dst,
345 dst_stride,
346 width,
347 height,
348 FlipMode::NoFlip,
349 FlopMode::NoFlop,
350 ),
351 RotationMode::Rotate180 => rotate180_rgb16(src, src_stride, dst, dst_stride, width, height),
352 RotationMode::Rotate270 => transpose_rgb16(
353 src,
354 src_stride,
355 dst,
356 dst_stride,
357 width,
358 height,
359 FlipMode::Flip,
360 FlopMode::Flop,
361 ),
362 };
363 map_ft_result(rs)
364}
365
366/// Rotates CbCr 8+ bit image.
367///
368/// This rotates any 2 channels image, channel order does not matter.
369///
370/// # Arguments
371///
372/// * `src`: Source image
373/// * `src_stride`: Source image stride
374/// * `dst`: Destination image
375/// * `dst_stride`: Destination image stride
376/// * `width`: Image width
377/// * `height`: Image Height
378/// * `mode`: Refer to [RotationMode] for mode info
379///
380/// returns: Result<(), [YuvError]>
381///
382pub fn rotate_cbcr16(
383 src: &[u16],
384 src_stride: usize,
385 dst: &mut [u16],
386 dst_stride: usize,
387 width: usize,
388 height: usize,
389 mode: RotationMode,
390) -> Result<(), YuvError> {
391 let rs = match mode {
392 RotationMode::Rotate90 => transpose_plane16_with_alpha(
393 src,
394 src_stride,
395 dst,
396 dst_stride,
397 width,
398 height,
399 FlipMode::NoFlip,
400 FlopMode::NoFlop,
401 ),
402 RotationMode::Rotate180 => {
403 rotate180_plane16_with_alpha(src, src_stride, dst, dst_stride, width, height)
404 }
405 RotationMode::Rotate270 => transpose_plane16_with_alpha(
406 src,
407 src_stride,
408 dst,
409 dst_stride,
410 width,
411 height,
412 FlipMode::Flip,
413 FlopMode::Flop,
414 ),
415 };
416 map_ft_result(rs)
417}
418
419/// Rotates Planar 8+ bit image.
420///
421/// This rotates planar image.
422///
423/// # Arguments
424///
425/// * `src`: Source image
426/// * `src_stride`: Source image stride
427/// * `dst`: Destination image
428/// * `dst_stride`: Destination image stride
429/// * `width`: Image width
430/// * `height`: Image Height
431/// * `mode`: Refer to [RotationMode] for mode info
432///
433/// returns: Result<(), [YuvError]>
434///
435pub fn rotate_plane16(
436 src: &[u16],
437 src_stride: usize,
438 dst: &mut [u16],
439 dst_stride: usize,
440 width: usize,
441 height: usize,
442 mode: RotationMode,
443) -> Result<(), YuvError> {
444 let rs = match mode {
445 RotationMode::Rotate90 => transpose_plane16(
446 src,
447 src_stride,
448 dst,
449 dst_stride,
450 width,
451 height,
452 FlipMode::NoFlip,
453 FlopMode::NoFlop,
454 ),
455 RotationMode::Rotate180 => {
456 rotate180_plane16(src, src_stride, dst, dst_stride, width, height)
457 }
458 RotationMode::Rotate270 => transpose_plane16(
459 src,
460 src_stride,
461 dst,
462 dst_stride,
463 width,
464 height,
465 FlipMode::Flip,
466 FlopMode::Flop,
467 ),
468 };
469 map_ft_result(rs)
470}