ironrdp_graphics/
image_processing.rs

1use core::{cmp, fmt};
2use std::io;
3
4use byteorder::WriteBytesExt as _;
5use ironrdp_pdu::geometry::{InclusiveRectangle, Rectangle as _};
6
7const ALPHA_OPAQUE: u8 = 0xff;
8
9pub struct ImageRegionMut<'a> {
10    pub region: InclusiveRectangle,
11    pub step: u16,
12    pub pixel_format: PixelFormat,
13    pub data: &'a mut [u8],
14}
15
16impl fmt::Debug for ImageRegionMut<'_> {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.debug_struct("ImageRegionMut")
19            .field("region", &self.region)
20            .field("step", &self.step)
21            .field("pixel_format", &self.pixel_format)
22            .field("data_len", &self.data.len())
23            .finish()
24    }
25}
26
27pub struct ImageRegion<'a> {
28    pub region: InclusiveRectangle,
29    pub step: u16,
30    pub pixel_format: PixelFormat,
31    pub data: &'a [u8],
32}
33
34impl fmt::Debug for ImageRegion<'_> {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        f.debug_struct("ImageRegion")
37            .field("region", &self.region)
38            .field("step", &self.step)
39            .field("pixel_format", &self.pixel_format)
40            .field("data_len", &self.data.len())
41            .finish()
42    }
43}
44
45impl ImageRegion<'_> {
46    pub fn copy_to(&self, other: &mut ImageRegionMut<'_>) -> io::Result<()> {
47        let width = cmp::min(self.region.width(), other.region.width());
48        let height = cmp::min(self.region.height(), other.region.height());
49        let width = usize::from(width);
50        let height = usize::from(height);
51
52        let dst_point = Point {
53            x: usize::from(other.region.left),
54            y: usize::from(other.region.top),
55        };
56        let src_point = Point {
57            x: usize::from(self.region.left),
58            y: usize::from(self.region.top),
59        };
60
61        let src_byte = usize::from(self.pixel_format.bytes_per_pixel());
62        let dst_byte = usize::from(other.pixel_format.bytes_per_pixel());
63
64        let src_step = if self.step == 0 {
65            usize::from(self.region.width()) * src_byte
66        } else {
67            usize::from(self.step)
68        };
69        let dst_step = if other.step == 0 {
70            width * dst_byte
71        } else {
72            usize::from(other.step)
73        };
74
75        if self.pixel_format.eq_no_alpha(other.pixel_format) {
76            let width = width * dst_byte;
77            for y in 0..height {
78                let src_start = (y + src_point.y) * src_step + src_point.x * src_byte;
79                let dst_start = (y + dst_point.y) * dst_step + dst_point.x * dst_byte;
80                other.data[dst_start..dst_start + width].clone_from_slice(&self.data[src_start..src_start + width]);
81            }
82        } else {
83            for y in 0..height {
84                let src = &self.data[((y + src_point.y) * src_step)..];
85                let dst = &mut other.data[((y + dst_point.y) * dst_step)..];
86
87                for x in 0..width {
88                    let color = self.pixel_format.read_color(&src[((x + src_point.x) * src_byte)..])?;
89                    other
90                        .pixel_format
91                        .write_color(color, &mut dst[((x + dst_point.x) * dst_byte)..])?;
92                }
93            }
94        }
95
96        Ok(())
97    }
98}
99
100#[derive(Debug, Copy, Clone, PartialEq, Eq)]
101pub enum PixelFormat {
102    ARgb32 = 536_971_400,
103    XRgb32 = 536_938_632,
104    ABgr32 = 537_036_936,
105    XBgr32 = 537_004_168,
106    BgrA32 = 537_168_008,
107    BgrX32 = 537_135_240,
108    RgbA32 = 537_102_472,
109    RgbX32 = 537_069_704,
110}
111
112impl TryFrom<u32> for PixelFormat {
113    type Error = ();
114
115    fn try_from(value: u32) -> Result<Self, Self::Error> {
116        match value {
117            536_971_400 => Ok(PixelFormat::ARgb32),
118            536_938_632 => Ok(PixelFormat::XRgb32),
119            537_036_936 => Ok(PixelFormat::ABgr32),
120            537_004_168 => Ok(PixelFormat::XBgr32),
121            537_168_008 => Ok(PixelFormat::BgrA32),
122            537_135_240 => Ok(PixelFormat::BgrX32),
123            537_102_472 => Ok(PixelFormat::RgbA32),
124            537_069_704 => Ok(PixelFormat::RgbX32),
125            _ => Err(()),
126        }
127    }
128}
129
130impl PixelFormat {
131    fn as_u32(&self) -> u32 {
132        match self {
133            Self::ARgb32 => 536_971_400,
134            Self::XRgb32 => 536_938_632,
135            Self::ABgr32 => 537_036_936,
136            Self::XBgr32 => 537_004_168,
137            Self::BgrA32 => 537_168_008,
138            Self::BgrX32 => 537_135_240,
139            Self::RgbA32 => 537_102_472,
140            Self::RgbX32 => 537_069_704,
141        }
142    }
143
144    pub const fn bytes_per_pixel(self) -> u8 {
145        match self {
146            Self::ARgb32
147            | Self::XRgb32
148            | Self::ABgr32
149            | Self::XBgr32
150            | Self::BgrA32
151            | Self::BgrX32
152            | Self::RgbA32
153            | Self::RgbX32 => 4,
154        }
155    }
156
157    pub fn eq_no_alpha(self, other: Self) -> bool {
158        let mask = !(8 << 12);
159
160        (self.as_u32() & mask) == (other.as_u32() & mask)
161    }
162
163    pub fn read_color(self, buffer: &[u8]) -> io::Result<Rgba> {
164        match self {
165            Self::ARgb32
166            | Self::XRgb32
167            | Self::ABgr32
168            | Self::XBgr32
169            | Self::BgrA32
170            | Self::BgrX32
171            | Self::RgbA32
172            | Self::RgbX32 => {
173                if buffer.len() < 4 {
174                    Err(io::Error::new(
175                        io::ErrorKind::InvalidInput,
176                        "input buffer is not large enough (this is a bug)",
177                    ))
178                } else {
179                    let color = &buffer[..4];
180
181                    match self {
182                        Self::ARgb32 => Ok(Rgba {
183                            a: color[0],
184                            r: color[1],
185                            g: color[2],
186                            b: color[3],
187                        }),
188                        Self::XRgb32 => Ok(Rgba {
189                            a: ALPHA_OPAQUE,
190                            r: color[1],
191                            g: color[2],
192                            b: color[3],
193                        }),
194                        Self::ABgr32 => Ok(Rgba {
195                            a: color[0],
196                            b: color[1],
197                            g: color[2],
198                            r: color[3],
199                        }),
200                        Self::XBgr32 => Ok(Rgba {
201                            a: ALPHA_OPAQUE,
202                            b: color[1],
203                            g: color[2],
204                            r: color[3],
205                        }),
206                        Self::BgrA32 => Ok(Rgba {
207                            b: color[0],
208                            g: color[1],
209                            r: color[2],
210                            a: color[3],
211                        }),
212                        Self::BgrX32 => Ok(Rgba {
213                            b: color[0],
214                            g: color[1],
215                            r: color[2],
216                            a: ALPHA_OPAQUE,
217                        }),
218                        Self::RgbA32 => Ok(Rgba {
219                            r: color[0],
220                            g: color[1],
221                            b: color[2],
222                            a: color[3],
223                        }),
224                        Self::RgbX32 => Ok(Rgba {
225                            r: color[0],
226                            g: color[1],
227                            b: color[2],
228                            a: ALPHA_OPAQUE,
229                        }),
230                    }
231                }
232            }
233        }
234    }
235
236    pub fn write_color(self, color: Rgba, mut buffer: &mut [u8]) -> io::Result<()> {
237        match self {
238            Self::ARgb32 => {
239                buffer.write_u8(color.a)?;
240                buffer.write_u8(color.r)?;
241                buffer.write_u8(color.g)?;
242                buffer.write_u8(color.b)?;
243            }
244            Self::XRgb32 => {
245                buffer.write_u8(ALPHA_OPAQUE)?;
246                buffer.write_u8(color.r)?;
247                buffer.write_u8(color.g)?;
248                buffer.write_u8(color.b)?;
249            }
250            Self::ABgr32 => {
251                buffer.write_u8(color.a)?;
252                buffer.write_u8(color.b)?;
253                buffer.write_u8(color.g)?;
254                buffer.write_u8(color.r)?;
255            }
256            Self::XBgr32 => {
257                buffer.write_u8(ALPHA_OPAQUE)?;
258                buffer.write_u8(color.b)?;
259                buffer.write_u8(color.g)?;
260                buffer.write_u8(color.r)?;
261            }
262            Self::BgrA32 => {
263                buffer.write_u8(color.b)?;
264                buffer.write_u8(color.g)?;
265                buffer.write_u8(color.r)?;
266                buffer.write_u8(color.a)?;
267            }
268            Self::BgrX32 => {
269                buffer.write_u8(color.b)?;
270                buffer.write_u8(color.g)?;
271                buffer.write_u8(color.r)?;
272                buffer.write_u8(ALPHA_OPAQUE)?;
273            }
274            Self::RgbA32 => {
275                buffer.write_u8(color.r)?;
276                buffer.write_u8(color.g)?;
277                buffer.write_u8(color.b)?;
278                buffer.write_u8(color.a)?;
279            }
280            Self::RgbX32 => {
281                buffer.write_u8(color.r)?;
282                buffer.write_u8(color.g)?;
283                buffer.write_u8(color.b)?;
284                buffer.write_u8(ALPHA_OPAQUE)?;
285            }
286        }
287
288        Ok(())
289    }
290}
291
292struct Point {
293    x: usize,
294    y: usize,
295}
296
297pub struct Rgba {
298    pub r: u8,
299    pub g: u8,
300    pub b: u8,
301    pub a: u8,
302}