diff --git a/src/highdicom/io.py b/src/highdicom/io.py index 3a03d847..bb44610c 100644 --- a/src/highdicom/io.py +++ b/src/highdicom/io.py @@ -492,6 +492,12 @@ def _bytes_per_frame_uncompressed(self) -> int: # are packed into 12.5 -> 13 bytes return n_pixels // 8 + (n_pixels % 8 > 0) else: + if self.metadata.PhotometricInterpretation == 'YBR_FULL_422': + # Account for subsampling of CB and CR when calculating + # expected number of samples + # See https://dicom.nema.org/medical/dicom/current/output/chtml + # /part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2 + n_pixels = self.metadata.Rows * self.metadata.Columns * 2 return n_pixels * bits_allocated // 8 def close(self) -> None: diff --git a/tests/test_io.py b/tests/test_io.py index 3df017e4..07d2504c 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -157,6 +157,25 @@ def test_read_multi_frame_seg_image_sm_dots_bitpacked(self): ) np.testing.assert_array_equal(frame, pixel_array[i, ...]) + def test_read_ybr_422_native(self): + # Reading a frame using YBR_422 photometric interpretation and no + # compression + filename = str(get_testdata_file('SC_ybr_full_422_uncompressed.dcm')) + dataset = dcmread(filename) + pixel_array = dataset.pixel_array + with ImageFileReader(filename) as reader: + assert reader.number_of_frames == 1 + frame = reader.read_frame(0, correct_color=False) + assert isinstance(frame, np.ndarray) + assert frame.ndim == 3 + assert frame.dtype == np.uint8 + assert frame.shape == ( + reader.metadata.Rows, + reader.metadata.Columns, + reader.metadata.SamplesPerPixel, + ) + np.testing.assert_array_equal(frame, pixel_array) + def test_read_single_frame_ct_image_dicom_bytes_io(self): filename = str(self._test_dir.joinpath("ct_image.dcm")) dcm = DicomBytesIO(open(filename, "rb").read())