22use std:: convert:: TryFrom ;
33use std:: error:: Error ;
44
5- use bitvec:: prelude:: * ;
5+ // use bitvec::prelude::*;
66
77use pyo3:: prelude:: * ;
88use pyo3:: wrap_pyfunction;
@@ -60,7 +60,7 @@ fn _parse_header(src: &[u8; 64]) -> [u32; 15] {
6060 Parameters
6161 ----------
6262 src
63- The 64 byte RLE header.
63+ The 64 byte RLE header containing 15 little-endian ordered offset values .
6464 */
6565 return [
6666 u32:: from_le_bytes ( [ src[ 4 ] , src[ 5 ] , src[ 6 ] , src[ 7 ] ] ) ,
@@ -158,7 +158,7 @@ fn _decode_frame(
158158
159159 // Check 'Bits Allocated' is 1 or a multiple of 8
160160 let mut is_bit_packed = false ;
161- let mut bytes_per_pixel: u8 ;
161+ let mut bytes_per_pixel: u8 ; // Valid values are 1 | 2 | 4 | 8
162162 match bpp {
163163 0 => return err_invalid_bits_allocated,
164164 1 => {
@@ -193,6 +193,7 @@ fn _decode_frame(
193193 // Don't need to check the unwrap as we just checked
194194 // there's enough data in `src`
195195 let header = <& [ u8 ; 64 ] >:: try_from ( & src[ 0 ..64 ] ) . unwrap ( ) ;
196+ // All 15 header offsets, however no guarantee they will be non-zero
196197 let all_offsets: [ u32 ; 15 ] = _parse_header ( header) ;
197198
198199 // First offset must always be 64
@@ -221,13 +222,19 @@ fn _decode_frame(
221222 // Check the samples per pixel is conformant
222223 let spp: u8 = nr_segments / bytes_per_pixel;
223224 match spp {
224- 1 | 3 => { } ,
225+ 1 => { } ,
226+ 3 => {
227+ // Bit packed data must be 1 sample per pixel
228+ match bpp {
229+ 1 => { return err_invalid_nr_samples } ,
230+ _ => { }
231+ }
232+ } ,
225233 _ => return err_invalid_nr_samples
226234 }
227235
228- /*
229- Example
230- -------
236+ /* Example
237+ ----------
231238 RLE encoded data is ordered like this (for 16-bit, 3 sample):
232239 Segment: 1 | 2 | 3 | 4 | 5 | 6
233240 R MSB | R LSB | G MSB | G LSB | B MSB | B LSB
@@ -242,23 +249,6 @@ fn _decode_frame(
242249 MSB LSB MSB LSB ... MSB LSB | MSB LSB MSB LSB ... MSB LSB | ...
243250 */
244251
245- /*
246- Bit-packed data
247- ---------------
248-
249- For bit-packed data (i.e. a *Bits Allocated* of 1), we decode the RLE encoding but
250- leave the bit-packing in place. This means the length of each decoded segment is not
251- equal to the number of pixels but instead the number of pixels / 8, rounded up to the
252- nearest whole integer with the difference being accounted for by padding 0b0 bits.
253-
254- Each decoded segment must have these padding bits removed and the final frame should be
255- the concatenated unpadded segments. Fortunately for bit-packed data there can be at
256- most 3 segments (with a *Samples per Pixel* of 3).
257-
258- Might be a good idea to use bool arrays instead of u8 and implicitly unpack to avoid
259- annoyances with multi-segment padding, then convert to u8 at the end.
260- */
261-
262252 // Decode each segment and place it into the vector
263253 // ------------------------------------------------
264254 // TODO: handle unwrap
@@ -303,57 +293,40 @@ fn _decode_frame(
303293 usize:: from ( bytes_per_pixel) ,
304294 usize:: from ( byte_offset) + so
305295 ) ?;
296+
306297 if len != pps { return err_segment_length }
307298 }
308299 }
309300
310301 return Ok ( frame)
311302 }
312303
313- // Bit-packed data
314- // The number of whole bytes per segment after decoding
315- // TODO: handle unwraps
316- let mut bytes_per_segment = usize:: try_from ( nr_pixels / 8 ) . unwrap ( ) ;
317- match nr_pixels % 8 {
318- 0 => { } ,
319- _ => { bytes_per_segment += 1 ) ; } ,
320- }
321-
322- let mut frame: Vec < u8 > = Vec :: new ( ) ;
323- for idx in 0 ..( offsets. len ( ) - 1 ) { // 0..1 or 0..3
324- // Start and end indices of the segment
325- let start = usize:: try_from ( offsets[ idx] ) . unwrap ( ) ;
326- let end = usize:: try_from ( offsets[ idx + 1 ] ) . unwrap ( ) ;
327- // TODO: match here on the unwrap
328- let segment = _decode_bit_packed_segment (
329- <& [ u8 ] >:: try_from ( & src[ start..end] ) . unwrap ( ) ,
330- usize:: from ( bytes_per_segment) ,
331- ) ?;
332-
333- if segment. len ( ) != bytes_per_segment { return err_segment_length }
334-
335- if spp == 1 { return Ok ( segment) }
304+ /* Bit-packed data
305+ ------------------
306+ For bit-packed data (i.e. a *Bits Allocated* of 1), we decode the RLE encoded data but
307+ leave the bit-packing in place. This means the length of each decoded segment is not
308+ equal to the number of pixels but instead the number of pixels / 8, rounded up to the
309+ nearest whole integer, with the difference being accounted for by 0b0 padding bits.
310+ */
336311
337- frame. extend ( segment) ;
312+ // The expected number of whole bytes per segment after decoding
313+ let mut bytes_per_segment: usize ;
314+ match nr_pixels % 8 {
315+ 0 => { bytes_per_segment = pps / 8 ; } ,
316+ _ => { bytes_per_segment = ( pps + ( 8 - pps % 8 ) ) / 8 ; } ,
338317 }
339318
340- // Multiple samples but byte aligned
341- if nr_pixels % 8 == 0 { return Ok ( frame) }
342-
343- // Multiple samples but not byte aligned
344- // -> need to remove the bit padding between segments
345- // TODO: handle unwraps
346- let mut bv = BitVec :: < _ , Msb0 > :: from_vec ( frame) ;
347- let step = usize:: try_from ( nr_pixels) . unwrap ( ) ;
348- for start in ( step..bv. len ( ) - 1 ) . step_by ( step) {
349- let end = start + ( 8 - usize:: try_from ( nr_pixels % 8 ) . unwrap ( ) ) ;
350- let bv2 = bv. drain ( start..end) ;
351- }
319+ // For bit-packed data we can only have 1 segment.
320+ let start = usize:: try_from ( offsets[ 0 ] ) . unwrap ( ) ;
321+ let end = usize:: try_from ( offsets[ 1 ] ) . unwrap ( ) ;
322+ let segment = _decode_bit_packed_segment (
323+ <& [ u8 ] >:: try_from ( & src[ start..end] ) . unwrap ( ) ,
324+ bytes_per_segment,
325+ ) ?;
352326
353- // Set any trailing bits to 0b0
354- bv. set_uninitialized ( false ) ;
327+ if segment. len ( ) != bytes_per_segment) { return err_segment_length }
355328
356- Ok ( bv . into_vec ( ) )
329+ return Ok ( segment )
357330}
358331
359332
@@ -373,8 +346,7 @@ fn _decode_bit_packed_segment(
373346
374347 let err_eod = Err (
375348 String :: from (
376- "The end of the data was reached before the segment was \
377- completely decoded"
349+ "The end of the data was reached before the segment was completely decoded"
378350 ) . into ( )
379351 ) ;
380352
@@ -625,7 +597,7 @@ fn encode_frame<'py>(
625597 spp : int
626598 The number of samples per pixel, supported values are 1 or 3.
627599 bpp : int
628- The number of bits per pixel, supported values are 8, 16, 32 and 64.
600+ The number of bits per pixel, supported values are 1, 8, 16, 32 and 64.
629601 byteorder : str
630602 Required if `bpp` is greater than 1, '>' if `src` is in big endian byte
631603 order, '<' if little endian.
@@ -651,18 +623,19 @@ fn _encode_frame(
651623 Parameters
652624 ----------
653625 src
654- The data to be RLE encoded, ordered as R1, G1, B1, R2, G2, B2, ... ,
655- Rn, Gn, Bn (i.e. Planar Configuration 0).
626+ The data to be RLE encoded, with multi-sample data ordered as R1, G1, B1,
627+ R2, G2, B2, ..., Rn, Gn, Bn (i.e. Planar Configuration 0).
656628 dst
657629 The vector storing the encoded data.
658630 rows
659631 The number of rows in the data.
660632 cols
661633 The number of columns in the data.
662634 spp
663- The number of samples per pixel, supported values are 1 or 3.
635+ The number of samples per pixel, supported values are 1 or 3. May only be 1 if `bpp`
636+ is 1.
664637 bpp
665- The number of bits per pixel, supported values are 8, 16, 32 and 64.
638+ The number of bits per pixel, supported values are 1, 8, 16, 32 and 64.
666639 byteorder
667640 Required if bpp is greater than 1, '>' if `src` is in big endian byte
668641 order, '<' if little endian.
@@ -696,26 +669,31 @@ fn _encode_frame(
696669 ) ;
697670
698671 // Check 'Samples per Pixel' is either 1 or 3
699- match spp {
700- 1 | 3 => { } ,
701- _ => return err_invalid_nr_samples
702- }
703-
704672 // Check 'Bits Allocated' is 1 or a multiple of 8
673+ // Check 'Samples per Pixel' is 1 if 'Bits Allocated' is 1
705674 let mut is_bit_packed = false ;
706675 let mut bytes_per_pixel: u8 ;
707- match bpp {
708- 0 => return err_invalid_bits_allocated,
676+ match spp {
709677 1 => {
710- is_bit_packed = true ;
711- bytes_per_pixel = 1 ;
712- } ,
713- _ => match bpp % 8 {
714- 0 => {
715- bytes_per_pixel = bpp / 8 ;
716- } ,
717- _ => return err_invalid_bits_allocated
678+ match bpp {
679+ 1 => {
680+ is_bit_packed = true ;
681+ bytes_per_pixel = 1 ;
682+ } ,
683+ 8 | 16 | 32 | 64 => {
684+ bytes_per_pixel = bpp / 8 ;
685+ } ,
686+ _ => { return err_invalid_bits_allocated }
687+ }
718688 }
689+ 3 => {
690+ match bpp {
691+ 1 => { return err_invalid_nr_samples } ,
692+ 8 | 16 | 32 | 64 => { bytes_per_pixel = bpp / 8 ; } ,
693+ _ => { return err_invalid_bits_allocated }
694+ }
695+ } ,
696+ _ => return err_invalid_nr_samples
719697 }
720698
721699 // Check `byteorder` is a valid character
@@ -734,11 +712,17 @@ fn _encode_frame(
734712 let r = usize:: try_from ( rows) . unwrap ( ) ;
735713 let c = usize:: try_from ( cols) . unwrap ( ) ;
736714
737- // FIXME: add support for bit-packed data
715+ let total_pixels = r * c * usize :: from ( spp ) ;
738716 if !is_bit_packed {
739- if src. len ( ) != r * c * usize:: from ( spp * bytes_per_pixel) {
740- return err_invalid_parameters
717+ let total_length = total_pixels * usize:: from ( bytes_per_pixel) ;
718+ if src. len ( ) != total_length { return err_invalid_parameters }
719+ } else {
720+ let mut total_length: usize ;
721+ match total_pixels % 8 {
722+ 0 => { total_length = total_pixels / 8 ; } ,
723+ _ => { total_length = ( total_pixels + ( 8 - total_pixels % 8 ) ) / 8 ; }
741724 }
725+ if src. len ( ) != total_length { return err_invalid_parameters }
742726 }
743727
744728 let nr_segments: u8 = spp * bytes_per_pixel;
@@ -749,10 +733,11 @@ fn _encode_frame(
749733 dst. extend ( u32:: from ( nr_segments) . to_le_bytes ( ) . to_vec ( ) ) ;
750734 dst. extend ( [ 0u8 ; 60 ] . to_vec ( ) ) ;
751735
752- // A vector of the start indexes used when segmenting - default big endian
736+ // A vector of the start indexes used when segmenting
737+ // Start with big-endian ordered pixel sample values
753738 let mut start_indices: Vec < usize > = ( 0 ..usize:: from ( nr_segments) ) . collect ( ) ;
754739 if byteorder != '>' {
755- // `src` has little endian byte ordering
740+ // Typically `src` uses little endian byte ordering
756741 for idx in 0 ..spp {
757742 let s = usize:: from ( idx * bytes_per_pixel) ;
758743 let e = usize:: from ( ( idx + 1 ) * bytes_per_pixel) ;
@@ -761,6 +746,8 @@ fn _encode_frame(
761746 }
762747
763748 // Encode the data and update the RLE header segment offsets
749+ // Segments are ordered from most significant byte to least significant for
750+ // multi-byte values
764751 for idx in 0 ..usize:: from ( nr_segments) {
765752 // Update RLE header: convert current offset to 4x le ordered u8s
766753 let current_offset = ( u32:: try_from ( dst. len ( ) ) . unwrap ( ) ) . to_le_bytes ( ) ;
@@ -769,14 +756,21 @@ fn _encode_frame(
769756 }
770757
771758 // Encode! Note the offset start of the `src` iter
772- let segment: Vec < u8 > = src[ start_indices[ idx] ..]
773- . into_iter ( )
774- . step_by ( usize:: from ( spp * bytes_per_pixel) )
775- . cloned ( )
776- . collect ( ) ;
777-
778- // FIXME: `cols` probably not correct for bit-packed data
779- _encode_segment_from_vector ( segment, dst, cols) ?;
759+ if !is_bit_packed {
760+ let segment: Vec < u8 > = src[ start_indices[ idx] ..]
761+ . into_iter ( )
762+ . step_by ( usize:: from ( spp * bytes_per_pixel) )
763+ . cloned ( )
764+ . collect ( ) ;
765+
766+ _encode_segment_from_vector ( segment, dst, cols) ?;
767+ } else {
768+ // Should only ever be 1 sample per pixel -> 1 segment
769+ // cols is wrong here, should be / 8
770+ // Also the DICOM Standard says each row should be encoded separately,
771+ // what do we do if the number of columns isn't divisble by 8?
772+ _encode_segment_from_vector ( src, dst, cols) ?;
773+ }
780774 }
781775
782776 Ok ( ( ) )
0 commit comments