1
1
//! Decode pixel data using GDCM when the default features are enabled.
2
2
3
3
use crate :: * ;
4
+ use dicom_dictionary_std:: tags;
4
5
use dicom_encoding:: adapters:: DecodeError ;
5
6
use dicom_encoding:: transfer_syntax:: TransferSyntaxIndex ;
6
7
use dicom_transfer_syntax_registry:: TransferSyntaxRegistry ;
@@ -18,28 +19,31 @@ where
18
19
use super :: attribute:: * ;
19
20
20
21
let pixel_data = pixel_data ( self ) . context ( GetAttributeSnafu ) ?;
21
-
22
+
22
23
let cols = cols ( self ) . context ( GetAttributeSnafu ) ?;
23
24
let rows = rows ( self ) . context ( GetAttributeSnafu ) ?;
24
25
25
26
let photometric_interpretation =
26
27
photometric_interpretation ( self ) . context ( GetAttributeSnafu ) ?;
27
- let pi_type = GDCMPhotometricInterpretation :: from_str ( photometric_interpretation. as_str ( ) )
28
- . map_err ( |_| {
29
- UnsupportedPhotometricInterpretationSnafu {
30
- pi : photometric_interpretation. clone ( ) ,
31
- }
32
- . build ( )
33
- } ) ?;
28
+ let pi_type = match photometric_interpretation {
29
+ PhotometricInterpretation :: PaletteColor => GDCMPhotometricInterpretation :: PALETTE_COLOR ,
30
+ _ => GDCMPhotometricInterpretation :: from_str ( photometric_interpretation. as_str ( ) )
31
+ . map_err ( |_| {
32
+ UnsupportedPhotometricInterpretationSnafu {
33
+ pi : photometric_interpretation. clone ( ) ,
34
+ }
35
+ . build ( )
36
+ } ) ?,
37
+ } ;
34
38
35
39
let transfer_syntax = & self . meta ( ) . transfer_syntax ;
36
40
let registry =
37
41
TransferSyntaxRegistry
38
- . get ( & & transfer_syntax)
42
+ . get ( transfer_syntax)
39
43
. context ( UnknownTransferSyntaxSnafu {
40
44
ts_uid : transfer_syntax,
41
45
} ) ?;
42
- let ts_type = GDCMTransferSyntax :: from_str ( & registry. uid ( ) ) . map_err ( |_| {
46
+ let ts_type = GDCMTransferSyntax :: from_str ( registry. uid ( ) ) . map_err ( |_| {
43
47
UnsupportedTransferSyntaxSnafu {
44
48
ts : transfer_syntax. clone ( ) ,
45
49
}
66
70
} ;
67
71
if fragments. len ( ) > 1 {
68
72
// Bundle fragments and decode multi-frame dicoms
69
- let dims = [ cols. into ( ) , rows. into ( ) , number_of_frames. into ( ) ] ;
73
+ let dims = [ cols. into ( ) , rows. into ( ) , number_of_frames] ;
70
74
let fragments: Vec < _ > = fragments. iter ( ) . map ( |frag| frag. as_slice ( ) ) . collect ( ) ;
71
75
decode_multi_frame_compressed (
72
76
fragments. as_slice ( ) ,
@@ -144,6 +148,184 @@ where
144
148
window,
145
149
} )
146
150
}
151
+
152
+ fn decode_pixel_data_frame ( & self , frame : u32 ) -> Result < DecodedPixelData < ' _ > > {
153
+ use super :: attribute:: * ;
154
+
155
+ let pixel_data = pixel_data ( self ) . context ( GetAttributeSnafu ) ?;
156
+
157
+ let cols = cols ( self ) . context ( GetAttributeSnafu ) ?;
158
+ let rows = rows ( self ) . context ( GetAttributeSnafu ) ?;
159
+
160
+ let photometric_interpretation =
161
+ photometric_interpretation ( self ) . context ( GetAttributeSnafu ) ?;
162
+ let pi_type = match photometric_interpretation {
163
+ PhotometricInterpretation :: PaletteColor => GDCMPhotometricInterpretation :: PALETTE_COLOR ,
164
+ _ => GDCMPhotometricInterpretation :: from_str ( photometric_interpretation. as_str ( ) )
165
+ . map_err ( |_| {
166
+ UnsupportedPhotometricInterpretationSnafu {
167
+ pi : photometric_interpretation. clone ( ) ,
168
+ }
169
+ . build ( )
170
+ } ) ?,
171
+ } ;
172
+
173
+ let transfer_syntax = & self . meta ( ) . transfer_syntax ;
174
+ let registry =
175
+ TransferSyntaxRegistry
176
+ . get ( transfer_syntax)
177
+ . context ( UnknownTransferSyntaxSnafu {
178
+ ts_uid : transfer_syntax,
179
+ } ) ?;
180
+ let ts_type = GDCMTransferSyntax :: from_str ( registry. uid ( ) ) . map_err ( |_| {
181
+ UnsupportedTransferSyntaxSnafu {
182
+ ts : transfer_syntax. clone ( ) ,
183
+ }
184
+ . build ( )
185
+ } ) ?;
186
+
187
+ let samples_per_pixel = samples_per_pixel ( self ) . context ( GetAttributeSnafu ) ?;
188
+ let bits_allocated = bits_allocated ( self ) . context ( GetAttributeSnafu ) ?;
189
+ let bits_stored = bits_stored ( self ) . context ( GetAttributeSnafu ) ?;
190
+ let high_bit = high_bit ( self ) . context ( GetAttributeSnafu ) ?;
191
+ let pixel_representation = pixel_representation ( self ) . context ( GetAttributeSnafu ) ?;
192
+ let planar_configuration = if let Ok ( el) = self . element ( tags:: PLANAR_CONFIGURATION ) {
193
+ el. uint16 ( ) . unwrap_or ( 0 )
194
+ } else {
195
+ 0
196
+ } ;
197
+ let rescale_intercept = rescale_intercept ( self ) ;
198
+ let rescale_slope = rescale_slope ( self ) ;
199
+ let number_of_frames = number_of_frames ( self ) . context ( GetAttributeSnafu ) ?;
200
+ let voi_lut_function = voi_lut_function ( self ) . context ( GetAttributeSnafu ) ?;
201
+ let voi_lut_function = voi_lut_function. and_then ( |v| VoiLutFunction :: try_from ( & * v) . ok ( ) ) ;
202
+
203
+ let decoded_pixel_data = match pixel_data. value ( ) {
204
+ Value :: PixelSequence ( v) => {
205
+ let fragments = v. fragments ( ) ;
206
+ let gdcm_error_mapper = |source : GDCMError | DecodeError :: Custom {
207
+ message : source. to_string ( ) ,
208
+ source : Some ( Box :: new ( source) ) ,
209
+ } ;
210
+
211
+ let frame = frame as usize ;
212
+ let data = if number_of_frames == 1 && fragments. len ( ) > 1 {
213
+ fragments. iter ( ) . flat_map ( |frame| frame. to_vec ( ) ) . collect ( )
214
+ } else {
215
+ fragments[ frame] . to_vec ( )
216
+ } ;
217
+
218
+ match ts_type {
219
+ GDCMTransferSyntax :: ImplicitVRLittleEndian
220
+ | GDCMTransferSyntax :: ExplicitVRLittleEndian => {
221
+ // This is just in case of encapsulated uncompressed data
222
+ let frame_size = cols * rows * samples_per_pixel * ( bits_allocated / 8 ) ;
223
+ data. chunks_exact ( frame_size as usize )
224
+ . nth ( frame)
225
+ . map ( |frame| frame. to_vec ( ) )
226
+ . unwrap_or_default ( )
227
+ }
228
+ _ => {
229
+ let buffer = [ data. as_slice ( ) ] ;
230
+ let dims = [ cols. into ( ) , rows. into ( ) , 1 ] ;
231
+
232
+ decode_multi_frame_compressed (
233
+ & buffer,
234
+ & dims,
235
+ pi_type,
236
+ ts_type,
237
+ samples_per_pixel,
238
+ bits_allocated,
239
+ bits_stored,
240
+ high_bit,
241
+ pixel_representation as u16 ,
242
+ )
243
+ . map_err ( gdcm_error_mapper)
244
+ . context ( DecodePixelDataSnafu ) ?
245
+ . to_vec ( )
246
+ }
247
+ }
248
+ }
249
+ Value :: Primitive ( p) => {
250
+ // Uncompressed data
251
+ let frame_size = cols as usize
252
+ * rows as usize
253
+ * samples_per_pixel as usize
254
+ * ( bits_allocated as usize / 8 ) ;
255
+ p. to_bytes ( )
256
+ . chunks_exact ( frame_size)
257
+ . nth ( frame as usize )
258
+ . map ( |frame| frame. to_vec ( ) )
259
+ . unwrap_or_default ( )
260
+ }
261
+ Value :: Sequence ( _) => InvalidPixelDataSnafu . fail ( ) ?,
262
+ } ;
263
+
264
+ // Convert to PlanarConfiguration::Standard
265
+ let decoded_pixel_data = if planar_configuration == 1 && samples_per_pixel == 3 {
266
+ interleave_planes (
267
+ cols as usize ,
268
+ rows as usize ,
269
+ bits_allocated as usize ,
270
+ decoded_pixel_data,
271
+ )
272
+ } else {
273
+ decoded_pixel_data
274
+ } ;
275
+
276
+ let window = match (
277
+ window_center ( self ) . context ( GetAttributeSnafu ) ?,
278
+ window_width ( self ) . context ( GetAttributeSnafu ) ?,
279
+ ) {
280
+ ( Some ( center) , Some ( width) ) => Some ( WindowLevel { center, width } ) ,
281
+ _ => None ,
282
+ } ;
283
+
284
+ Ok ( DecodedPixelData {
285
+ data : Cow :: from ( decoded_pixel_data) ,
286
+ cols : cols. into ( ) ,
287
+ rows : rows. into ( ) ,
288
+ number_of_frames : 1 ,
289
+ photometric_interpretation,
290
+ samples_per_pixel,
291
+ planar_configuration : PlanarConfiguration :: Standard ,
292
+ bits_allocated,
293
+ bits_stored,
294
+ high_bit,
295
+ pixel_representation,
296
+ rescale_intercept,
297
+ rescale_slope,
298
+ voi_lut_function,
299
+ window,
300
+ } )
301
+ }
302
+ }
303
+
304
+ fn interleave_planes ( cols : usize , rows : usize , bits_allocated : usize , data : Vec < u8 > ) -> Vec < u8 > {
305
+ let frame_size = cols * rows * ( bits_allocated / 8 ) ;
306
+ let mut interleaved = Vec :: with_capacity ( data. len ( ) ) ;
307
+
308
+ let mut i = 0 ;
309
+ while i < frame_size {
310
+ interleaved. push ( data[ i] ) ;
311
+ if bits_allocated > 8 {
312
+ interleaved. push ( data[ i + 1 ] )
313
+ }
314
+
315
+ interleaved. push ( data[ i + frame_size] ) ;
316
+ if bits_allocated > 8 {
317
+ interleaved. push ( data[ i + frame_size + 1 ] )
318
+ }
319
+
320
+ interleaved. push ( data[ i + frame_size * 2 ] ) ;
321
+ if bits_allocated > 8 {
322
+ interleaved. push ( data[ i + frame_size * 2 + 1 ] )
323
+ }
324
+
325
+ i = if bits_allocated > 8 { i + 2 } else { i + 1 } ;
326
+ }
327
+
328
+ interleaved
147
329
}
148
330
149
331
#[ cfg( test) ]
@@ -225,7 +407,7 @@ mod tests {
225
407
#[ case( "pydicom/SC_rgb_rle_2frame.dcm" , 1 ) ]
226
408
#[ case( "pydicom/JPEG2000.dcm" , 0 ) ]
227
409
#[ case( "pydicom/JPEG2000_UNC.dcm" , 0 ) ]
228
- fn test_parse_dicom_pixel_data_individual_frames ( #[ case] value : & str , #[ case] frame : u32 ) {
410
+ fn test_parse_dicom_pixel_data_individual_frames ( #[ case] value : & str , #[ case] frame : u32 ) {
229
411
let test_file = dicom_test_files:: path ( value) . unwrap ( ) ;
230
412
println ! ( "Parsing pixel data for {}" , test_file. display( ) ) ;
231
413
let obj = open_file ( test_file) . unwrap ( ) ;
0 commit comments