dicom_toolkit_codec/jpeg/
encoder.rs1use dicom_toolkit_core::error::{DcmError, DcmResult};
6use jpeg_encoder::{ColorType, Encoder};
7
8use super::params::JpegParams;
9
10pub fn encode_jpeg(
19 pixels: &[u8],
20 width: u16,
21 height: u16,
22 samples_per_pixel: u8,
23 params: &JpegParams,
24) -> DcmResult<Vec<u8>> {
25 let color_type = match samples_per_pixel {
26 1 => ColorType::Luma,
27 3 => ColorType::Rgb,
28 n => {
29 return Err(DcmError::CompressionError {
30 reason: format!("JPEG encoder: unsupported samples per pixel {n}"),
31 })
32 }
33 };
34
35 let mut buf = Vec::new();
36 let mut enc = Encoder::new(&mut buf, params.quality);
37 if samples_per_pixel == 3 {
38 enc.set_sampling_factor(params.sampling_factor);
39 }
40
41 enc.encode(pixels, width, height, color_type)
42 .map_err(|e| DcmError::CompressionError {
43 reason: format!("JPEG encode error: {e}"),
44 })?;
45
46 Ok(buf)
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn encode_grayscale_2x2() {
55 let pixels = vec![128u8, 64, 192, 32];
56 let result = encode_jpeg(&pixels, 2, 2, 1, &JpegParams::default());
57 assert!(result.is_ok(), "encode failed: {:?}", result.err());
58 let bytes = result.unwrap();
59 assert_eq!(&bytes[0..2], &[0xFF, 0xD8]);
61 assert_eq!(&bytes[bytes.len() - 2..], &[0xFF, 0xD9]);
63 }
64
65 #[test]
66 fn encode_rgb_2x2() {
67 let pixels: Vec<u8> = vec![
68 255, 0, 0, 0, 255, 0, 0, 0, 255, 128, 128, 128, ];
73 let result = encode_jpeg(&pixels, 2, 2, 3, &JpegParams::default());
74 assert!(result.is_ok(), "encode failed: {:?}", result.err());
75 }
76
77 #[test]
78 fn encode_decode_roundtrip_grayscale() {
79 use crate::jpeg::decoder::decode_jpeg;
80
81 let pixels: Vec<u8> = (0u8..=255).collect();
82 let result = encode_jpeg(
83 &pixels,
84 16,
85 16,
86 1,
87 &JpegParams {
88 quality: 100,
89 ..Default::default()
90 },
91 );
92 let bytes = result.unwrap();
93
94 let frame = decode_jpeg(&bytes).unwrap();
95 assert_eq!(frame.width, 16);
96 assert_eq!(frame.height, 16);
97 assert_eq!(frame.samples_per_pixel, 1);
98 assert_eq!(frame.data.len(), 16 * 16);
99 }
100}