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        if value.is_empty() {
92            // return an empty fragment list
93            return PixelFragmentSequence {
94                offset_table: C::new(),
95                fragments: C::new(),
96            };
97        }
98
99        let mut offset_table = C::with_capacity(value.len() + 1);
100        offset_table.push(0u32);
101        let mut current_offset = 0u32;
102
103        let mut fragments = Vec::new();
104        let is_multiframe = value.len() > 1;
105        let last_frame = value.len() - 1;
106
107        for (index, mut frame) in value.into_iter().enumerate() {
108            if frame.is_multiframe() && is_multiframe {
109                panic!("More than 1 fragment per frame is invalid for multi frame pixel data");
110            }
111
112            if index < last_frame {
113                let offset = frame.len();
114                offset_table.push(current_offset + offset);
115                current_offset += offset;
116            }
117
118            fragments.append(&mut frame.fragments);
119        }
120
121        PixelFragmentSequence {
122            offset_table,
123            fragments: C::from_vec(fragments),
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use crate::value::fragments::Fragments;
131    use crate::value::{InMemFragment, PixelFragmentSequence};
132
133    #[test]
134    fn test_fragment_frame() {
135        let fragment = Fragments::new(vec![150, 164, 200], 0);
136        assert_eq!(fragment.fragments.len(), 1, "1 fragment should be present");
137        assert_eq!(
138            fragment.fragments[0].len(),
139            4,
140            "The fragment size should be 4"
141        );
142        assert_eq!(
143            fragment.fragments[0],
144            vec![150, 164, 200, 0],
145            "The data should be 0 padded"
146        );
147
148        let fragment = Fragments::new(vec![150, 164, 200, 222], 4);
149        assert_eq!(fragment.fragments.len(), 1, "1 fragment should be present");
150        assert_eq!(
151            fragment.fragments[0].len(),
152            4,
153            "The fragment size should be 4"
154        );
155        assert_eq!(
156            fragment.fragments[0],
157            vec![150, 164, 200, 222],
158            "The data should be what was sent"
159        );
160
161        let fragment = Fragments::new(vec![150, 164, 200, 222], 2);
162        assert_eq!(fragment.fragments.len(), 2, "2 fragments should be present");
163        assert_eq!(fragment.fragments[0].len(), 2);
164        assert_eq!(fragment.fragments[1].len(), 2);
165        assert_eq!(fragment.fragments[0], vec![150, 164]);
166        assert_eq!(fragment.fragments[1], vec![200, 222]);
167
168        let fragment = Fragments::new(vec![150, 164, 200], 1);
169        assert_eq!(
170            fragment.fragments.len(),
171            2,
172            "2 fragments should be present as fragment_size < 2"
173        );
174        assert_eq!(fragment.fragments[0].len(), 2);
175        assert_eq!(fragment.fragments[0], vec![150, 164]);
176        assert_eq!(fragment.fragments[1].len(), 2);
177        assert_eq!(fragment.fragments[1], vec![200, 0]);
178
179        let fragment = Fragments::new(vec![150, 164, 200, 222], 1);
180        assert_eq!(
181            fragment.fragments.len(),
182            2,
183            "2 fragments should be present as fragment_size < 2"
184        );
185        assert_eq!(fragment.fragments[0].len(), 2);
186        assert_eq!(fragment.fragments[0], vec![150, 164]);
187        assert_eq!(fragment.fragments[1].len(), 2);
188        assert_eq!(fragment.fragments[1], vec![200, 222]);
189    }
190
191    #[test]
192    fn test_bot_single_fragment_generation() {
193        let data = vec![Fragments::new(vec![0u8; 2], 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_fragments_generation() {
201        let data = vec![Fragments::new(vec![0u8; 4], 2)];
202        let fragment_sequence: PixelFragmentSequence<InMemFragment> = data.into();
203        assert_eq!(fragment_sequence.offset_table.len(), 1);
204        assert_eq!(fragment_sequence.offset_table[0], 0);
205    }
206
207    #[test]
208    fn test_bot_multi_frame_generation() {
209        let data = vec![
210            Fragments::new(vec![0u8; 4], 0),
211            Fragments::new(vec![1u8; 6], 0),
212        ];
213        let fragment_sequence: PixelFragmentSequence<InMemFragment> = data.into();
214        assert_eq!(fragment_sequence.offset_table.len(), 2);
215        assert_eq!(fragment_sequence.offset_table[0], 0);
216        assert_eq!(fragment_sequence.offset_table[1], 12); // 8 separator bytes + 4 data bytes
217    }
218}