dicom_core/value/
fragments.rs

1//! Helper module for handling pixel encapsulation into fragments
2use crate::value::{InMemFragment, PixelFragmentSequence, C};
3
4/// Represents the fragments of a single frame.
5///
6/// A [`PixelFragmentSequence`] can be generated from a list of [`Fragments`].
7/// In case of multi-frame, a list of frames composed by 1 fragment is expected.
8///
9/// The frames can be independently processed, so parallel execution is possible.
10///
11/// # Example
12/// ```
13/// use dicom_core::{DataElement, Tag};
14/// use dicom_core::header::EmptyObject;
15/// use dicom_core::value::Value::PixelSequence;
16/// use dicom_core::value::fragments::Fragments;
17/// use dicom_core::value::InMemFragment;
18/// use dicom_core::VR::OB;
19///
20/// // Frames are represented as Vec<Vec<u8>>
21/// // Single 512x512 frame
22/// let frames = vec![vec![0; 262144]];
23/// let fragments = frames
24///     .into_iter()
25///     .map(|frame| Fragments::new(frame, 0))
26///     .collect::<Vec<Fragments>>();
27///
28/// let element = DataElement::new(
29///     Tag(0x7FE0, 0x0008),
30///     OB,
31///     PixelSequence::<EmptyObject, InMemFragment>(fragments.into())
32/// );
33/// ```
34///
35/// From this last example, it is possible to extend it to implement a pipeline, and even use rayon
36/// for parallel processing of the frames.
37#[derive(Debug)]
38pub struct Fragments {
39    fragments: Vec<InMemFragment>,
40}
41
42impl Fragments {
43    pub fn new(data: Vec<u8>, fragment_size: u32) -> Self {
44        let fragment_size: u32 = if fragment_size == 0 {
45            data.len() as u32
46        } else {
47            fragment_size
48        };
49
50        let fragment_size = if fragment_size % 2 == 0 {
51            fragment_size
52        } else {
53            fragment_size + 1
54        };
55
56        let number_of_fragments = (data.len() as f32 / fragment_size as f32).ceil() as u32;
57
58        // Calculate the encapsulated size. If necessary pad the vector with zeroes so all the
59        // chunks have the same fragment_size
60        let mut data = data;
61        let encapsulated_size = (fragment_size * number_of_fragments) as usize;
62        if encapsulated_size > data.len() {
63            data.resize(encapsulated_size, 0);
64        }
65
66        let fragments = data
67            .chunks_exact(fragment_size as usize)
68            .map(|fragment| fragment.to_vec())
69            .collect::<Vec<InMemFragment>>();
70
71        Fragments { fragments }
72    }
73
74    pub fn is_empty(&self) -> bool {
75        self.fragments.len() == 0
76    }
77
78    pub fn is_multiframe(&self) -> bool {
79        self.fragments.len() > 1
80    }
81
82    pub fn len(&self) -> u32 {
83        self.fragments
84            .iter()
85            .fold(0u32, |acc, fragment| acc + fragment.len() as u32 + 8u32)
86    }
87}
88
89impl From<Vec<Fragments>> for PixelFragmentSequence<InMemFragment> {
90    fn from(value: Vec<Fragments>) -> Self {
91        let mut offset_table = C::with_capacity(value.len() + 1);
92        offset_table.push(0u32);
93        let mut current_offset = 0u32;
94
95        let mut fragments = Vec::new();
96        let is_multiframe = value.len() > 1;
97        let last_frame = value.len() - 1;
98
99        for (index, mut frame) in value.into_iter().enumerate() {
100            if frame.is_multiframe() && is_multiframe {
101                panic!("More than 1 fragment per frame is invalid for multi frame pixel data");
102            }
103
104            if index < last_frame {
105                let offset = frame.len();
106                offset_table.push(current_offset + offset);
107                current_offset += offset;
108            }
109
110            fragments.append(&mut frame.fragments);
111        }
112
113        PixelFragmentSequence {
114            offset_table,
115            fragments: C::from_vec(fragments),
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use crate::value::fragments::Fragments;
123    use crate::value::{InMemFragment, PixelFragmentSequence};
124
125    #[test]
126    fn test_fragment_frame() {
127        let fragment = Fragments::new(vec![150, 164, 200], 0);
128        assert_eq!(fragment.fragments.len(), 1, "1 fragment should be present");
129        assert_eq!(
130            fragment.fragments[0].len(),
131            4,
132            "The fragment size should be 4"
133        );
134        assert_eq!(
135            fragment.fragments[0],
136            vec![150, 164, 200, 0],
137            "The data should be 0 padded"
138        );
139
140        let fragment = Fragments::new(vec![150, 164, 200, 222], 4);
141        assert_eq!(fragment.fragments.len(), 1, "1 fragment should be present");
142        assert_eq!(
143            fragment.fragments[0].len(),
144            4,
145            "The fragment size should be 4"
146        );
147        assert_eq!(
148            fragment.fragments[0],
149            vec![150, 164, 200, 222],
150            "The data should be what was sent"
151        );
152
153        let fragment = Fragments::new(vec![150, 164, 200, 222], 2);
154        assert_eq!(fragment.fragments.len(), 2, "2 fragments should be present");
155        assert_eq!(fragment.fragments[0].len(), 2);
156        assert_eq!(fragment.fragments[1].len(), 2);
157        assert_eq!(fragment.fragments[0], vec![150, 164]);
158        assert_eq!(fragment.fragments[1], vec![200, 222]);
159
160        let fragment = Fragments::new(vec![150, 164, 200], 1);
161        assert_eq!(
162            fragment.fragments.len(),
163            2,
164            "2 fragments should be present as fragment_size < 2"
165        );
166        assert_eq!(fragment.fragments[0].len(), 2);
167        assert_eq!(fragment.fragments[0], vec![150, 164]);
168        assert_eq!(fragment.fragments[1].len(), 2);
169        assert_eq!(fragment.fragments[1], vec![200, 0]);
170
171        let fragment = Fragments::new(vec![150, 164, 200, 222], 1);
172        assert_eq!(
173            fragment.fragments.len(),
174            2,
175            "2 fragments should be present as fragment_size < 2"
176        );
177        assert_eq!(fragment.fragments[0].len(), 2);
178        assert_eq!(fragment.fragments[0], vec![150, 164]);
179        assert_eq!(fragment.fragments[1].len(), 2);
180        assert_eq!(fragment.fragments[1], vec![200, 222]);
181    }
182
183    #[test]
184    fn test_bot_single_fragment_generation() {
185        let data = vec![Fragments::new(vec![0u8; 2], 2)];
186        let fragment_sequence: PixelFragmentSequence<InMemFragment> = data.into();
187        assert_eq!(fragment_sequence.offset_table.len(), 1);
188        assert_eq!(fragment_sequence.offset_table[0], 0);
189    }
190
191    #[test]
192    fn test_bot_multi_fragments_generation() {
193        let data = vec![Fragments::new(vec![0u8; 4], 2)];
194        let fragment_sequence: PixelFragmentSequence<InMemFragment> = data.into();
195        assert_eq!(fragment_sequence.offset_table.len(), 1);
196        assert_eq!(fragment_sequence.offset_table[0], 0);
197    }
198
199    #[test]
200    fn test_bot_multi_frame_generation() {
201        let data = vec![
202            Fragments::new(vec![0u8; 4], 0),
203            Fragments::new(vec![1u8; 6], 0),
204        ];
205        let fragment_sequence: PixelFragmentSequence<InMemFragment> = data.into();
206        assert_eq!(fragment_sequence.offset_table.len(), 2);
207        assert_eq!(fragment_sequence.offset_table[0], 0);
208        assert_eq!(fragment_sequence.offset_table[1], 12); // 8 separator bytes + 4 data bytes
209    }
210}