Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## main

* fix one-byte overread into struct padding [bgilbert]
* support single-frame DICOM images and allow BitsStored > 8 [tokyovigilante]

## 1.2.0, 09/04/2025

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ int main() {
return 1;
}

printf("NumerOfFrames == %s\n", num_frames);
printf("NumberOfFrames == %s\n", num_frames);

dcm_filehandle_destroy(filehandle);

Expand Down
Binary file added data/test_files/ct_brain_single.dcm
Binary file not shown.
16 changes: 15 additions & 1 deletion src/dicom-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ static bool get_num_frames(DcmError **error,
{
const char *value;
if (!get_tag_str(error, metadata, "NumberOfFrames", &value)) {
return false;
*number_of_frames = 1;
return true;
}

uint32_t num_frames = strtol(value, NULL, 10);
Expand Down Expand Up @@ -742,6 +743,18 @@ static bool set_pixel_description(DcmError **error,
!dcm_element_get_value_integer(error, element, 0, &value)) {
return false;
}
if (value == 1) {
dcm_error_set(error, DCM_ERROR_CODE_INVALID,
"reading frame item failed",
"1-bit pixel storage (Bits Allocated == 1) not implemented");
return false;
}
if (value % 8 != 0) {
dcm_error_set(error, DCM_ERROR_CODE_INVALID,
"reading frame item failed",
"BitsAllocated must be a multiple of 8");
return false;
}
desc->bits_allocated = (uint16_t) value;

element = dcm_dataset_get(error, metadata, 0x00280101);
Expand Down Expand Up @@ -1300,6 +1313,7 @@ bool dcm_filehandle_prepare_read_frame(DcmError **error,
filehandle->offset_table[i] = i *
filehandle->desc.rows *
filehandle->desc.columns *
(filehandle->desc.bits_allocated / 8) *
filehandle->desc.samples_per_pixel;
}

Expand Down
3 changes: 2 additions & 1 deletion src/dicom-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,8 @@ char *dcm_parse_frame(DcmError **error,
return NULL;
}
} else {
*length = desc->rows * desc->columns * desc->samples_per_pixel;
*length = desc->rows * desc->columns * desc->samples_per_pixel *
(desc->bits_allocated / 8);
}

char *value = DCM_MALLOC(error, *length);
Expand Down
51 changes: 51 additions & 0 deletions tests/check_dicom.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,45 @@ START_TEST(test_file_sm_image_file_meta_memory)
}
END_TEST

START_TEST(test_file_ct_brain_single)
{
const uint32_t frame_number = 1;
const uint32_t frame_length = 524288; // 512 x 512 x 16 bits stored

char *file_path = fixture_path("data/test_files/ct_brain_single.dcm");
DcmFilehandle *filehandle =
dcm_filehandle_create_from_file(NULL, file_path);
free(file_path);
ck_assert_ptr_nonnull(filehandle);

const DcmDataSet *metadata =
dcm_filehandle_get_metadata_subset(NULL, filehandle);
ck_assert_ptr_nonnull(metadata);
ck_assert_ptr_null(dcm_dataset_get(NULL, metadata, 0x00280008)); // NumberOfFrames should not be present

ck_assert_int_ne(dcm_filehandle_prepare_read_frame(NULL, filehandle), 0);

DcmFrame *frame = dcm_filehandle_read_frame(NULL,
filehandle,
frame_number);
ck_assert_uint_eq(dcm_frame_get_number(frame), frame_number);
ck_assert_uint_eq(dcm_frame_get_rows(frame), 512);
ck_assert_uint_eq(dcm_frame_get_columns(frame), 512);
ck_assert_uint_eq(dcm_frame_get_samples_per_pixel(frame), 1);
ck_assert_uint_eq(dcm_frame_get_bits_allocated(frame), 16);
ck_assert_uint_eq(dcm_frame_get_bits_stored(frame), 16);
ck_assert_uint_eq(dcm_frame_get_high_bit(frame), 15);
ck_assert_uint_eq(dcm_frame_get_pixel_representation(frame), 1);
ck_assert_uint_eq(dcm_frame_get_planar_configuration(frame), 0);
ck_assert_str_eq(dcm_frame_get_photometric_interpretation(frame), "MONOCHROME2");
ck_assert_str_eq(dcm_frame_get_transfer_syntax_uid(frame),
"1.2.840.10008.1.2.1");
ck_assert_uint_eq(dcm_frame_get_length(frame), frame_length);

dcm_frame_destroy(frame);
dcm_filehandle_destroy(filehandle);
}
END_TEST

static Suite *create_main_suite(void)
{
Expand Down Expand Up @@ -846,12 +885,24 @@ static Suite *create_file_suite(void)
return suite;
}

static Suite *create_single_frame_suite(void)
{
Suite *suite = suite_create("single_frame");

TCase *frame_case = tcase_create("ct_brain_frame");
tcase_add_test(frame_case, test_file_ct_brain_single);
suite_add_tcase(suite, frame_case);

return suite;
}


int main(void)
{
SRunner *runner = srunner_create(create_main_suite());
srunner_add_suite(runner, create_data_suite());
srunner_add_suite(runner, create_file_suite());
srunner_add_suite(runner, create_single_frame_suite());
srunner_run_all(runner, CK_VERBOSE);
int number_failed = srunner_ntests_failed(runner);
srunner_free(runner);
Expand Down
Loading