/rust/registry/src/index.crates.io-6f17d22bba15001f/exr-1.73.0/src/compression/rle.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use super::*; |
2 | | use super::optimize_bytes::*; |
3 | | use super::Error; |
4 | | use super::Result; |
5 | | |
6 | | // inspired by https://github.com/openexr/openexr/blob/master/OpenEXR/IlmImf/ImfRle.cpp |
7 | | |
8 | | const MIN_RUN_LENGTH : usize = 3; |
9 | | const MAX_RUN_LENGTH : usize = 127; |
10 | | |
11 | | |
12 | 0 | pub fn decompress_bytes( |
13 | 0 | channels: &ChannelList, |
14 | 0 | compressed: ByteVec, |
15 | 0 | rectangle: IntegerBounds, |
16 | 0 | expected_byte_size: usize, |
17 | 0 | pedantic: bool, |
18 | 0 | ) -> Result<ByteVec> { |
19 | 0 | let mut remaining = compressed.as_slice(); |
20 | 0 | let mut decompressed = Vec::with_capacity(expected_byte_size.min(8*2048)); |
21 | | |
22 | 0 | while !remaining.is_empty() && decompressed.len() != expected_byte_size { |
23 | 0 | let count = take_1(&mut remaining)? as i8 as i32; |
24 | | |
25 | 0 | if count < 0 { |
26 | | // take the next '-count' bytes as-is |
27 | 0 | let values = take_n(&mut remaining, (-count) as usize)?; |
28 | 0 | decompressed.extend_from_slice(values); |
29 | | } |
30 | | else { |
31 | | // repeat the next value 'count + 1' times |
32 | 0 | let value = take_1(&mut remaining)?; |
33 | 0 | decompressed.resize(decompressed.len() + count as usize + 1, value); |
34 | | } |
35 | | } |
36 | | |
37 | 0 | if pedantic && !remaining.is_empty() { |
38 | 0 | return Err(Error::invalid("data amount")); |
39 | 0 | } |
40 | 0 |
|
41 | 0 | differences_to_samples(&mut decompressed); |
42 | 0 | interleave_byte_blocks(&mut decompressed); |
43 | 0 | Ok(super::convert_little_endian_to_current(decompressed, channels, rectangle))// TODO no alloc |
44 | 0 | } |
45 | | |
46 | 0 | pub fn compress_bytes(channels: &ChannelList, uncompressed: ByteVec, rectangle: IntegerBounds) -> Result<ByteVec> { |
47 | 0 | // see https://github.com/AcademySoftwareFoundation/openexr/blob/3bd93f85bcb74c77255f28cdbb913fdbfbb39dfe/OpenEXR/IlmImf/ImfTiledOutputFile.cpp#L750-L842 |
48 | 0 | let mut data = super::convert_current_to_little_endian(uncompressed, channels, rectangle);// TODO no alloc |
49 | 0 |
|
50 | 0 | separate_bytes_fragments(&mut data); |
51 | 0 | samples_to_differences(&mut data); |
52 | 0 |
|
53 | 0 | let mut compressed = Vec::with_capacity(data.len()); |
54 | 0 | let mut run_start = 0; |
55 | 0 | let mut run_end = 1; |
56 | | |
57 | 0 | while run_start < data.len() { |
58 | | while |
59 | 0 | run_end < data.len() |
60 | 0 | && data[run_start] == data[run_end] |
61 | 0 | && (run_end - run_start) as i32 - 1 < MAX_RUN_LENGTH as i32 |
62 | 0 | { |
63 | 0 | run_end += 1; |
64 | 0 | } |
65 | | |
66 | 0 | if run_end - run_start >= MIN_RUN_LENGTH { |
67 | 0 | compressed.push(((run_end - run_start) as i32 - 1) as u8); |
68 | 0 | compressed.push(data[run_start]); |
69 | 0 | run_start = run_end; |
70 | 0 |
|
71 | 0 | } else { |
72 | | while |
73 | 0 | run_end < data.len() && ( |
74 | 0 | (run_end + 1 >= data.len() || data[run_end] != data[run_end + 1]) |
75 | 0 | || (run_end + 2 >= data.len() || data[run_end + 1] != data[run_end + 2]) |
76 | 0 | ) && run_end - run_start < MAX_RUN_LENGTH |
77 | 0 | { |
78 | 0 | run_end += 1; |
79 | 0 | } |
80 | | |
81 | 0 | compressed.push((run_start as i32 - run_end as i32) as u8); |
82 | 0 | compressed.extend_from_slice(&data[run_start .. run_end]); |
83 | 0 |
|
84 | 0 | run_start = run_end; |
85 | 0 | run_end += 1; |
86 | | } |
87 | | } |
88 | | |
89 | 0 | Ok(compressed) |
90 | 0 | } |
91 | | |
92 | 0 | fn take_1(slice: &mut &[u8]) -> Result<u8> { |
93 | 0 | if !slice.is_empty() { |
94 | 0 | let result = slice[0]; |
95 | 0 | *slice = &slice[1..]; |
96 | 0 | Ok(result) |
97 | | |
98 | | } else { |
99 | 0 | Err(Error::invalid("compressed data")) |
100 | | } |
101 | 0 | } |
102 | | |
103 | 0 | fn take_n<'s>(slice: &mut &'s [u8], n: usize) -> Result<&'s [u8]> { |
104 | 0 | if n <= slice.len() { |
105 | 0 | let (front, back) = slice.split_at(n); |
106 | 0 | *slice = back; |
107 | 0 | Ok(front) |
108 | | |
109 | | } else { |
110 | 0 | Err(Error::invalid("compressed data")) |
111 | | } |
112 | 0 | } |