ironrdp_graphics/rdp6/bitmap_stream/
encoder.rs

1use ironrdp_core::{not_enough_bytes_err, EncodeError, WriteCursor};
2use ironrdp_pdu::bitmap::rdp6::{BitmapStreamHeader, ColorPlaneDefinition};
3
4use crate::rdp6::rle::{compress_8bpp_plane, RleEncodeError};
5
6#[derive(Debug)]
7pub enum BitmapEncodeError {
8    Rle(RleEncodeError),
9    Encode(EncodeError),
10}
11
12impl core::fmt::Display for BitmapEncodeError {
13    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
14        match self {
15            BitmapEncodeError::Rle(_error) => write!(f, "failed to rle compress"),
16            BitmapEncodeError::Encode(_error) => write!(f, "failed to encode pdu"),
17        }
18    }
19}
20
21impl core::error::Error for BitmapEncodeError {
22    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
23        match self {
24            BitmapEncodeError::Rle(error) => Some(error),
25            BitmapEncodeError::Encode(error) => Some(error),
26        }
27    }
28}
29
30pub trait ColorChannels {
31    const STRIDE: usize;
32    const R: usize;
33    const G: usize;
34    const B: usize;
35}
36
37pub trait AlphaChannel {
38    const A: usize;
39}
40
41pub trait PixelFormat {
42    const STRIDE: usize;
43
44    fn r(pixel: &[u8]) -> u8;
45    fn g(pixel: &[u8]) -> u8;
46    fn b(pixel: &[u8]) -> u8;
47}
48
49pub trait PixelAlpha: PixelFormat {
50    fn a(pixel: &[u8]) -> u8;
51}
52
53impl<T> PixelFormat for T
54where
55    T: ColorChannels,
56{
57    const STRIDE: usize = T::STRIDE;
58
59    fn r(pixel: &[u8]) -> u8 {
60        pixel[T::R]
61    }
62
63    fn g(pixel: &[u8]) -> u8 {
64        pixel[T::G]
65    }
66
67    fn b(pixel: &[u8]) -> u8 {
68        pixel[T::B]
69    }
70}
71
72impl<T> PixelAlpha for T
73where
74    T: ColorChannels + AlphaChannel,
75{
76    fn a(pixel: &[u8]) -> u8 {
77        pixel[T::A]
78    }
79}
80
81pub struct RgbChannels;
82
83impl ColorChannels for RgbChannels {
84    const STRIDE: usize = 3;
85    const R: usize = 0;
86    const G: usize = 1;
87    const B: usize = 2;
88}
89
90pub struct ARgbChannels;
91
92impl ColorChannels for ARgbChannels {
93    const STRIDE: usize = 4;
94    const R: usize = 1;
95    const G: usize = 2;
96    const B: usize = 3;
97}
98
99impl AlphaChannel for ARgbChannels {
100    const A: usize = 0;
101}
102
103pub struct RgbAChannels;
104
105impl ColorChannels for RgbAChannels {
106    const STRIDE: usize = 4;
107    const R: usize = 0;
108    const G: usize = 1;
109    const B: usize = 2;
110}
111
112impl AlphaChannel for RgbAChannels {
113    const A: usize = 3;
114}
115
116pub struct ABgrChannels;
117
118impl ColorChannels for ABgrChannels {
119    const STRIDE: usize = 4;
120    const R: usize = 3;
121    const G: usize = 2;
122    const B: usize = 1;
123}
124
125impl AlphaChannel for ABgrChannels {
126    const A: usize = 0;
127}
128
129pub struct BgrAChannels;
130
131impl ColorChannels for BgrAChannels {
132    const STRIDE: usize = 4;
133    const R: usize = 2;
134    const G: usize = 1;
135    const B: usize = 0;
136}
137
138impl AlphaChannel for BgrAChannels {
139    const A: usize = 3;
140}
141
142impl BitmapEncodeError {
143    fn rle(e: RleEncodeError) -> Self {
144        Self::Rle(e)
145    }
146}
147
148pub struct BitmapStreamEncoder {
149    width: usize,
150    height: usize,
151}
152
153impl BitmapStreamEncoder {
154    pub fn new(width: usize, height: usize) -> Self {
155        Self { width, height }
156    }
157
158    pub fn encode_channels_stream<R, G, B>(
159        &mut self,
160        (r, g, b): (R, G, B),
161        dst: &mut [u8],
162        rle: bool,
163    ) -> Result<usize, BitmapEncodeError>
164    where
165        R: Iterator<Item = u8>,
166        G: Iterator<Item = u8>,
167        B: Iterator<Item = u8>,
168    {
169        let mut cursor = WriteCursor::new(dst);
170
171        let header = BitmapStreamHeader {
172            enable_rle_compression: rle,
173            use_alpha: false,
174            color_plane_definition: ColorPlaneDefinition::Argb,
175        };
176
177        ironrdp_core::encode_cursor(&header, &mut cursor).map_err(BitmapEncodeError::Encode)?;
178
179        if rle {
180            compress_8bpp_plane(r, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::Rle)?;
181            compress_8bpp_plane(g, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::Rle)?;
182            compress_8bpp_plane(b, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::Rle)?;
183        } else {
184            let remaining = cursor.len();
185            let needed = self.width * self.height * 3 + 1;
186            if needed > remaining {
187                return Err(BitmapEncodeError::Encode(not_enough_bytes_err(
188                    "BitmapStreamData",
189                    remaining,
190                    needed,
191                )));
192            }
193
194            for byte in r.chain(g).chain(b) {
195                cursor.write_u8(byte);
196            }
197            cursor.write_u8(0u8);
198        }
199
200        Ok(cursor.pos())
201    }
202
203    pub fn encode_pixels_stream<'a, I, F>(
204        &mut self,
205        data: I,
206        dst: &mut [u8],
207        rle: bool,
208    ) -> Result<usize, BitmapEncodeError>
209    where
210        F: PixelFormat,
211        I: Iterator<Item = &'a [u8]> + Clone,
212    {
213        let r = data.clone().map(F::r);
214        let g = data.clone().map(F::g);
215        let b = data.map(F::b);
216
217        self.encode_channels_stream((r, g, b), dst, rle)
218    }
219
220    pub fn encode_bitmap<F>(&mut self, src: &[u8], dst: &mut [u8], rle: bool) -> Result<usize, BitmapEncodeError>
221    where
222        F: PixelFormat,
223    {
224        let r = src.chunks_exact(F::STRIDE).map(F::r);
225        let g = src.chunks_exact(F::STRIDE).map(F::g);
226        let b = src.chunks_exact(F::STRIDE).map(F::b);
227
228        self.encode_channels_stream((r, g, b), dst, rle)
229    }
230
231    pub fn encode_channels_stream_alpha<R, G, B, A>(
232        &mut self,
233        (r, g, b, a): (R, G, B, A),
234        dst: &mut [u8],
235        rle: bool,
236    ) -> Result<usize, BitmapEncodeError>
237    where
238        R: Iterator<Item = u8>,
239        G: Iterator<Item = u8>,
240        B: Iterator<Item = u8>,
241        A: Iterator<Item = u8>,
242    {
243        let mut cursor = WriteCursor::new(dst);
244
245        let header = BitmapStreamHeader {
246            enable_rle_compression: rle,
247            use_alpha: false,
248            color_plane_definition: ColorPlaneDefinition::Argb,
249        };
250
251        ironrdp_core::encode_cursor(&header, &mut cursor).map_err(BitmapEncodeError::Encode)?;
252
253        if rle {
254            compress_8bpp_plane(a, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::rle)?;
255            compress_8bpp_plane(r, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::rle)?;
256            compress_8bpp_plane(g, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::rle)?;
257            compress_8bpp_plane(b, &mut cursor, self.width, self.height).map_err(BitmapEncodeError::rle)?;
258        } else {
259            let remaining = cursor.len();
260            let needed = self.width * self.height * 4 + 1;
261            if needed > remaining {
262                return Err(BitmapEncodeError::Encode(not_enough_bytes_err(
263                    "BitmapStreamData",
264                    remaining,
265                    needed,
266                )));
267            }
268
269            for byte in a.chain(r).chain(g).chain(b) {
270                cursor.write_u8(byte);
271            }
272            cursor.write_u8(0u8);
273        }
274
275        Ok(cursor.pos())
276    }
277
278    pub fn encode_bitmap_alpha<F>(&mut self, src: &[u8], dst: &mut [u8], rle: bool) -> Result<usize, BitmapEncodeError>
279    where
280        F: PixelFormat + PixelAlpha,
281    {
282        let r = src.chunks_exact(F::STRIDE).map(F::r);
283        let g = src.chunks_exact(F::STRIDE).map(F::g);
284        let b = src.chunks_exact(F::STRIDE).map(F::b);
285        let a = src.chunks_exact(F::STRIDE).map(F::a);
286
287        self.encode_channels_stream_alpha((r, g, b, a), dst, rle)
288    }
289}