dicom_toolkit_data/io/
codec.rs1use dicom_toolkit_core::error::{DcmError, DcmResult};
6
7pub trait PixelCodec: Send + Sync {
10 fn uid(&self) -> &'static str;
11 fn decode_frame(&self, data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>>;
12 fn encode_frame(&self, data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>>;
13}
14
15pub struct RleCodec;
18
19impl PixelCodec for RleCodec {
20 fn uid(&self) -> &'static str {
21 "1.2.840.10008.1.2.5"
22 }
23
24 fn decode_frame(&self, data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>> {
25 rle_decode(data, rows, cols, bits)
26 }
27
28 fn encode_frame(&self, data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>> {
29 rle_encode(data, rows, cols, bits)
30 }
31}
32
33fn rle_decode(data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>> {
36 if data.len() < 64 {
37 return Err(DcmError::DecompressionError {
38 reason: "RLE header too small".into(),
39 });
40 }
41
42 let pixel_count = rows as usize * cols as usize;
43 let bytes_per_sample = if bits <= 8 { 1usize } else { 2usize };
44
45 let num_segments = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
46 if num_segments == 0 || num_segments > 15 {
47 return Err(DcmError::DecompressionError {
48 reason: format!("invalid RLE segment count: {}", num_segments),
49 });
50 }
51
52 let mut offsets = [0u32; 15];
54 for (i, offset) in offsets.iter_mut().enumerate() {
55 let base = 4 + i * 4;
56 *offset = u32::from_le_bytes([data[base], data[base + 1], data[base + 2], data[base + 3]]);
57 }
58
59 let mut segments: Vec<Vec<u8>> = Vec::with_capacity(num_segments);
61 for i in 0..num_segments {
62 let start = offsets[i] as usize;
63 let end = if i + 1 < num_segments {
64 offsets[i + 1] as usize
65 } else {
66 data.len()
67 };
68 if start > data.len() || end > data.len() || start > end {
69 return Err(DcmError::DecompressionError {
70 reason: format!("invalid RLE segment offset: {} > {}", start, end),
71 });
72 }
73 let seg = rle_decode_segment(&data[start..end], pixel_count)?;
74 segments.push(seg);
75 }
76
77 let samples = num_segments / bytes_per_sample;
80 let total_bytes = pixel_count * samples * bytes_per_sample;
81 let mut out = vec![0u8; total_bytes];
82
83 for sample in 0..samples {
84 for pixel in 0..pixel_count {
85 if bytes_per_sample == 1 {
86 out[pixel * samples + sample] = segments[sample][pixel];
87 } else {
88 let hi = segments[sample * 2][pixel];
90 let lo = segments[sample * 2 + 1][pixel];
91 let out_idx = (pixel * samples + sample) * 2;
92 out[out_idx] = lo; out[out_idx + 1] = hi;
94 }
95 }
96 }
97
98 Ok(out)
99}
100
101fn rle_decode_segment(data: &[u8], pixel_count: usize) -> DcmResult<Vec<u8>> {
102 let mut out = Vec::with_capacity(pixel_count);
103 let mut pos = 0;
104
105 while pos < data.len() && out.len() < pixel_count {
106 let n = data[pos] as i8;
107 pos += 1;
108 if n >= 0 {
109 let count = n as usize + 1;
111 let end = pos + count;
112 if end > data.len() {
113 return Err(DcmError::DecompressionError {
114 reason: "RLE literal run overflows data".into(),
115 });
116 }
117 out.extend_from_slice(&data[pos..end]);
118 pos = end;
119 } else if n != -128 {
120 if pos >= data.len() {
122 return Err(DcmError::DecompressionError {
123 reason: "RLE replicated run missing byte".into(),
124 });
125 }
126 let byte = data[pos];
127 pos += 1;
128 let count = (1i32 - n as i32) as usize;
129 for _ in 0..count {
130 out.push(byte);
131 }
132 }
133 }
135
136 Ok(out)
137}
138
139fn rle_encode(data: &[u8], rows: u16, cols: u16, bits: u16) -> DcmResult<Vec<u8>> {
142 let pixel_count = rows as usize * cols as usize;
143 let bytes_per_sample = if bits <= 8 { 1usize } else { 2usize };
144
145 let total_pixels = pixel_count * bytes_per_sample;
146 if data.len() < total_pixels {
147 return Err(DcmError::CompressionError {
148 reason: "insufficient pixel data for RLE encoding".into(),
149 });
150 }
151 let samples = data.len() / total_pixels;
152 let num_segments = samples * bytes_per_sample;
153
154 let mut byte_planes: Vec<Vec<u8>> = vec![Vec::with_capacity(pixel_count); num_segments];
156 for pixel in 0..pixel_count {
157 for sample in 0..samples {
158 if bytes_per_sample == 1 {
159 byte_planes[sample].push(data[pixel * samples + sample]);
160 } else {
161 let idx = (pixel * samples + sample) * 2;
162 let lo = data[idx];
163 let hi = data[idx + 1];
164 byte_planes[sample * 2].push(hi);
166 byte_planes[sample * 2 + 1].push(lo);
167 }
168 }
169 }
170
171 let mut encoded_segments: Vec<Vec<u8>> = Vec::with_capacity(num_segments);
173 for plane in &byte_planes {
174 encoded_segments.push(rle_encode_segment(plane));
175 }
176
177 let mut header = vec![0u8; 64];
179 let n = num_segments as u32;
180 header[0..4].copy_from_slice(&n.to_le_bytes());
181
182 let mut offset = 64u32;
184 for (i, seg) in encoded_segments.iter().enumerate() {
185 let base = 4 + i * 4;
186 header[base..base + 4].copy_from_slice(&offset.to_le_bytes());
187 offset += seg.len() as u32;
188 }
189
190 let mut out = header;
191 for seg in encoded_segments {
192 out.extend_from_slice(&seg);
193 }
194
195 if out.len() % 2 != 0 {
197 out.push(0);
198 }
199
200 Ok(out)
201}
202
203fn rle_encode_segment(data: &[u8]) -> Vec<u8> {
204 let mut out = Vec::new();
205 let mut i = 0;
206
207 while i < data.len() {
208 let mut run_len = 1;
210 while i + run_len < data.len() && data[i + run_len] == data[i] && run_len < 128 {
211 run_len += 1;
212 }
213
214 if run_len > 1 {
215 out.push((257 - run_len as i32) as u8);
217 out.push(data[i]);
218 i += run_len;
219 } else {
220 let lit_start = i;
222 while i < data.len() {
223 let mut next_run = 1;
224 while i + next_run < data.len() && data[i + next_run] == data[i] && next_run < 128 {
225 next_run += 1;
226 }
227 if next_run >= 2 {
228 break;
229 }
230 i += 1;
231 if i - lit_start >= 128 {
232 break;
233 }
234 }
235 let lit_len = i - lit_start;
236 out.push((lit_len - 1) as u8);
237 out.extend_from_slice(&data[lit_start..i]);
238 }
239 }
240
241 out
242}
243
244pub fn codec_for_uid(uid: &str) -> Option<Box<dyn PixelCodec>> {
246 match uid {
247 "1.2.840.10008.1.2.5" => Some(Box::new(RleCodec)),
248 _ => None,
249 }
250}
251
252#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn rle_encode_decode_roundtrip_8bit() {
260 let rows = 4u16;
261 let cols = 4u16;
262 let bits = 8u16;
263 let data: Vec<u8> = (0..16u8).collect();
264
265 let codec = RleCodec;
266 let encoded = codec.encode_frame(&data, rows, cols, bits).unwrap();
267 let decoded = codec.decode_frame(&encoded, rows, cols, bits).unwrap();
268 assert_eq!(decoded, data);
269 }
270
271 #[test]
272 fn rle_encode_decode_roundtrip_16bit() {
273 let rows = 2u16;
274 let cols = 2u16;
275 let bits = 16u16;
276 let data: Vec<u8> = vec![0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04];
277
278 let codec = RleCodec;
279 let encoded = codec.encode_frame(&data, rows, cols, bits).unwrap();
280 let decoded = codec.decode_frame(&encoded, rows, cols, bits).unwrap();
281 assert_eq!(decoded, data);
282 }
283
284 #[test]
285 fn rle_decode_segment_runs() {
286 let data = [0x01u8, 0xAA, 0xBB, 0xFE, 0xCC];
288 let result = rle_decode_segment(&data, 5).unwrap();
289 assert_eq!(result, vec![0xAA, 0xBB, 0xCC, 0xCC, 0xCC]);
290 }
291}