devpage_design/bands/
mod.rs1use std::io::Write;
7
8use crate::display::List;
9use crate::tiles::TILE;
10
11pub const BAND_BYTES: usize = 16 << 20;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum Piece {
21 Tile { col: u32, row: u32 },
22 Strip { col: u32, y: u32, rows: u32 },
23}
24
25pub fn rows_per_band(width: u32) -> u32 {
29 let padded = width.max(1).div_ceil(TILE) as usize * TILE as usize * 4;
30 (BAND_BYTES / padded).clamp(1, TILE as usize) as u32
31}
32
33pub fn png(list: &List, out: impl Write) -> Result<(), png::EncodingError> {
35 let (w, h) = (list.area.width as u32, list.area.height as u32);
36 bands(w, h, out, |piece| {
37 Ok::<_, std::convert::Infallible>(match piece {
38 Piece::Tile { col, row } => crate::cpu::tile(list, 1.0, col, row),
39 Piece::Strip { col, y, rows } => crate::cpu::strip(list, col, y, rows),
40 })
41 })
42 .map_err(|e| match e {
43 Band::Encoding(e) => e,
44 })
45}
46
47#[derive(Debug)]
50pub enum Band<E> {
51 Encoding(png::EncodingError),
52 Tile(E),
53}
54
55impl<E: std::fmt::Display> std::fmt::Display for Band<E> {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 Band::Encoding(e) => write!(f, "{e}"),
59 Band::Tile(e) => write!(f, "{e}"),
60 }
61 }
62}
63
64pub fn bands<P: AsRef<[u8]>, E>(
69 width: u32,
70 height: u32,
71 out: impl Write,
72 mut piece: impl FnMut(Piece) -> Result<P, E>,
73) -> Result<(), Band<E>> {
74 let (w, h) = (width.max(1), height.max(1));
75 let mut encoder = png::Encoder::new(out, w, h);
76 encoder.set_color(png::ColorType::Rgba);
77 encoder.set_depth(png::BitDepth::Eight);
78 let mut header = encoder.write_header().map_err(Band::Encoding)?;
79 let mut writer = header.stream_writer().map_err(Band::Encoding)?;
80 let cols = w.div_ceil(TILE);
81 let per = rows_per_band(w);
82 let mut y = 0;
83 while y < h {
84 let rows = per.min(h - y);
85 let band = (0..cols)
86 .map(|col| {
87 piece(if per == TILE {
88 Piece::Tile { col, row: y / TILE }
89 } else {
90 Piece::Strip { col, y, rows }
91 })
92 })
93 .collect::<Result<Vec<P>, E>>()
94 .map_err(Band::Tile)?;
95 for r in 0..rows {
96 for (col, p) in band.iter().enumerate() {
97 let across = (w - col as u32 * TILE).min(TILE) as usize;
98 let start = r as usize * TILE as usize * 4;
99 writer
100 .write_all(&p.as_ref()[start..start + across * 4])
101 .map_err(|e| Band::Encoding(e.into()))?;
102 }
103 }
104 y += rows;
105 }
106 writer.finish().map_err(Band::Encoding)
107}
108
109#[cfg(test)]
110mod tests;