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