dicom_toolkit_codec/jpeg_ls/
encoder.rs1use dicom_toolkit_core::error::{DcmError, DcmResult};
6
7use super::marker;
8use super::params::{
9 compute_default, ColorTransform, DerivedTraits, InterleaveMode, JlsParameters, BASIC_RESET,
10};
11use super::sample::needs_u16;
12use super::scan::ScanEncoder;
13
14pub fn encode_jpeg_ls(
22 pixels: &[u8],
23 width: u32,
24 height: u32,
25 bits_per_sample: u8,
26 components: u8,
27 near: i32,
28) -> DcmResult<Vec<u8>> {
29 if !(2..=16).contains(&bits_per_sample) {
30 return Err(DcmError::CompressionError {
31 reason: format!("JPEG-LS: unsupported bit depth {bits_per_sample}"),
32 });
33 }
34 if components == 0 || components > 4 {
35 return Err(DcmError::CompressionError {
36 reason: format!("JPEG-LS: unsupported component count {components}"),
37 });
38 }
39
40 let max_val = (1i32 << bits_per_sample) - 1;
41 let defaults = compute_default(max_val, near);
42 let traits = DerivedTraits::new(max_val, near, BASIC_RESET);
43 let w = width as usize;
44 let h = height as usize;
45 let nc = components as usize;
46
47 let interleave = if nc == 1 {
49 InterleaveMode::None
50 } else {
51 InterleaveMode::Line
52 };
53
54 let params = JlsParameters {
55 width,
56 height,
57 bits_per_sample,
58 components,
59 near,
60 interleave,
61 color_transform: ColorTransform::None,
62 ..Default::default()
63 };
64
65 let mut output = marker::write_header(¶ms);
67
68 if nc == 1 || interleave == InterleaveMode::None {
69 let pixel_values = bytes_to_i32(pixels, w * h * nc, bits_per_sample)?;
71
72 if nc == 1 {
73 let mut encoder = ScanEncoder::new(traits, defaults.t1, defaults.t2, defaults.t3, w, h);
74 let scan_data = encoder.encode(&pixel_values)?;
75 output.extend_from_slice(&scan_data);
76 } else {
77 for c in 0..nc {
79 let component_pixels: Vec<i32> =
80 (0..(w * h)).map(|i| pixel_values[i * nc + c]).collect();
81
82 let mut encoder =
83 ScanEncoder::new(traits, defaults.t1, defaults.t2, defaults.t3, w, h);
84 let scan_data = encoder.encode(&component_pixels)?;
85 output.extend_from_slice(&scan_data);
86
87 if c + 1 < nc {
89 }
92 }
93 }
94 } else {
95 let pixel_values = bytes_to_i32(pixels, w * h * nc, bits_per_sample)?;
97
98 let mut line_interleaved = Vec::with_capacity(w * h * nc);
101 for y in 0..h {
102 for c in 0..nc {
103 for x in 0..w {
104 line_interleaved.push(pixel_values[(y * w + x) * nc + c]);
105 }
106 }
107 }
108
109 let effective_h = h * nc;
110 let mut encoder = ScanEncoder::new(
111 traits,
112 defaults.t1,
113 defaults.t2,
114 defaults.t3,
115 w,
116 effective_h,
117 );
118 let scan_data = encoder.encode(&line_interleaved)?;
119 output.extend_from_slice(&scan_data);
120 }
121
122 marker::write_eoi(&mut output);
123 Ok(output)
124}
125
126fn bytes_to_i32(data: &[u8], count: usize, bits_per_sample: u8) -> DcmResult<Vec<i32>> {
128 if needs_u16(bits_per_sample) {
129 if data.len() < count * 2 {
130 return Err(DcmError::CompressionError {
131 reason: format!("JPEG-LS: expected {} bytes, got {}", count * 2, data.len()),
132 });
133 }
134 let mut values = Vec::with_capacity(count);
135 for i in 0..count {
136 let lo = data[i * 2] as i32;
137 let hi = data[i * 2 + 1] as i32;
138 values.push(lo | (hi << 8));
139 }
140 Ok(values)
141 } else {
142 if data.len() < count {
143 return Err(DcmError::CompressionError {
144 reason: format!("JPEG-LS: expected {} bytes, got {}", count, data.len()),
145 });
146 }
147 Ok(data[..count].iter().map(|&b| b as i32).collect())
148 }
149}
150
151#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::jpeg_ls::decoder::decode_jpeg_ls;
157
158 #[test]
159 fn encode_decode_roundtrip_8bit_grayscale() {
160 let w = 16u32;
161 let h = 8u32;
162 let mut pixels = Vec::with_capacity((w * h) as usize);
163 for y in 0..h {
164 for x in 0..w {
165 pixels.push(((x * 16 + y * 8) % 256) as u8);
166 }
167 }
168
169 let encoded = encode_jpeg_ls(&pixels, w, h, 8, 1, 0).unwrap();
170 let decoded = decode_jpeg_ls(&encoded).unwrap();
171
172 assert_eq!(decoded.width, w);
173 assert_eq!(decoded.height, h);
174 assert_eq!(decoded.bits_per_sample, 8);
175 assert_eq!(decoded.components, 1);
176 assert_eq!(decoded.pixels, pixels);
177 }
178
179 #[test]
180 fn encode_decode_roundtrip_constant() {
181 let pixels = vec![128u8; 64];
182 let encoded = encode_jpeg_ls(&pixels, 8, 8, 8, 1, 0).unwrap();
183 let decoded = decode_jpeg_ls(&encoded).unwrap();
184 assert_eq!(decoded.pixels, pixels);
185 }
186
187 #[test]
188 fn encode_decode_roundtrip_16bit_grayscale() {
189 let w = 8u32;
190 let h = 4u32;
191 let mut pixels = Vec::with_capacity((w * h * 2) as usize);
192 for y in 0..h {
193 for x in 0..w {
194 let val = ((x * 1000 + y * 500) % 4096) as u16;
195 pixels.push(val as u8);
196 pixels.push((val >> 8) as u8);
197 }
198 }
199
200 let encoded = encode_jpeg_ls(&pixels, w, h, 12, 1, 0).unwrap();
201 let decoded = decode_jpeg_ls(&encoded).unwrap();
202
203 assert_eq!(decoded.width, w);
204 assert_eq!(decoded.height, h);
205 assert_eq!(decoded.bits_per_sample, 12);
206 assert_eq!(decoded.pixels, pixels);
207 }
208}