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}