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}