@@ -49,7 +49,9 @@ struct _DcmFilehandle {
4949 DcmDataSet * meta ;
5050
5151 // image properties we need to track
52- uint32_t tiles_across ;
52+ uint32_t frame_width ;
53+ uint32_t frame_height ;
54+ uint32_t frames_across ;
5355 uint32_t num_frames ;
5456 struct PixelDescription desc ;
5557 DcmLayout layout ;
@@ -63,6 +65,8 @@ struct _DcmFilehandle {
6365
6466 // used to count frames as we scan perframefunctionalgroup
6567 uint32_t frame_number ;
68+ int32_t column_position ;
69+ int32_t row_position ;
6670
6771 // indent for file print
6872 int indent ;
@@ -296,23 +300,44 @@ static bool get_num_frames(DcmError **error,
296300}
297301
298302
299- static bool get_tiles_across (DcmError * * error ,
300- const DcmDataSet * metadata ,
301- uint32_t * tiles_across )
303+ static bool get_frame_size (DcmError * * error ,
304+ const DcmDataSet * metadata ,
305+ uint32_t * frame_width ,
306+ uint32_t * frame_height )
302307{
303308 int64_t width ;
304- int64_t tile_width ;
309+ int64_t height ;
305310
306- if (!get_tag_int (error , metadata , "Columns" , & tile_width )) {
311+ if (!get_tag_int (error , metadata , "Columns" , & width ) ||
312+ !get_tag_int (error , metadata , "Rows" , & height )) {
313+ return false;
314+ }
315+
316+ * frame_width = width ;
317+ * frame_height = height ;
318+
319+ return true;
320+ }
321+
322+
323+ static bool get_frames_across (DcmError * * error ,
324+ const DcmDataSet * metadata ,
325+ uint32_t * frames_across )
326+ {
327+ int64_t width ;
328+ uint32_t frame_width ;
329+ uint32_t frame_height ;
330+
331+ if (!get_frame_size (error , metadata , & frame_width , & frame_height )) {
307332 return false;
308333 }
309334
310335 // TotalPixelMatrixColumns is optional and defaults to Columns, ie. one
311- // tile across
312- width = tile_width ;
336+ // frame across
337+ width = frame_width ;
313338 (void ) get_tag_int (NULL , metadata , "TotalPixelMatrixColumns" , & width );
314339
315- * tiles_across = width / tile_width + !!(width % tile_width );
340+ * frames_across = width / frame_width + !!(width % frame_width );
316341
317342 return true;
318343}
@@ -790,15 +815,22 @@ const DcmDataSet *dcm_filehandle_get_metadata_subset(DcmError **error,
790815 }
791816
792817 // useful values for later
793- if (!get_tiles_across (error , meta , & filehandle -> tiles_across ) ||
818+ if (!get_frame_size (error ,
819+ meta ,
820+ & filehandle -> frame_width ,
821+ & filehandle -> frame_height ) ||
822+ !get_frames_across (error , meta , & filehandle -> frames_across ) ||
794823 !get_num_frames (error , meta , & filehandle -> num_frames ) ||
795824 !set_pixel_description (error , meta , & filehandle -> desc )) {
796825 dcm_dataset_destroy (meta );
797826 return false;
798827 }
799828
800- // we support sparse and full tile layout, defaulting to full if no type
801- // is specified
829+ // we support sparse and full frame layout, defaulting to full if
830+ // no type is specified
831+ //
832+ // we flip to SPARSE if there's a PerFrameFunctionalGroupsSequence
833+ // containing frame positions, see below
802834 const char * type ;
803835 if (get_tag_str (NULL , meta , "DimensionOrganizationType" , & type )) {
804836 if (strcmp (type , "TILED_SPARSE" ) == 0 || strcmp (type , "3D" ) == 0 ) {
@@ -822,28 +854,103 @@ const DcmDataSet *dcm_filehandle_get_metadata_subset(DcmError **error,
822854}
823855
824856
825- static bool parse_frame_index_element_create (DcmError * * error ,
857+ static bool parse_frame_index_sequence_begin (DcmError * * error ,
826858 void * client ,
827859 uint32_t tag ,
828860 DcmVR vr ,
829- char * value ,
830861 uint32_t length )
831862{
832863 USED (error );
864+ USED (vr );
865+ USED (length );
833866
834867 DcmFilehandle * filehandle = (DcmFilehandle * ) client ;
835868
836- if (vr == DCM_VR_UL && length == 8 && tag == TAG_DIMENSION_INDEX_VALUES ) {
837- // it will have already been byteswapped for us, if necessary
838- uint32_t * ul = (uint32_t * ) value ;
839- uint32_t col = ul [0 ];
840- uint32_t row = ul [1 ];
841- uint32_t index = (col - 1 ) + (row - 1 ) * filehandle -> tiles_across ;
869+ if (tag == TAG_PLANE_POSITION_SLIDE_SEQUENCE ) {
870+ filehandle -> column_position = -1 ;
871+ filehandle -> row_position = -1 ;
872+ }
873+
874+ return true;
875+ }
876+
877+
878+ static bool parse_frame_index_sequence_end (DcmError * * error ,
879+ void * client ,
880+ uint32_t tag ,
881+ DcmVR vr ,
882+ uint32_t length )
883+ {
884+ USED (vr );
885+ USED (length );
842886
887+ DcmFilehandle * filehandle = (DcmFilehandle * ) client ;
888+
889+ // have we seen a valid pair of frame positions
890+ if (tag == TAG_PLANE_POSITION_SLIDE_SEQUENCE &&
891+ filehandle -> column_position != -1 &&
892+ filehandle -> row_position != -1 ) {
893+ // we don't support fractional frame positioning ... they must be
894+ // exactly aligned on frame boundaries
895+ if ((filehandle -> column_position - 1 ) % filehandle -> frame_width != 0 ||
896+ (filehandle -> row_position - 1 ) % filehandle -> frame_height != 0 ) {
897+ dcm_error_set (error , DCM_ERROR_CODE_PARSE ,
898+ "Reading PerFrameFunctionalGroupsSequence failed" ,
899+ "Unsupported frame alignment." );
900+ return false;
901+ }
902+
903+ // map the position of the frame to the frame number
904+ int col = (filehandle -> column_position - 1 ) / filehandle -> frame_width ;
905+ int row = (filehandle -> row_position - 1 ) / filehandle -> frame_height ;
906+ uint32_t index = col + row * filehandle -> frames_across ;
843907 if (index < filehandle -> num_frames ) {
844908 filehandle -> frame_index [index ] = filehandle -> frame_number ;
845- filehandle -> frame_number += 1 ;
909+
910+ // we have something meaningful in PerFrameFunctionalGroupsSequence,
911+ // so we must display in SPARSE mode
912+ filehandle -> layout = DCM_LAYOUT_SPARSE ;
913+ }
914+
915+ // end of TAG_PLANE_POSITION_SLIDE_SEQUENCE, so we're on to the next
916+ // frame
917+ filehandle -> frame_number += 1 ;
918+ }
919+
920+ return true;
921+ }
922+
923+
924+ static bool parse_frame_index_element_create (DcmError * * error ,
925+ void * client ,
926+ uint32_t tag ,
927+ DcmVR vr ,
928+ char * value ,
929+ uint32_t length )
930+ {
931+ USED (error );
932+
933+ DcmFilehandle * filehandle = (DcmFilehandle * ) client ;
934+
935+ switch (tag ) {
936+ case TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX :
937+ if (vr == DCM_VR_SL && length == 4 ) {
938+ int32_t * sl = (int32_t * ) value ;
939+
940+ filehandle -> column_position = sl [0 ];
846941 }
942+ break ;
943+
944+ case TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX :
945+ if (vr == DCM_VR_SL && length == 4 ) {
946+ int32_t * sl = (int32_t * ) value ;
947+
948+ filehandle -> row_position = sl [0 ];
949+ }
950+ break ;
951+
952+ default :
953+ break ;
847954 }
848955
849956 return true;
@@ -870,6 +977,8 @@ static bool read_frame_index(DcmError **error,
870977 DcmFilehandle * filehandle )
871978{
872979 static DcmParse parse = {
980+ .sequence_begin = parse_frame_index_sequence_begin ,
981+ .sequence_end = parse_frame_index_sequence_end ,
873982 .element_create = parse_frame_index_element_create ,
874983 .stop = parse_frame_index_stop ,
875984 };
@@ -1095,29 +1204,29 @@ DcmFrame *dcm_filehandle_read_frame_position(DcmError **error,
10951204 return NULL ;
10961205 }
10971206
1098- if (column >= filehandle -> tiles_across ) {
1207+ if (column >= filehandle -> frames_across ) {
10991208 dcm_error_set (error , DCM_ERROR_CODE_PARSE ,
11001209 "Reading Frame position failed" ,
11011210 "Column must be less than %u" ,
1102- filehandle -> tiles_across );
1211+ filehandle -> frames_across );
11031212 return NULL ;
11041213 }
11051214
1106- uint32_t index = column + row * filehandle -> tiles_across ;
1215+ uint32_t index = column + row * filehandle -> frames_across ;
11071216
11081217 if (index >= filehandle -> num_frames ) {
11091218 dcm_error_set (error , DCM_ERROR_CODE_PARSE ,
11101219 "Reading Frame position failed" ,
11111220 "Row must be less than %u" ,
1112- filehandle -> num_frames / filehandle -> tiles_across );
1221+ filehandle -> num_frames / filehandle -> frames_across );
11131222 return NULL ;
11141223 }
11151224
11161225 if (filehandle -> layout == DCM_LAYOUT_SPARSE ) {
11171226 index = filehandle -> frame_index [index ];
11181227 if (index == 0xffffffff ) {
1119- dcm_error_set (error , DCM_ERROR_CODE_PARSE ,
1120- "Reading Frame position failed " ,
1228+ dcm_error_set (error , DCM_ERROR_CODE_MISSING_FRAME ,
1229+ "No frame " ,
11211230 "No Frame at position (%u, %u)" , column , row );
11221231 return NULL ;
11231232 }
0 commit comments