crabshell_render/
capture.rs1use std::rc::Rc;
6
7use crabshell_ui::{CaptureFrame, Fit};
8use tiny_skia::PixmapRef;
9
10use crate::PixelFormat;
11use crate::icons::halve;
12use crate::images;
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
18pub struct Turn {
19 pub quarters: u8,
21 pub flipped: bool,
23}
24
25impl Turn {
26 fn sideways(self) -> bool {
28 self.quarters % 2 == 1
29 }
30}
31
32pub fn capture_frame(
38 pixels: &[u8],
39 width: u32,
40 height: u32,
41 format: PixelFormat,
42 opaque: bool,
43 turn: Turn,
44 cover: (u32, u32),
45) -> Option<CaptureFrame> {
46 let source = PixmapRef::from_bytes(pixels, width, height)?;
47 let cover = if turn.sideways() {
49 (cover.1, cover.0)
50 } else {
51 cover
52 };
53 let (kept_width, kept_height) = frame_size((width, height), cover);
54 let mut first = if kept_width * 2 <= width && kept_height * 2 <= height {
57 halve(source).ok()?
58 } else {
59 source.to_owned()
60 };
61 if opaque {
62 for pixel in first.data_mut().as_chunks_mut::<4>().0 {
63 pixel[3] = 255;
64 }
65 }
66 let mut kept = if (first.width(), first.height()) == (kept_width, kept_height) {
69 first
70 } else {
71 images::scale(first.as_ref(), kept_width, kept_height, Fit::Fill).ok()?
72 };
73 if format == PixelFormat::Argb8888 {
74 for pixel in kept.data_mut().as_chunks_mut::<4>().0 {
75 pixel.swap(0, 2);
76 }
77 }
78 let (width, height, rgba) = upright(kept_width, kept_height, kept.take(), turn);
79 Some(CaptureFrame {
80 width,
81 height,
82 rgba: Rc::from(rgba),
83 })
84}
85
86fn upright(width: u32, height: u32, rgba: Vec<u8>, turn: Turn) -> (u32, u32, Vec<u8>) {
88 if turn == Turn::default() {
89 return (width, height, rgba);
90 }
91 let (w, h) = (width as usize, height as usize);
92 let (out_w, out_h) = if turn.sideways() { (h, w) } else { (w, h) };
93 let mut out = vec![0; rgba.len()];
94 for y in 0..out_h {
95 for x in 0..out_w {
96 let (bx, by) = match turn.quarters % 4 {
100 0 => (x, y),
101 1 => (y, h - 1 - x),
102 2 => (w - 1 - x, h - 1 - y),
103 _ => (w - 1 - y, x),
104 };
105 let bx = if turn.flipped { w - 1 - bx } else { bx };
106 let (from, to) = ((by * w + bx) * 4, (y * out_w + x) * 4);
107 out[to..to + 4].copy_from_slice(&rgba[from..from + 4]);
108 }
109 }
110 (out_w as u32, out_h as u32, out)
111}
112
113pub fn frame_size(source: (u32, u32), cover: (u32, u32)) -> (u32, u32) {
118 let across = f64::from(cover.0) / f64::from(source.0.max(1));
119 let down = f64::from(cover.1) / f64::from(source.1.max(1));
120 let factor = across.max(down).min(1.0);
121 let side = |length: u32| ((f64::from(length) * factor).round() as u32).max(1);
123 (side(source.0), side(source.1))
124}