1use alloc::collections::BTreeMap;
10use alloc::string::{String, ToString};
11use alloc::vec;
12use alloc::vec::Vec;
13use core::iter::Iterator;
14use core::option::Option::{self, *};
15use core::result::Result::{self, *};
16
17use zune_core::bytestream::{ZByteReader, ZReaderTrait};
18use zune_core::colorspace::ColorSpace;
19use zune_core::log::trace;
20use zune_core::options::DecoderOptions;
21
22use crate::errors::HdrDecodeErrors;
23
24pub struct HdrDecoder<T: ZReaderTrait> {
34 buf: ZByteReader<T>,
35 options: DecoderOptions,
36 metadata: BTreeMap<String, String>,
37 width: usize,
38 height: usize,
39 decoded_headers: bool
40}
41
42impl<T> HdrDecoder<T>
43where
44 T: ZReaderTrait
45{
46 pub fn new(data: T) -> HdrDecoder<T> {
63 Self::new_with_options(data, DecoderOptions::default())
64 }
65
66 pub fn new_with_options(data: T, options: DecoderOptions) -> HdrDecoder<T> {
89 HdrDecoder {
90 buf: ZByteReader::new(data),
91 options,
92 width: 0,
93 height: 0,
94 metadata: BTreeMap::new(),
95 decoded_headers: false
96 }
97 }
98 pub const fn get_metadata(&self) -> &BTreeMap<String, String> {
104 &self.metadata
105 }
106 pub fn decode_headers(&mut self) -> Result<(), HdrDecodeErrors> {
111 let mut max_header_size = vec![0; 1024];
113
114 if self.decoded_headers {
115 return Ok(());
116 }
117 self.get_buffer_until(b'\n', &mut max_header_size)?;
118
119 if !(max_header_size.starts_with(b"#?RADIANCE\n")
120 || max_header_size.starts_with(b"#?RGBE\n"))
121 {
122 return Err(HdrDecodeErrors::InvalidMagicBytes);
123 }
124
125 loop {
126 let size = self.get_buffer_until(b'\n', &mut max_header_size)?;
127 if max_header_size.starts_with(b"#")
128 {
130 continue;
131 }
132 if max_header_size[..size].contains(&b'=') {
133 let keys_and_values = String::from_utf8_lossy(&max_header_size[..size]);
136
137 let mut keys_and_values_split = keys_and_values.trim().split('=');
138 let key = keys_and_values_split.next().unwrap().trim().to_string();
139 let value = keys_and_values_split.next().unwrap().trim().to_string();
140 self.metadata.insert(key, value);
141 }
142
143 if size == 0 || max_header_size[0] == b'\n' {
144 trace!("Metadata: {:?}", self.metadata);
145 break;
146 }
147 }
148 let header_size = self.get_buffer_until(b' ', &mut max_header_size)?;
149
150 let first_type = String::from_utf8_lossy(&max_header_size[..header_size])
151 .trim()
152 .to_string();
153
154 let header_size = self.get_buffer_until(b' ', &mut max_header_size)?;
155
156 let coords1 = String::from_utf8_lossy(&max_header_size[..header_size])
157 .trim()
158 .to_string();
159
160 let header_size = self.get_buffer_until(b' ', &mut max_header_size)?;
161
162 let second_type = String::from_utf8_lossy(&max_header_size[..header_size])
163 .trim()
164 .to_string();
165
166 let header_size = self.get_buffer_until(b'\n', &mut max_header_size)?;
167
168 let coords2 = String::from_utf8_lossy(&max_header_size[..header_size])
169 .trim()
170 .to_string();
171
172 match (first_type.as_str(), second_type.as_str()) {
173 ("-Y", "+X") => {
174 self.height = coords1.parse::<usize>()?;
175 self.width = coords2.parse::<usize>()?;
176 }
177 ("+X", "-Y") => {
178 self.height = coords2.parse::<usize>()?;
179 self.width = coords1.parse::<usize>()?;
180 }
181 (_, _) => {
182 return Err(HdrDecodeErrors::UnsupportedOrientation(
183 first_type,
184 second_type
185 ));
186 }
187 }
188 if self.height > self.options.get_max_height() {
189 return Err(HdrDecodeErrors::TooLargeDimensions(
190 "height",
191 self.options.get_max_height(),
192 self.height
193 ));
194 }
195
196 if self.width > self.options.get_max_width() {
197 return Err(HdrDecodeErrors::TooLargeDimensions(
198 "width",
199 self.options.get_max_width(),
200 self.width
201 ));
202 }
203
204 trace!("Width: {}", self.width);
205 trace!("Height: {}", self.height);
206
207 self.decoded_headers = true;
208
209 Ok(())
210 }
211
212 pub const fn get_dimensions(&self) -> Option<(usize, usize)> {
219 if self.decoded_headers {
220 Some((self.width, self.height))
221 } else {
222 None
223 }
224 }
225
226 pub fn get_colorspace(&self) -> Option<ColorSpace> {
232 if self.decoded_headers {
233 Some(ColorSpace::RGB)
234 } else {
235 None
236 }
237 }
238
239 pub fn decode(&mut self) -> Result<Vec<f32>, HdrDecodeErrors> {
247 self.decode_headers()?;
248 let mut buffer = vec![0.0f32; self.width * self.height * 3];
249
250 self.decode_into(&mut buffer)?;
251
252 Ok(buffer)
253 }
254 pub fn output_buffer_size(&self) -> Option<usize> {
263 if self.decoded_headers {
264 Some(self.width.checked_mul(self.height)?.checked_mul(3)?)
265 } else {
266 None
267 }
268 }
269
270 pub fn decode_into(&mut self, buffer: &mut [f32]) -> Result<(), HdrDecodeErrors> {
293 if !self.decoded_headers {
294 self.decode_headers()?;
295 }
296
297 let output_size = self.output_buffer_size().unwrap();
298
299 if buffer.len() < output_size {
300 return Err(HdrDecodeErrors::TooSmallOutputArray(
301 output_size,
302 buffer.len()
303 ));
304 }
305
306 let mut scanline = vec![0_u8; self.width * 4]; let output_scanline_size = self.width * 3; for out_scanline in buffer
313 .chunks_exact_mut(output_scanline_size)
314 .take(self.height)
315 {
316 if self.width < 8 || self.width > 0x7fff {
317 self.decompress(&mut scanline, self.width as i32)?;
318 convert_scanline(&scanline, out_scanline);
319 continue;
320 }
321
322 let mut i = self.buf.get_u8();
323
324 if i != 2 {
325 self.buf.rewind(1);
327
328 self.decompress(&mut scanline, self.width as i32)?;
329 convert_scanline(&scanline, out_scanline);
330 continue;
331 }
332 if !self.buf.has(3) {
333 return Err(HdrDecodeErrors::Generic("Not enough bytes"));
336 }
337
338 scanline[1] = self.buf.get_u8();
339 scanline[2] = self.buf.get_u8();
340 i = self.buf.get_u8();
341
342 if scanline[1] != 2 || (scanline[2] & 128) != 0 {
343 scanline[0] = 2;
344 scanline[3] = i;
345
346 self.decompress(&mut scanline, self.width as i32)?;
347 convert_scanline(&scanline, out_scanline);
348 continue;
349 }
350
351 for i in 0..4 {
352 let new_scanline = &mut scanline[i..];
353
354 let mut j = 0;
355
356 loop {
357 if j >= self.width * 4 || self.buf.eof() {
358 break;
359 }
360 let mut run = i32::from(self.buf.get_u8());
361
362 if run > 128 {
363 let val = self.buf.get_u8();
364 run &= 127;
365
366 while run > 0 {
367 run -= 1;
368
369 if j >= self.width * 4 {
370 break;
371 }
372 new_scanline[j] = val;
373 j += 4;
374 }
375 } else if run > 0 {
376 while run > 0 {
377 run -= 1;
378
379 if j >= self.width * 4 {
380 break;
381 }
382
383 new_scanline[j] = self.buf.get_u8();
384 j += 4;
385 }
386 }
387 }
388 }
389 convert_scanline(&scanline, out_scanline);
390 }
391
392 Ok(())
393 }
394
395 fn decompress(&mut self, scanline: &mut [u8], mut width: i32) -> Result<(), HdrDecodeErrors> {
396 let mut shift = 0;
397 let mut scanline_offset = 0;
398
399 while width > 0 {
400 if !self.buf.has(4) {
401 return Err(HdrDecodeErrors::Generic("Not enough bytes"));
404 }
405
406 scanline[0] = self.buf.get_u8();
407 scanline[1] = self.buf.get_u8();
408 scanline[2] = self.buf.get_u8();
409 scanline[3] = self.buf.get_u8();
410
411 if scanline[0] == 1 && scanline[1] == 1 && scanline[2] == 1 {
412 let run = scanline[3];
413
414 let mut i = i32::from(run) << shift;
415
416 while width > 0 && scanline_offset > 4 && i > 0 {
417 scanline.copy_within(scanline_offset - 4..scanline_offset, 4);
418 scanline_offset += 4;
419 i -= 1;
420 width -= 4;
421 }
422 shift += 8;
423
424 if shift > 16 {
425 break;
426 }
427 } else {
428 scanline_offset += 4;
429 width -= 1;
430 shift = 0;
431 }
432 }
433 Ok(())
434 }
435
436 fn get_buffer_until(
442 &mut self, needle: u8, write_to: &mut Vec<u8>
443 ) -> Result<usize, HdrDecodeErrors> {
444 let start = self.buf.get_position();
445
446 self.buf.skip_until_false(|c| c != needle);
448
449 let end = self.buf.get_position();
450 let diff = end - start + 1;
452 self.buf.set_position(start);
454
455 if diff > write_to.len() {
456 write_to.resize(diff + 2, 0);
457 }
458 self.buf
460 .read_exact(&mut write_to[..diff])
461 .map_err(HdrDecodeErrors::Generic)?;
462
463 self.buf.set_position(end + 1);
466 Ok(diff)
467 }
468}
469
470fn convert_scanline(in_scanline: &[u8], out_scanline: &mut [f32]) {
471 for (rgbe, out) in in_scanline
472 .chunks_exact(4)
473 .zip(out_scanline.chunks_exact_mut(3))
474 {
475 if rgbe[3] == 0 {
476 out[0..3].fill(0.0);
477 } else {
478 let epxo = i32::from(rgbe[3]) - 128;
481
482 if epxo.is_positive() {
483 out[0] = convert_pos(i32::from(rgbe[0]), epxo);
484 out[1] = convert_pos(i32::from(rgbe[1]), epxo);
485 out[2] = convert_pos(i32::from(rgbe[2]), epxo);
486 } else {
487 out[0] = convert_neg(i32::from(rgbe[0]), epxo);
488 out[1] = convert_neg(i32::from(rgbe[1]), epxo);
489 out[2] = convert_neg(i32::from(rgbe[2]), epxo);
490 }
491 }
492 }
493}
494
495fn ldexp_pos(x: f32, exp: u32) -> f32 {
496 let pow = 1_u32.wrapping_shl(exp) as f32;
497 x * pow
498}
499fn ldexp_neg(x: f32, exp: u32) -> f32 {
500 let pow = 1_u32.wrapping_shl(exp) as f32;
501 x / pow
502}
503#[inline]
520fn convert_pos(val: i32, exponent: i32) -> f32 {
521 let v = (val as f32) / 256.0;
522 ldexp_pos(v, exponent as u32)
523}
524
525#[inline]
526fn convert_neg(val: i32, exponent: i32) -> f32 {
527 let v = (val as f32) / 256.0;
528 ldexp_neg(v, exponent.abs() as u32)
529}