1use libcamera_sys::*;
2
3#[derive(Debug, Clone, Copy)]
5pub struct Point {
6 pub x: i32,
7 pub y: i32,
8}
9
10impl From<libcamera_point_t> for Point {
11 fn from(p: libcamera_point_t) -> Self {
12 Self { x: p.x, y: p.y }
13 }
14}
15
16#[derive(Debug, Clone, Copy)]
18pub struct Size {
19 pub width: u32,
20 pub height: u32,
21}
22
23impl Size {
24 pub const fn new(width: u32, height: u32) -> Self {
25 Self { width, height }
26 }
27
28 pub fn align_down_to(self, h_alignment: u32, v_alignment: u32) -> Self {
29 if h_alignment == 0 || v_alignment == 0 {
30 return self;
31 }
32 Self {
33 width: self.width / h_alignment * h_alignment,
34 height: self.height / v_alignment * v_alignment,
35 }
36 }
37
38 pub fn align_up_to(self, h_alignment: u32, v_alignment: u32) -> Self {
39 if h_alignment == 0 || v_alignment == 0 {
40 return self;
41 }
42 Self {
43 width: self.width.div_ceil(h_alignment) * h_alignment,
44 height: self.height.div_ceil(v_alignment) * v_alignment,
45 }
46 }
47
48 pub fn bound_to(self, bound: Size) -> Self {
49 Self {
50 width: self.width.min(bound.width),
51 height: self.height.min(bound.height),
52 }
53 }
54
55 pub fn expand_to(self, expand: Size) -> Self {
56 Self {
57 width: self.width.max(expand.width),
58 height: self.height.max(expand.height),
59 }
60 }
61
62 pub fn grow_by(self, margins: Size) -> Self {
63 Self {
64 width: self.width.saturating_add(margins.width),
65 height: self.height.saturating_add(margins.height),
66 }
67 }
68
69 pub fn shrink_by(self, margins: Size) -> Self {
70 Self {
71 width: self.width.saturating_sub(margins.width),
72 height: self.height.saturating_sub(margins.height),
73 }
74 }
75
76 pub fn bounded_to_aspect_ratio(self, ratio: Size) -> Self {
78 if ratio.width == 0 || ratio.height == 0 {
79 return self;
80 }
81
82 let ratio1 = self.width as u64 * ratio.height as u64;
83 let ratio2 = ratio.width as u64 * self.height as u64;
84
85 if ratio1 > ratio2 {
86 Self {
87 width: (ratio2 / ratio.height as u64) as u32,
88 height: self.height,
89 }
90 } else {
91 Self {
92 width: self.width,
93 height: (ratio1 / ratio.width as u64) as u32,
94 }
95 }
96 }
97
98 pub fn expanded_to_aspect_ratio(self, ratio: Size) -> Self {
100 if ratio.width == 0 || ratio.height == 0 {
101 return self;
102 }
103
104 let ratio1 = self.width as u64 * ratio.height as u64;
105 let ratio2 = ratio.width as u64 * self.height as u64;
106
107 if ratio1 < ratio2 {
108 Self {
109 width: (ratio2 / ratio.height as u64) as u32,
110 height: self.height,
111 }
112 } else {
113 Self {
114 width: self.width,
115 height: (ratio1 / ratio.width as u64) as u32,
116 }
117 }
118 }
119
120 pub fn centered_to(self, center: Point) -> Rectangle {
122 let x = center.x - (self.width as i32 / 2);
123 let y = center.y - (self.height as i32 / 2);
124 Rectangle {
125 x,
126 y,
127 width: self.width,
128 height: self.height,
129 }
130 }
131}
132
133impl From<libcamera_size_t> for Size {
134 fn from(s: libcamera_size_t) -> Self {
135 Self {
136 width: s.width,
137 height: s.height,
138 }
139 }
140}
141
142impl From<Size> for libcamera_size_t {
143 fn from(s: Size) -> Self {
144 Self {
145 width: s.width,
146 height: s.height,
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy)]
153pub struct SizeRange {
154 pub min: Size,
155 pub max: Size,
156 pub h_step: u32,
157 pub v_step: u32,
158}
159
160impl SizeRange {
161 pub fn contains(&self, size: Size) -> bool {
162 if size.width < self.min.width
163 || size.width > self.max.width
164 || size.height < self.min.height
165 || size.height > self.max.height
166 {
167 return false;
168 }
169
170 if self.h_step != 0 {
171 let delta_w = size.width - self.min.width;
172 if !delta_w.is_multiple_of(self.h_step) {
173 return false;
174 }
175 }
176 if self.v_step != 0 {
177 let delta_h = size.height - self.min.height;
178 if !delta_h.is_multiple_of(self.v_step) {
179 return false;
180 }
181 }
182
183 true
184 }
185}
186
187impl From<libcamera_size_range_t> for SizeRange {
188 fn from(r: libcamera_size_range_t) -> Self {
189 Self {
190 min: r.min.into(),
191 max: r.max.into(),
192 h_step: r.hStep,
193 v_step: r.vStep,
194 }
195 }
196}
197
198impl From<SizeRange> for libcamera_size_range_t {
199 fn from(r: SizeRange) -> Self {
200 Self {
201 min: r.min.into(),
202 max: r.max.into(),
203 hStep: r.h_step,
204 vStep: r.v_step,
205 }
206 }
207}
208
209#[derive(Debug, Clone, Copy)]
211pub struct Rectangle {
212 pub x: i32,
213 pub y: i32,
214 pub width: u32,
215 pub height: u32,
216}
217
218impl Rectangle {
219 pub fn size(&self) -> Size {
220 Size {
221 width: self.width,
222 height: self.height,
223 }
224 }
225
226 pub fn center(&self) -> Point {
228 Point {
229 x: self.x.saturating_add((self.width / 2) as i32),
230 y: self.y.saturating_add((self.height / 2) as i32),
231 }
232 }
233
234 pub fn top_left(&self) -> Point {
236 Point { x: self.x, y: self.y }
237 }
238
239 pub fn bounded_to(self, bound: Rectangle) -> Rectangle {
241 let top_left_x = i64::from(self.x).max(i64::from(bound.x));
242 let top_left_y = i64::from(self.y).max(i64::from(bound.y));
243 let bottom_right_x =
244 (i64::from(self.x) + i64::from(self.width)).min(i64::from(bound.x) + i64::from(bound.width));
245 let bottom_right_y =
246 (i64::from(self.y) + i64::from(self.height)).min(i64::from(bound.y) + i64::from(bound.height));
247
248 let new_width = if bottom_right_x > top_left_x {
249 (bottom_right_x - top_left_x) as u32
250 } else {
251 0
252 };
253 let new_height = if bottom_right_y > top_left_y {
254 (bottom_right_y - top_left_y) as u32
255 } else {
256 0
257 };
258
259 Rectangle {
260 x: top_left_x as i32,
261 y: top_left_y as i32,
262 width: new_width,
263 height: new_height,
264 }
265 }
266
267 pub fn enclosed_in(self, boundary: Rectangle) -> Rectangle {
269 let mut result = self.bounded_to(Rectangle {
270 x: self.x,
271 y: self.y,
272 width: boundary.width,
273 height: boundary.height,
274 });
275
276 let clamp = |val: i64, min: i64, max: i64| -> i64 {
277 if val < min {
278 min
279 } else if val > max {
280 max
281 } else {
282 val
283 }
284 };
285
286 let max_x = i64::from(boundary.x) + i64::from(boundary.width) - i64::from(result.width);
287 let max_y = i64::from(boundary.y) + i64::from(boundary.height) - i64::from(result.height);
288
289 result.x = clamp(i64::from(result.x), i64::from(boundary.x), max_x) as i32;
290 result.y = clamp(i64::from(result.y), i64::from(boundary.y), max_y) as i32;
291 result
292 }
293
294 pub fn translated_by(self, delta: Point) -> Rectangle {
296 Rectangle {
297 x: self.x.saturating_add(delta.x),
298 y: self.y.saturating_add(delta.y),
299 width: self.width,
300 height: self.height,
301 }
302 }
303
304 pub fn scaled_by(self, numerator: Size, denominator: Size) -> Rectangle {
306 if denominator.width == 0 || denominator.height == 0 {
307 return self;
308 }
309 Rectangle {
310 x: (i64::from(self.x) * i64::from(numerator.width) / i64::from(denominator.width)) as i32,
311 y: (i64::from(self.y) * i64::from(numerator.height) / i64::from(denominator.height)) as i32,
312 width: (u64::from(self.width) * u64::from(numerator.width) / u64::from(denominator.width)) as u32,
313 height: (u64::from(self.height) * u64::from(numerator.height) / u64::from(denominator.height)) as u32,
314 }
315 }
316}
317
318impl core::ops::Mul<f32> for Size {
319 type Output = Size;
320
321 fn mul(self, rhs: f32) -> Self::Output {
322 Size {
323 width: (self.width as f32 * rhs) as u32,
324 height: (self.height as f32 * rhs) as u32,
325 }
326 }
327}
328
329impl core::ops::Div<f32> for Size {
330 type Output = Size;
331
332 fn div(self, rhs: f32) -> Self::Output {
333 Size {
334 width: (self.width as f32 / rhs) as u32,
335 height: (self.height as f32 / rhs) as u32,
336 }
337 }
338}
339
340impl core::ops::MulAssign<f32> for Size {
341 fn mul_assign(&mut self, rhs: f32) {
342 *self = *self * rhs;
343 }
344}
345
346impl core::ops::DivAssign<f32> for Size {
347 fn div_assign(&mut self, rhs: f32) {
348 *self = *self / rhs;
349 }
350}
351
352impl From<libcamera_rectangle_t> for Rectangle {
353 fn from(r: libcamera_rectangle_t) -> Self {
354 Self {
355 x: r.x,
356 y: r.y,
357 width: r.width,
358 height: r.height,
359 }
360 }
361}
362
363impl From<Rectangle> for libcamera_rectangle_t {
364 fn from(r: Rectangle) -> Self {
365 Self {
366 x: r.x,
367 y: r.y,
368 width: r.width,
369 height: r.height,
370 }
371 }
372}
373
374impl Size {
375 pub fn transposed(self) -> Self {
377 Size {
378 width: self.height,
379 height: self.width,
380 }
381 }
382}