1use alloc::vec::Vec;
16
17use super::consts::*;
18use super::Ui;
19use gfx::{Surface, FMT_ARGB, FMT_PARGB, FMT_XRGB};
20
21const V5_SIZE: usize = 124;
22const HDR_SIZE: usize = 14 + V5_SIZE;
23const PNG_CLIP_LEVEL: u32 = 1;
24
25pub fn clipimg_record(png: Option<&[u8]>, bmp: Option<&[u8]>) -> Vec<u8> {
27 let mut r = Vec::new();
28 for part in [png, bmp] {
29 let p = part.unwrap_or(&[]);
30 r.extend_from_slice(&(p.len() as u64).to_le_bytes());
31 r.extend_from_slice(p);
32 }
33 r
34}
35
36pub fn clipimg_parse(r: &[u8]) -> Option<(Option<&[u8]>, Option<&[u8]>)> {
38 let mut parts = [None, None];
39 let mut o = 0usize;
40 for p in parts.iter_mut() {
41 let n = u64::from_le_bytes(r.get(o..o + 8)?.try_into().ok()?) as usize;
42 o += 8;
43 let d = r.get(o..o.checked_add(n)?)?;
44 o += n;
45 *p = if n == 0 { None } else { Some(d) };
46 }
47 Some((parts[0], parts[1]))
48}
49
50pub fn clip_bmp_from_sf(sf: &Surface) -> Option<Vec<u8>> {
53 let (w, h) = (sf.w as u32, sf.h as u32);
54 if w.wrapping_sub(1) >= 65535 || h.wrapping_sub(1) >= 65535 {
55 return None;
56 }
57 if sf.fmt != FMT_XRGB && sf.fmt != FMT_PARGB && sf.fmt != FMT_ARGB {
58 return None;
59 }
60 let row = w as usize * 4;
61 let size = row * h as usize + HDR_SIZE;
62 if size > u32::MAX as usize {
63 return None;
64 }
65 let mut b = Vec::new();
66 b.try_reserve_exact(size).ok()?;
67 b.resize(size, 0);
68 let put32 = |b: &mut [u8], o: usize, v: u32| b[o..o + 4].copy_from_slice(&v.to_le_bytes());
69 b[0] = b'B';
70 b[1] = b'M';
71 put32(&mut b, 2, size as u32);
72 put32(&mut b, 10, HDR_SIZE as u32);
73 put32(&mut b, 14, V5_SIZE as u32);
74 put32(&mut b, 18, w);
75 put32(&mut b, 22, h); b[26] = 1;
77 b[28] = 32;
78 put32(&mut b, 30, 3); put32(&mut b, 34, (size - HDR_SIZE) as u32);
80 put32(&mut b, 38, 2835);
81 put32(&mut b, 42, 2835);
82 put32(&mut b, 54, 0x00FF_0000);
83 put32(&mut b, 58, 0x0000_FF00);
84 put32(&mut b, 62, 0x0000_00FF);
85 put32(&mut b, 66, 0xFF00_0000);
86 put32(&mut b, 70, 0x7352_4742); put32(&mut b, 122, 4); for y in 0..h as usize {
90 let d = HDR_SIZE + (h as usize - y - 1) * row;
91 let s = y * sf.stride as usize;
92 let (dst, src) = (&mut b[d..d + row], &sf.px[s..s + row]);
93 if sf.fmt == FMT_PARGB {
94 gfx::straight::unpremul_row(dst, src);
95 } else {
96 dst.copy_from_slice(src);
97 if sf.fmt == FMT_XRGB {
98 for x in 0..w as usize {
99 dst[x * 4 + 3] = 255; }
101 }
102 }
103 }
104 Some(b)
105}
106
107impl Ui {
108 pub fn clip_set_image(&mut self, sf: &Surface) -> i32 {
110 let png = img_png::enc::encode_classic(sf, PNG_CLIP_LEVEL);
111 let bmp = clip_bmp_from_sf(sf);
112 let Some(png) = png else { return -1 }; let rec = clipimg_record(Some(&png), bmp.as_deref());
114 self.clip_set(CLIP_IMAGE, &rec)
115 }
116
117 pub fn clip_get_image(&mut self) -> Result<Surface, i32> {
120 let Some(data) = self.clip_get(CLIP_IMAGE) else { return Err(-1) };
121 let dec = img_core::ImgDec { flags: img_core::IMGD_STRAIGHT, frame: 0, hint: 0, maxpx: 0, maxmem: 0, cancel: None };
122 img_core::io::decode_ex(&data, Some(&dec), None)
123 }
124}