libcamera/
transform.rs

1use libcamera_sys::*;
2
3use crate::camera::Orientation;
4
5/// 2D plane transform matching libcamera::Transform.
6#[derive(Clone, Copy, Debug)]
7pub struct Transform(pub libcamera_transform_t);
8
9impl Transform {
10    pub fn hflip() -> Self {
11        Transform(unsafe { libcamera_transform_hflip() })
12    }
13    pub fn vflip() -> Self {
14        Transform(unsafe { libcamera_transform_vflip() })
15    }
16    pub fn transpose() -> Self {
17        Transform(unsafe { libcamera_transform_transpose() })
18    }
19}
20
21impl Transform {
22    pub fn identity() -> Self {
23        Transform(unsafe { libcamera_transform_identity() })
24    }
25
26    /// Construct from rotation degrees, optionally applying hflip.
27    pub fn from_rotation(angle: i32, hflip: bool) -> Option<Self> {
28        let mut success = false;
29        let t = unsafe { libcamera_transform_from_rotation(angle, hflip, &mut success) };
30        if success {
31            Some(Transform(t))
32        } else {
33            None
34        }
35    }
36
37    pub fn inverse(self) -> Self {
38        Transform(unsafe { libcamera_transform_inverse(self.0) })
39    }
40
41    pub fn combine(self, other: Transform) -> Self {
42        Transform(unsafe { libcamera_transform_combine(self.0, other.0) })
43    }
44
45    pub fn to_string_repr(self) -> String {
46        unsafe {
47            let ptr = libcamera_transform_to_string(self.0);
48            if ptr.is_null() {
49                return String::new();
50            }
51            let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned();
52            libc::free(ptr.cast());
53            s
54        }
55    }
56}
57
58impl std::fmt::Display for Transform {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        f.write_str(&self.to_string_repr())
61    }
62}
63
64impl Transform {
65    /// Compute the transform between two orientations (equivalent to libcamera Orientation division).
66    pub fn between_orientations(from: Orientation, to: Orientation) -> Self {
67        Transform(unsafe { libcamera_transform_between_orientations(from.into(), to.into()) })
68    }
69}
70
71pub fn apply_transform_to_orientation(orientation: Orientation, transform: Transform) -> Orientation {
72    unsafe {
73        libcamera_transform_apply_orientation(orientation.into(), transform.0)
74            .try_into()
75            .unwrap()
76    }
77}
78
79/// Convert a rotation angle to an EXIF orientation using libcamera's helper.
80pub fn orientation_from_rotation(angle: i32) -> Option<Orientation> {
81    let mut success = false;
82    let ori = unsafe { libcamera_orientation_from_rotation(angle, &mut success) };
83    if success {
84        ori.try_into().ok()
85    } else {
86        None
87    }
88}
89
90impl core::ops::BitOr for Transform {
91    type Output = Transform;
92    fn bitor(self, rhs: Self) -> Self::Output {
93        Transform(unsafe { libcamera_transform_or(self.0, rhs.0) })
94    }
95}
96
97impl core::ops::BitAnd for Transform {
98    type Output = Transform;
99    fn bitand(self, rhs: Self) -> Self::Output {
100        Transform(unsafe { libcamera_transform_and(self.0, rhs.0) })
101    }
102}
103
104impl core::ops::BitXor for Transform {
105    type Output = Transform;
106    fn bitxor(self, rhs: Self) -> Self::Output {
107        Transform(unsafe { libcamera_transform_xor(self.0, rhs.0) })
108    }
109}
110
111impl core::ops::Not for Transform {
112    type Output = Transform;
113    fn not(self) -> Self::Output {
114        Transform(unsafe { libcamera_transform_not(self.0) })
115    }
116}