From 24ddadd76bf51b3af8a53a91754316d6df7c025a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 4 Jun 2026 14:29:24 +0100 Subject: [PATCH 1/5] add dcm_filehandle_find_frame_number() - deprecate dcm_filehandle_get_frame_number() - bump version to 1.3 --- CHANGELOG.md | 5 ++++ include/dicom/dicom.h | 32 +++++++++++++++++++- meson.build | 6 ++-- src/dicom-file.c | 68 +++++++++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc802df..c823bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.3.0, date tbd + +* add dcm_filehandle_find_frame_number(), deprecate + dcm_filehandle_get_frame_number() [jcupitt] + ## 1.2.1, 28/04/2026 * add support for encapsulated pixel data reading [weanti] diff --git a/include/dicom/dicom.h b/include/dicom/dicom.h index 8dedf0d..887cb04 100644 --- a/include/dicom/dicom.h +++ b/include/dicom/dicom.h @@ -1777,20 +1777,50 @@ DcmFrame *dcm_filehandle_read_frame(DcmError **error, DcmFilehandle *filehandle, uint32_t frame_number); +/** + * Find the frame number at a position. + * + * Given a tile row and column, find the number of the frame that should be + * displayed at that position, taking into account any frame-positioning + * metadata. + * + * If no frame is available at that position, set frame_number to 0. + * + * :param error: Pointer to error object + * :param filehandle: File + * :param column: Column number, from 0 + * :param row: Row number, from 0 + * :param frame_number: Return one-based frame number, or 0 for no frame + * + * :return: true on success, false for error + */ +DCM_EXTERN +bool dcm_filehandle_find_frame_number(DcmError **error, + DcmFilehandle *filehandle, + uint32_t column, + uint32_t row, + uint32_t *frame_number); + /** * Get the frame number at a position. * + * Note: this function is deprecated, please use + * :c:func:`dcm_filehandle_find_frame_number()` instead. + * * Given a tile row and column, get the number of the frame that should be * displayed at that position, taking into account any frame-positioning * metadata. * + * If no frame is available, return false and set the error + * :c:enum:`DCM_ERROR_CODE_MISSING_FRAME`. + * * :param error: Pointer to error object * :param filehandle: File * :param column: Column number, from 0 * :param row: Row number, from 0 * :param frame_number: Return one-based frame number * - * :return: true on success, false for no frame available + * :return: true on success, false for error or no frame available */ DCM_EXTERN bool dcm_filehandle_get_frame_number(DcmError **error, diff --git a/meson.build b/meson.build index 33ec4f1..ad0bef8 100644 --- a/meson.build +++ b/meson.build @@ -10,7 +10,7 @@ project( ], license : 'MIT', meson_version : '>=0.55', - version : '1.2.1', + version : '1.3.0', ) if not meson.is_subproject() meson.add_dist_script('scripts/dist.py') @@ -34,8 +34,8 @@ endif # 2. Backward-compatible ABI change: bump minor, reset patch # 3. Other, eg. bugfix: bump patch abi_version_major = 1 -abi_version_minor = 2 -abi_version_patch = 1 +abi_version_minor = 3 +abi_version_patch = 0 abi_version = '@0@.@1@.@2@'.format( abi_version_major, diff --git a/src/dicom-file.c b/src/dicom-file.c index 59d3f4f..5e10049 100644 --- a/src/dicom-file.c +++ b/src/dicom-file.c @@ -1405,13 +1405,13 @@ DcmFrame *dcm_filehandle_read_frame(DcmError **error, } -bool dcm_filehandle_get_frame_number(DcmError **error, - DcmFilehandle *filehandle, - uint32_t column, - uint32_t row, - uint32_t *frame_number) +bool dcm_filehandle_find_frame_number(DcmError **error, + DcmFilehandle *filehandle, + uint32_t column, + uint32_t row, + uint32_t *frame_number) { - dcm_log_debug("Get frame number at (%u, %u)", column, row); + dcm_log_debug("Find frame number for tile (%u, %u)", column, row); if (!dcm_filehandle_prepare_read_frame(error, filehandle)) { return false; @@ -1431,25 +1431,48 @@ bool dcm_filehandle_get_frame_number(DcmError **error, if (filehandle->layout == DCM_LAYOUT_SPARSE) { index = filehandle->frame_index[index]; if (index == 0xffffffff) { - dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, - "no frame", - "no frame at position (%u, %u)", column, row); - return false; + // missing frame + *frame_number = 0; + } + else { + *frame_number = (uint32_t) (index + 1); } } else { // subtract the start of this file, for catenation support index -= filehandle->frame_offset; if (index < 0 || index >= (int64_t) filehandle->num_frames) { - dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, - "no frame", - "no frame at position (%u, %u)", column, row); - return false; + // missing frame + *frame_number = 0; + } + else { + *frame_number = (uint32_t) (index + 1); } } - // frame numbers are from 1, and are always uint32 - if (frame_number) - *frame_number = (uint32_t) (index + 1); + return true; +} + + +/* Deprecated function, only here for compatibility with libdicom 1.2 and + * earlier. + */ +bool dcm_filehandle_get_frame_number(DcmError **error, + DcmFilehandle *filehandle, + uint32_t column, + uint32_t row, + uint32_t *frame_number) +{ + if (!dcm_filehandle_find_frame_number(error, filehandle, + column, row, frame_number)) { + return false; + } + + if (*frame_number == 0) { + dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, + "no frame", + "no frame at position (%u, %u)", column, row); + return false; + } return true; } @@ -1463,11 +1486,18 @@ DcmFrame *dcm_filehandle_read_frame_position(DcmError **error, dcm_log_debug("Read frame position (%u, %u)", column, row); uint32_t frame_number; - if (!dcm_filehandle_get_frame_number(error, - filehandle, column, row, &frame_number)) { + if (!dcm_filehandle_find_frame_number(error, filehandle, + column, row, &frame_number)) { return NULL; } + if (frame_number == 0) { + dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, + "no frame", + "no frame at position (%u, %u)", column, row); + return false; + } + return dcm_filehandle_read_frame(error, filehandle, frame_number); } From 816a9570906061b52dbcc5c5e5c45a4b97c25b84 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 5 Jun 2026 17:43:50 +0100 Subject: [PATCH 2/5] address review comments and add DCM_DEPRECATED() macro --- CHANGELOG.md | 1 + include/dicom/dicom.h | 21 ++++++++++++++------- src/dicom-file.c | 15 +++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c823bcd..3d1ebb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * add dcm_filehandle_find_frame_number(), deprecate dcm_filehandle_get_frame_number() [jcupitt] +* add DCM_DEPRECATED() macro [jcupitt] ## 1.2.1, 28/04/2026 diff --git a/include/dicom/dicom.h b/include/dicom/dicom.h index 887cb04..53983ab 100644 --- a/include/dicom/dicom.h +++ b/include/dicom/dicom.h @@ -20,6 +20,16 @@ #define DCM_EXTERN __attribute__((visibility("default"))) extern #endif +#ifndef BUILDING_LIBDICOM +#if defined(_MSC_VER) +#define DCM_DEPRECATED(MSG) __declspec(deprecated(MSG)) +#elif defined(__GNUC__) +#define DCM_DEPRECATED(MSG) __attribute__((deprecated(MSG))) +#endif +#else +#define DCM_DEPRECATED(MSG) +#endif + /** * Maximum number of characters in values with Value Representation AE. */ @@ -124,13 +134,7 @@ typedef struct _DcmSequence DcmSequence; * .. deprecated:: 1.1.0 * Calling this function is no longer necessary. */ -#ifndef BUILDING_LIBDICOM -#if defined(_MSC_VER) -__declspec(deprecated("dcm_init() no longer needs to be called")) -#elif defined(__GNUC__) -__attribute__((deprecated("dcm_init() no longer needs to be called"))) -#endif -#endif +DCM_DEPRECATED("dcm_init() no longer needs to be called") DCM_EXTERN void dcm_init(void); @@ -1786,6 +1790,8 @@ DcmFrame *dcm_filehandle_read_frame(DcmError **error, * * If no frame is available at that position, set frame_number to 0. * + * frame_number may be NULL. + * * :param error: Pointer to error object * :param filehandle: File * :param column: Column number, from 0 @@ -1822,6 +1828,7 @@ bool dcm_filehandle_find_frame_number(DcmError **error, * * :return: true on success, false for error or no frame available */ +DCM_DEPRECATED("deprecated for dcm_filehandle_find_frame_number()") DCM_EXTERN bool dcm_filehandle_get_frame_number(DcmError **error, DcmFilehandle *filehandle, diff --git a/src/dicom-file.c b/src/dicom-file.c index 5e10049..afcf6d2 100644 --- a/src/dicom-file.c +++ b/src/dicom-file.c @@ -1432,20 +1432,24 @@ bool dcm_filehandle_find_frame_number(DcmError **error, index = filehandle->frame_index[index]; if (index == 0xffffffff) { // missing frame - *frame_number = 0; + if (frame_number) + *frame_number = 0; } else { - *frame_number = (uint32_t) (index + 1); + if (frame_number) + *frame_number = (uint32_t) (index + 1); } } else { // subtract the start of this file, for catenation support index -= filehandle->frame_offset; if (index < 0 || index >= (int64_t) filehandle->num_frames) { // missing frame - *frame_number = 0; + if (frame_number) + *frame_number = 0; } else { - *frame_number = (uint32_t) (index + 1); + if (frame_number) + *frame_number = (uint32_t) (index + 1); } } @@ -1453,8 +1457,7 @@ bool dcm_filehandle_find_frame_number(DcmError **error, } -/* Deprecated function, only here for compatibility with libdicom 1.2 and - * earlier. +/* Deprecated function, only here for compatibility with libdicom 1.2. */ bool dcm_filehandle_get_frame_number(DcmError **error, DcmFilehandle *filehandle, From 45eeacf147f58ce06ef8ca8278d06e411853eddd Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 5 Jun 2026 19:51:47 +0100 Subject: [PATCH 3/5] second review round comments --- CHANGELOG.md | 1 + src/dicom-file.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d1ebb8..81e66af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * add dcm_filehandle_find_frame_number(), deprecate dcm_filehandle_get_frame_number() [jcupitt] * add DCM_DEPRECATED() macro [jcupitt] +* don't format ignored errors for debug log if logging is disabled [bgilbert] ## 1.2.1, 28/04/2026 diff --git a/src/dicom-file.c b/src/dicom-file.c index afcf6d2..1d012a8 100644 --- a/src/dicom-file.c +++ b/src/dicom-file.c @@ -1470,7 +1470,8 @@ bool dcm_filehandle_get_frame_number(DcmError **error, return false; } - if (*frame_number == 0) { + if (frame_number && + *frame_number == 0) { dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, "no frame", "no frame at position (%u, %u)", column, row); From dc27379326ba26c657c70864d216429622b4a5c4 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 5 Jun 2026 20:40:16 +0100 Subject: [PATCH 4/5] address review comments --- include/dicom/dicom.h | 4 ++-- src/dicom-file.c | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/dicom/dicom.h b/include/dicom/dicom.h index 53983ab..92534d8 100644 --- a/include/dicom/dicom.h +++ b/include/dicom/dicom.h @@ -1790,8 +1790,6 @@ DcmFrame *dcm_filehandle_read_frame(DcmError **error, * * If no frame is available at that position, set frame_number to 0. * - * frame_number may be NULL. - * * :param error: Pointer to error object * :param filehandle: File * :param column: Column number, from 0 @@ -1820,6 +1818,8 @@ bool dcm_filehandle_find_frame_number(DcmError **error, * If no frame is available, return false and set the error * :c:enum:`DCM_ERROR_CODE_MISSING_FRAME`. * + * frame_number may be NULL. + * * :param error: Pointer to error object * :param filehandle: File * :param column: Column number, from 0 diff --git a/src/dicom-file.c b/src/dicom-file.c index 1d012a8..645fbb2 100644 --- a/src/dicom-file.c +++ b/src/dicom-file.c @@ -1432,24 +1432,20 @@ bool dcm_filehandle_find_frame_number(DcmError **error, index = filehandle->frame_index[index]; if (index == 0xffffffff) { // missing frame - if (frame_number) - *frame_number = 0; + *frame_number = 0; } else { - if (frame_number) - *frame_number = (uint32_t) (index + 1); + *frame_number = (uint32_t) (index + 1); } } else { // subtract the start of this file, for catenation support index -= filehandle->frame_offset; if (index < 0 || index >= (int64_t) filehandle->num_frames) { // missing frame - if (frame_number) - *frame_number = 0; + *frame_number = 0; } else { - if (frame_number) - *frame_number = (uint32_t) (index + 1); + *frame_number = (uint32_t) (index + 1); } } @@ -1465,19 +1461,22 @@ bool dcm_filehandle_get_frame_number(DcmError **error, uint32_t row, uint32_t *frame_number) { - if (!dcm_filehandle_find_frame_number(error, filehandle, - column, row, frame_number)) { + uint32_t n; + + if (!dcm_filehandle_find_frame_number(error, filehandle, column, row, &n)) { return false; } - if (frame_number && - *frame_number == 0) { + if (n == 0) { dcm_error_set(error, DCM_ERROR_CODE_MISSING_FRAME, "no frame", "no frame at position (%u, %u)", column, row); return false; } + if (*frame_number) + *frame_number = n; + return true; } From ed78426f4f63a03660306ca221cfbabedef06698 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 5 Jun 2026 21:08:58 +0100 Subject: [PATCH 5/5] ooops! --- src/dicom-file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dicom-file.c b/src/dicom-file.c index 645fbb2..48647f3 100644 --- a/src/dicom-file.c +++ b/src/dicom-file.c @@ -1474,7 +1474,7 @@ bool dcm_filehandle_get_frame_number(DcmError **error, return false; } - if (*frame_number) + if (frame_number) *frame_number = n; return true;