def test_kwargs_from_ds(self): """Test Encoder.kwargs_from_ds()""" # Note no NumberOfFrames element ds = Dataset() ds.Rows = 10 ds.Columns = 12 ds.SamplesPerPixel = 1 ds.BitsAllocated = 8 ds.BitsStored = 8 ds.PixelRepresentation = 0 ds.PhotometricInterpretation = 'RGB' enc = Encoder(RLELossless) kwargs = enc.kwargs_from_ds(ds) assert 1 == kwargs['number_of_frames'] assert enc._check_kwargs(kwargs) is None # Test conversion of empty *Number of Frames* ds.NumberOfFrames = None kwargs = enc.kwargs_from_ds(ds) assert 1 == kwargs['number_of_frames'] # Test already present *Number of Frames* is unaffected ds.NumberOfFrames = 10 kwargs = enc.kwargs_from_ds(ds) assert 10 == kwargs['number_of_frames'] # Test missing elements del ds.Columns del ds.BitsAllocated msg = ( r"The following required elements are missing from the dataset: " r"'Columns', 'BitsAllocated'") with pytest.raises(AttributeError, match=msg): enc.kwargs_from_ds(ds) # Test VM 0 ds.Columns = None ds.BitsAllocated = None msg = (r"The following required dataset elements have a VM of 0: " r"'Columns', 'BitsAllocated'") with pytest.raises(AttributeError, match=msg): enc.kwargs_from_ds(ds)
class TestEncoder_Preprocess: """Tests for Encoder._preprocess().""" def setup(self): self.e = Encoder(JPEG2000Lossless) self.ds = ds = Dataset() ds.Rows = 1 ds.Columns = 3 ds.SamplesPerPixel = 1 ds.PixelRepresentation = 0 ds.BitsAllocated = 8 ds.BitsStored = 8 ds.NumberOfFrames = 1 ds.PhotometricInterpretation = 'RGB' self.arr_3s = np.asarray([ [[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24]], ], '|u1') assert self.arr_3s.shape == (4, 2, 3) def test_invalid_arr_shape_raises(self): """Test that an array size and dataset mismatch raise exceptions""" # 1D arrays arr = np.asarray((1, 2, 3, 4)) msg = (r"Unable to encode as the shape of the ndarray \(4,\) " r"doesn't match the values for the rows, columns and samples " r"per pixel") kwargs = self.e.kwargs_from_ds(self.ds) assert arr.shape == (4, ) with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) # 2D arrays arr = np.asarray([[1, 2, 3, 4]]) assert arr.shape == (1, 4) msg = r"Unable to encode as the shape of the ndarray \(1, 4\) " with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) self.ds.Rows = 2 self.ds.Columns = 2 self.ds.SamplesPerPixel = 3 arr = np.asarray([[1, 2], [3, 4]]) assert arr.shape == (2, 2) msg = r"Unable to encode as the shape of the ndarray \(2, 2\) " with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) # 3D arrays self.ds.Rows = 3 arr = np.asarray([[[1, 2, 1], [3, 4, 1]]]) assert arr.shape == (1, 2, 3) msg = r"Unable to encode as the shape of the ndarray \(1, 2, 3\) " with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) def test_invalid_arr_dtype_raises(self): """Test an invalid arr dtype raises exception.""" arr = np.asarray(('a', 'b', 'c')) msg = ( r"Unable to encode as the ndarray's dtype '<U1' is not supported") kwargs = self.e.kwargs_from_ds(self.ds) with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) def test_invalid_pixel_representation_raises(self): """Test exception raised if pixel representation/dtype mismatch""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 0 self.ds.Rows = 1 self.ds.Columns = 3 kwargs = self.e.kwargs_from_ds(self.ds) arr = np.asarray([1, 2, 3], dtype='|i1') msg = (r"Unable to encode as the ndarray's dtype 'int8' is not " r"consistent with pixel representation '0' \(unsigned int\)") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) arr = np.asarray([1, 2, 3], dtype='|u1') kwargs['pixel_representation'] = 1 msg = (r"Unable to encode as the ndarray's dtype 'uint8' is not " r"consistent with pixel representation '1' \(signed int\)") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) def test_invalid_bits_allocated_raises(self): """Test exception raised for invalid Bits Allocated""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 0 self.ds.Rows = 1 self.ds.Columns = 3 kwargs = self.e.kwargs_from_ds(self.ds) arr = np.asarray([1, 2, 3], dtype='|u1') kwargs['bits_stored'] = 9 msg = ( r"Unable to encode as the bits stored value is greater than the " r"bits allocated value") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) kwargs['bits_stored'] = 8 kwargs['bits_allocated'] = 9 msg = (r"Unable to encode as a bits allocated value of 9 is not " r"supported \(must be a multiple of 8\)") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) kwargs['bits_allocated'] = 16 msg = (r"Unable to encode as the ndarray's dtype 'uint8' is not " r"consistent with a bits allocated value of 16") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) def test_invalid_samples_per_pixel_raises(self): """Test exception raised spp is invalid""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.SamplesPerPixel = 2 self.ds.PixelRepresentation = 0 self.ds.Rows = 2 self.ds.Columns = 2 kwargs = self.e.kwargs_from_ds(self.ds) arr = np.asarray([1, 2, 3], dtype='|i1') msg = (r"Unable to encode as a samples per pixel value of 2 is not " r"supported \(must be 1 or 3\)") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) arr = np.asarray([[1, 2], [1, 3]], dtype='|i1') kwargs['samples_per_pixel'] = 3 msg = (r"Unable to encode as the shape of the ndarray \(2, 2\) is not " r"consistent with a samples per pixel value of 3") with pytest.raises(ValueError, match=msg): self.e._preprocess(arr, **kwargs) def test_u08_1s(self): """Test processing u8/1s""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 0 self.ds.Rows = 1 self.ds.Columns = 3 # Override the encoding profile validation self.e._uid = None arr = np.asarray([1, 2, 3], dtype='|u1') assert arr.dtype.itemsize == 1 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 3 assert b"\x01\x02\x03" == out def test_u08_3s(self): """Test processing u8/3s""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.PixelRepresentation = 0 self.ds.Rows = 4 self.ds.Columns = 2 self.ds.SamplesPerPixel = 3 # Override the encoding profile validation self.e._uid = None arr = self.arr_3s.astype('|u1') assert arr.dtype.itemsize == 1 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 24 assert out == bytes(range(1, 25)) def test_i08_1s(self): """Test processing i8/1s""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 1 self.ds.Rows = 1 self.ds.Columns = 3 # Override the encoding profile validation self.e._uid = None arr = np.asarray([-128, 0, 127], dtype='|i1') assert arr.dtype.itemsize == 1 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 3 assert out == b"\x80\x00\x7f" def test_i08_3s(self): """Test processing i8/3s""" self.ds.BitsAllocated = 8 self.ds.BitsStored = 8 self.ds.PixelRepresentation = 1 self.ds.Rows = 4 self.ds.Columns = 2 self.ds.SamplesPerPixel = 3 # Override the encoding profile validation self.e._uid = None arr = self.arr_3s.astype('|i1') assert arr.dtype.itemsize == 1 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 24 assert out == bytes(range(1, 25)) def test_u16_1s(self): """Test processing u16/1s""" self.ds.BitsAllocated = 16 self.ds.BitsStored = 16 self.ds.PixelRepresentation = 0 self.ds.Rows = 1 self.ds.Columns = 3 self.ds.SamplesPerPixel = 1 # Override the encoding profile validation self.e._uid = None for dtype in ('>u2', '<u2', '=u2'): arr = np.asarray([1, 2, 3], dtype=dtype) assert arr.dtype.itemsize == 2 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 6 assert out == b"\x01\x00\x02\x00\x03\x00" def test_u16_3s(self): """Test processing u16/3s""" self.ds.BitsAllocated = 16 self.ds.BitsStored = 16 self.ds.SamplesPerPixel = 3 self.ds.PixelRepresentation = 0 self.ds.Rows = 4 self.ds.Columns = 2 ref = b''.join([bytes([b]) + b'\x00' for b in bytes(range(1, 25))]) # Override the encoding profile validation self.e._uid = None for dtype in ('>u2', '<u2', '=u2'): arr = self.arr_3s.astype(dtype) assert arr.dtype.itemsize == 2 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 48 assert out == ref def test_i16_1s(self): """Test processing i16/1s""" self.ds.BitsAllocated = 16 self.ds.BitsStored = 16 self.ds.PixelRepresentation = 1 self.ds.Rows = 1 self.ds.Columns = 3 self.ds.SamplesPerPixel = 1 # Override the encoding profile validation self.e._uid = None for dtype in ('>i2', '<i2', '=i2'): arr = np.asarray([-128, 0, 127], dtype=dtype) assert arr.dtype.itemsize == 2 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 6 assert out == b"\x80\xff\x00\x00\x7f\x00" def test_i16_3s(self): """Test processing i16/3s""" self.ds.BitsAllocated = 16 self.ds.BitsStored = 16 self.ds.SamplesPerPixel = 3 self.ds.PixelRepresentation = 1 self.ds.Rows = 4 self.ds.Columns = 2 ref = b''.join([bytes([b]) + b'\x00' for b in bytes(range(1, 25))]) # Override the encoding profile validation self.e._uid = None for dtype in ('>i2', '<i2', '=i2'): arr = self.arr_3s.astype(dtype) assert arr.dtype.itemsize == 2 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 48 assert out == ref def test_u32_1s(self): """Test processing u32/1s""" self.ds.BitsAllocated = 32 self.ds.BitsStored = 32 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 0 self.ds.Rows = 1 self.ds.Columns = 3 ref = b"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00" # Override the encoding profile validation self.e._uid = None for dtype in ('>u4', '<u4', '=u4'): arr = np.asarray([1, 2, 3], dtype=dtype) assert arr.dtype.itemsize == 4 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 12 assert out == ref def test_u32_3s(self): """Test processing u32/3s""" self.ds.BitsAllocated = 32 self.ds.BitsStored = 32 self.ds.SamplesPerPixel = 3 self.ds.PixelRepresentation = 0 self.ds.Rows = 4 self.ds.Columns = 2 ref = b''.join([bytes([b]) + b'\x00' * 3 for b in bytes(range(1, 25))]) # Override the encoding profile validation self.e._uid = None for dtype in ('>u4', '<u4', '=u4'): arr = self.arr_3s.astype(dtype) assert arr.dtype.itemsize == 4 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 96 assert out == ref def test_i32_1s(self): """Test processing i32/1s""" self.ds.BitsAllocated = 32 self.ds.BitsStored = 32 self.ds.SamplesPerPixel = 1 self.ds.PixelRepresentation = 1 self.ds.Rows = 1 self.ds.Columns = 3 ref = b"\x80\xff\xff\xff\x00\x00\x00\x00\x7f\x00\x00\x00" # Override the encoding profile validation self.e._uid = None for dtype in ('>i4', '<i4', '=i4'): arr = np.asarray([-128, 0, 127], dtype=dtype) assert arr.dtype.itemsize == 4 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 12 assert out == ref def test_i32_3s(self): """Test processing i32/3s""" self.ds.BitsAllocated = 32 self.ds.BitsStored = 32 self.ds.SamplesPerPixel = 3 self.ds.PixelRepresentation = 1 self.ds.Rows = 4 self.ds.Columns = 2 ref = b''.join([bytes([b]) + b'\x00' * 3 for b in bytes(range(1, 25))]) # Override the encoding profile validation self.e._uid = None for dtype in ('>i4', '<i4', '=i4'): arr = self.arr_3s.astype(dtype) assert arr.dtype.itemsize == 4 kwargs = self.e.kwargs_from_ds(self.ds) out = self.e._preprocess(arr, **kwargs) assert len(out) == 96 assert out == ref