Skip to content

Commit be2086b

Browse files
authored
Revise sparse mode (#65)
* revise sparse mode again We were not distinguishing between frames and tiles carefully enough. See openslide/openslide#484
1 parent 298694b commit be2086b

File tree

1 file changed

+44
-34
lines changed

1 file changed

+44
-34
lines changed

src/dicom-file.c

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#define strdup(v) _strdup(v)
1313
#endif
1414

15-
#include <assert.h>
1615
#include <ctype.h>
1716
#include <stdbool.h>
1817
#include <stdlib.h>
@@ -51,19 +50,26 @@ struct _DcmFilehandle {
5150
// image properties we need to track
5251
uint32_t frame_width;
5352
uint32_t frame_height;
54-
uint32_t frames_across;
5553
uint32_t num_frames;
5654
struct PixelDescription desc;
5755
DcmLayout layout;
5856

59-
// both zero-indexed and length num_frames
60-
uint32_t *frame_index;
57+
// zero-indexed and length num_frames
6158
int64_t *offset_table;
6259

60+
// frames form a grid of tiles, there can be more tiles than frames in
61+
// sparse mode
62+
uint32_t tiles_across;
63+
uint32_t tiles_down;
64+
uint32_t num_tiles;
65+
66+
// zero-indexed and of length num_tiles
67+
uint32_t *frame_index;
68+
6369
// the last top level tag the scanner saw
6470
uint32_t last_tag;
6571

66-
// used to count frames as we scan perframefunctionalgroup
72+
// used to count frames as we scan per frame functional group sequence
6773
uint32_t frame_number;
6874
int32_t column_position;
6975
int32_t row_position;
@@ -320,11 +326,13 @@ static bool get_frame_size(DcmError **error,
320326
}
321327

322328

323-
static bool get_frames_across(DcmError **error,
324-
const DcmDataSet *metadata,
325-
uint32_t *frames_across)
329+
static bool get_tiles(DcmError **error,
330+
const DcmDataSet *metadata,
331+
uint32_t *tiles_across,
332+
uint32_t *tiles_down)
326333
{
327334
int64_t width;
335+
int64_t height;
328336
uint32_t frame_width;
329337
uint32_t frame_height;
330338

@@ -337,7 +345,13 @@ static bool get_frames_across(DcmError **error,
337345
width = frame_width;
338346
(void) get_tag_int(NULL, metadata, "TotalPixelMatrixColumns", &width);
339347

340-
*frames_across = width / frame_width + !!(width % frame_width);
348+
// TotalPixelMatrixColumns is optional and defaults to Columns, ie. one
349+
// frame across
350+
height = frame_width;
351+
(void) get_tag_int(NULL, metadata, "TotalPixelMatrixRows", &height);
352+
353+
*tiles_across = width / frame_width + !!(width % frame_width);
354+
*tiles_down = height / frame_height + !!(height % frame_height);
341355

342356
return true;
343357
}
@@ -819,17 +833,20 @@ const DcmDataSet *dcm_filehandle_get_metadata_subset(DcmError **error,
819833
meta,
820834
&filehandle->frame_width,
821835
&filehandle->frame_height) ||
822-
!get_frames_across(error, meta, &filehandle->frames_across) ||
823836
!get_num_frames(error, meta, &filehandle->num_frames) ||
837+
!get_tiles(error, meta,
838+
&filehandle->tiles_across, &filehandle->tiles_down) ||
824839
!set_pixel_description(error, meta, &filehandle->desc)) {
825840
dcm_dataset_destroy(meta);
826841
return false;
827842
}
843+
filehandle->num_tiles = filehandle->tiles_across *
844+
filehandle->tiles_down;
828845

829846
// we support sparse and full frame layout, defaulting to full if
830847
// no type is specified
831848
//
832-
// we flip to SPARSE if there's a PerFrameFunctionalGroupsSequence
849+
// we flip to SPARSE if there's a per frame functional group sequence
833850
// containing frame positions, see below
834851
const char *type;
835852
if (get_tag_str(NULL, meta, "DimensionOrganizationType", &type)) {
@@ -886,12 +903,12 @@ static bool parse_frame_index_sequence_end(DcmError **error,
886903

887904
DcmFilehandle *filehandle = (DcmFilehandle *) client;
888905

889-
// have we seen a valid pair of frame positions
906+
// have we seen a valid pair of tile positions
890907
if (tag == TAG_PLANE_POSITION_SLIDE_SEQUENCE &&
891908
filehandle->column_position != -1 &&
892909
filehandle->row_position != -1) {
893-
// we don't support fractional frame positioning ... they must be
894-
// exactly aligned on frame boundaries
910+
// we don't support fractional tile positioning ... they must be
911+
// exactly aligned on tile boundaries
895912
if ((filehandle->column_position - 1) % filehandle->frame_width != 0 ||
896913
(filehandle->row_position - 1) % filehandle->frame_height != 0) {
897914
dcm_error_set(error, DCM_ERROR_CODE_PARSE,
@@ -900,15 +917,15 @@ static bool parse_frame_index_sequence_end(DcmError **error,
900917
return false;
901918
}
902919

903-
// map the position of the frame to the frame number
920+
// map the position of the tile to the frame number
904921
int col = (filehandle->column_position - 1) / filehandle->frame_width;
905922
int row = (filehandle->row_position - 1) / filehandle->frame_height;
906-
uint32_t index = col + row * filehandle->frames_across;
907-
if (index < filehandle->num_frames) {
923+
uint32_t index = col + row * filehandle->tiles_across;
924+
if (index < filehandle->num_tiles) {
908925
filehandle->frame_index[index] = filehandle->frame_number;
909926

910-
// we have something meaningful in PerFrameFunctionalGroupsSequence,
911-
// so we must display in SPARSE mode
927+
// we have something meaningful in per frame functional group
928+
// sequence, so we must display in SPARSE mode
912929
filehandle->layout = DCM_LAYOUT_SPARSE;
913930
}
914931

@@ -984,14 +1001,14 @@ static bool read_frame_index(DcmError **error,
9841001
};
9851002

9861003
filehandle->frame_index = DCM_NEW_ARRAY(error,
987-
filehandle->num_frames,
1004+
filehandle->num_tiles,
9881005
uint32_t);
9891006
if (filehandle->frame_index == NULL) {
9901007
return false;
9911008
}
9921009

9931010
// we may not have all frames ... set to missing initially
994-
for (uint32_t i = 0; i < filehandle->num_frames; i++) {
1011+
for (uint32_t i = 0; i < filehandle->num_tiles; i++) {
9951012
filehandle->frame_index[i] = 0xffffffff;
9961013
}
9971014

@@ -1204,24 +1221,17 @@ DcmFrame *dcm_filehandle_read_frame_position(DcmError **error,
12041221
return NULL;
12051222
}
12061223

1207-
if (column >= filehandle->frames_across) {
1208-
dcm_error_set(error, DCM_ERROR_CODE_PARSE,
1209-
"Reading Frame position failed",
1210-
"Column must be less than %u",
1211-
filehandle->frames_across);
1212-
return NULL;
1213-
}
1214-
1215-
uint32_t index = column + row * filehandle->frames_across;
1216-
1217-
if (index >= filehandle->num_frames) {
1224+
if (column >= filehandle->tiles_across ||
1225+
row >= filehandle->tiles_down) {
12181226
dcm_error_set(error, DCM_ERROR_CODE_PARSE,
12191227
"Reading Frame position failed",
1220-
"Row must be less than %u",
1221-
filehandle->num_frames / filehandle->frames_across);
1228+
"Column and row must be less than %u, %u",
1229+
filehandle->tiles_across,
1230+
filehandle->tiles_down);
12221231
return NULL;
12231232
}
12241233

1234+
uint32_t index = column + row * filehandle->tiles_across;
12251235
if (filehandle->layout == DCM_LAYOUT_SPARSE) {
12261236
index = filehandle->frame_index[index];
12271237
if (index == 0xffffffff) {

0 commit comments

Comments
 (0)