@@ -69,19 +69,19 @@ def as_bytes(self, offsets):
6969
7070 def test_bits_allocated_zero_raises (self ):
7171 """Test exception raised for BitsAllocated 0."""
72- msg = r"The \(0028,0100\) 'Bits Allocated' value must be 8, 16, 32 or 64"
72+ msg = r"The \(0028,0100\) 'Bits Allocated' value must be 1, 8, 16, 32 or 64"
7373 with pytest .raises (ValueError , match = msg ):
7474 decode_frame (b"\x00 \x00 \x00 \x00 " , 1 , 0 , "<" )
7575
7676 def test_bits_allocated_not_octal_raises (self ):
77- """Test exception raised for BitsAllocated not a multiple of 8."""
78- msg = r"The \(0028,0100\) 'Bits Allocated' value must be 8, 16, 32 or 64"
77+ """Test exception raised for BitsAllocated not 1 or a multiple of 8."""
78+ msg = r"The \(0028,0100\) 'Bits Allocated' value must be 1, 8, 16, 32 or 64"
7979 with pytest .raises (ValueError , match = msg ):
8080 decode_frame (b"\x00 \x00 \x00 \x00 " , 1 , 12 , "<" )
8181
8282 def test_bits_allocated_large_raises (self ):
8383 """Test exception raised for BitsAllocated greater than 64."""
84- msg = r"The \(0028,0100\) 'Bits Allocated' value must be 8, 16, 32 or 64"
84+ msg = r"The \(0028,0100\) 'Bits Allocated' value must be 1, 8, 16, 32 or 64"
8585 with pytest .raises (ValueError , match = msg ):
8686 decode_frame (b"\x00 \x00 \x00 \x00 " , 1 , 72 , "<" )
8787
@@ -357,6 +357,114 @@ def test_u32_3s(self):
357357 assert [4294967295 , 16777216 , 65536 , 256 , 1 , 0 ] == arr [6 :12 ].tolist ()
358358 assert [1 , 16777216 , 65536 , 256 , 1 , 4294967294 ] == arr [12 :].tolist ()
359359
360+ def test_u8_1s_bs1 (self ):
361+ """Test decoding bit packed 1 sample/px."""
362+ header = b"\x01 \x00 \x00 \x00 \x40 \x00 \x00 \x00 "
363+ header += (64 - len (header )) * b"\x00 "
364+ # 0, 64, 128, 160, 192, 255
365+ data = b"\x05 \x00 \x40 \x80 \xA0 \xC0 \xFF "
366+ # Big endian
367+ # 48 px - byte aligned in 6 bytes
368+ decoded = decode_frame (header + data , 6 * 8 , 1 , ">" )
369+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
370+ assert [0 , 64 , 128 , 160 , 192 , 255 ] == arr .tolist ()
371+
372+ # 37 px -> 5 bytes
373+ decoded = decode_frame (header + data , 4 * 8 + 5 , 1 , ">" )
374+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
375+ assert [0 , 64 , 128 , 160 , 192 ] == arr .tolist ()
376+
377+ # 2 px -> 1 byte
378+ decoded = decode_frame (header + data , 2 , 1 , ">" )
379+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
380+ assert [0 ] == arr .tolist ()
381+
382+ # Little-endian
383+ decoded = decode_frame (header + data , 6 * 8 , 1 , "<" )
384+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
385+ assert [0 , 64 , 128 , 160 , 192 , 255 ] == arr .tolist ()
386+
387+ decoded = decode_frame (header + data , 4 * 8 + 5 , 1 , "<" )
388+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
389+ assert [0 , 64 , 128 , 160 , 192 ] == arr .tolist ()
390+
391+ decoded = decode_frame (header + data , 2 , 1 , "<" )
392+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
393+ assert [0 ] == arr .tolist ()
394+
395+ def test_u8_3s_bs1 (self ):
396+ """Test decoding bit packed 3 sample/px."""
397+ header = (
398+ b"\x03 \x00 \x00 \x00 " # 3 segments
399+ b"\x40 \x00 \x00 \x00 " # 64
400+ b"\x47 \x00 \x00 \x00 " # 71
401+ b"\x4E \x00 \x00 \x00 " # 78
402+ )
403+ header += (64 - len (header )) * b"\x00 "
404+ # 0, 64, 128, 160, 192, 255
405+ data = (
406+ b"\x05 \x00 \x40 \x80 \xA0 \xC0 \xFF " # R
407+ b"\x05 \x7F \xC0 \x80 \x40 \x00 \xFF " # B
408+ b"\x05 \x01 \x40 \x80 \xA0 \xC0 \xFE " # G
409+ )
410+ # 48 px - byte aligned in 18 bytes
411+ decoded = decode_frame (header + data , 6 * 8 , 1 , "<" )
412+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
413+ # Ordered all R, all G, all B
414+ assert [0 , 64 , 128 , 160 , 192 , 255 ] == arr [:6 ].tolist ()
415+ assert [127 , 192 , 128 , 64 , 0 , 255 ] == arr [6 :12 ].tolist ()
416+ assert [1 , 64 , 128 , 160 , 192 , 254 ] == arr [12 :].tolist ()
417+
418+ # 47 px - non-byte aligned in 18 bytes
419+ decoded = decode_frame (header + data , 6 * 8 - 1 , 1 , "<" )
420+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
421+ # Boundaries are 47 | 94 | 141
422+ # v removed
423+ # 255 | 127: 0b[1111_111x 0b0]111_1111 -> 0b1111_1110
424+ assert [0 , 64 , 128 , 160 , 192 , 254 ] == arr [:6 ].tolist ()
425+ # Left shift values by 1 bit
426+ # 127 | 192: 0b0[111_1111 0b1]100_0000 -> 0b1111_1111
427+ # 192 | 128: 0b1[100_0000 0b1]000_0000 -> 0b1000_0001
428+ # 128 | 64: 0b1[000_0000 0b0]100_0000 -> 0b0000_0000
429+ # 64 | 0: 0b0[100_0000 0b0]000_0000 -> 0b1000_0000
430+ # 0 | 255: 0b0[000_0000 0b1]111_1111 -> 0b0000_0001
431+ # v removed
432+ # 255 | 1: 0b1[111_111x 0b00]00_0001 -> 0b1111_1100
433+ assert [255 , 129 , 0 , 128 , 1 , 252 ] == arr [6 :12 ].tolist ()
434+ # Left shift values by 2 bits
435+ # 1 | 64: 0b00[00_0001 0b01]00_0000 -> 0b0000_0101
436+ # 64 | 128: 0b01[00_0000 0b10]00_0000 -> 0b0000_0010
437+ # 128 | 160: 0b10[00_0000 0b10]10_0000 -> 0b0000_0010
438+ # 160 | 192: 0b10[10_0000 0b11]00_0000 -> 0b1000_0011
439+ # 192 | 254: 0b11[00_0000 0b11]11_1110 -> 0b0000_0011
440+ # v removed
441+ # 254 | x: 0b11[11_111x -> 0b1111_1000
442+ assert [5 , 2 , 2 , 131 , 3 , 248 ] == arr [12 :].tolist ()
443+
444+ # 41 px - non-byte aligned in 16 bytes
445+ decoded = decode_frame (header + data , 5 * 8 + 1 , 1 , "<" )
446+ arr = np .frombuffer (decoded , np .dtype ("uint8" ))
447+ # Boundaries are 48 | 96 | 144 -> 41 | 82 | 123
448+ # vvv vvvv removed
449+ # 255 | 255: 0b[1xxx_xxxx 0b0111_111]1 -> 0b1011_1111
450+ assert [0 , 64 , 128 , 160 , 192 , 191 ] == arr [:6 ].tolist ()
451+ # Left shift values by 7 bits
452+ # 255 | 192: 0b1111_111[1 0b1100_000]0 -> 0b1110_0000
453+ # 192 | 128: 0b1100_000[0 0b1000_000]0 -> 0b0100_0000
454+ # 128 | 64: 0b1000_000[0 0b0100_000]0 -> 0b0010_0000
455+ # 64 | 0: 0b0100_000[0 0b0000_000]0 -> 0b0000_0000
456+ # vvv vvvv removed
457+ # 0 | 255 | 1: 0b0000_000[0 0b1xxx_xxxx 0b0000_00]01 -> 0b0100_0000
458+ assert [224 , 64 , 32 , 0 , 64 ] == arr [6 :11 ].tolist ()
459+ # Left shift values by 14 bits
460+ # 1 | 64: 0b0000_00[01 0b0100_00]00 -> 0b0101_0000
461+ # 64 | 128: 0b0100_00[00 0b1000_00]00 -> 0b0010_0000
462+ # 128 | 160: 0b1000_00[00 0b1010_00]00 -> 0b0010_1000
463+ # 160 | 192: 0b1010_00[00 0b1100_00]00 -> 0b0011_0000
464+ # vvv vvvv removed
465+ # 192 | 254: 0b1100_[00 0b1]xxx_xxxx -> 0b0010_0000
466+ assert [80 , 32 , 40 , 48 , 32 ] == arr [11 :].tolist ()
467+
360468
361469@pytest .mark .skipif (not HAVE_PYDICOM , reason = "No pydicom" )
362470class TestDecodeFrame_Datasets :
0 commit comments