; $Id: query_dicom.pro,v 1.14 2004/01/21 15:54:59 scottm Exp $
;
; Copyright (c) 1993-2004, Research Systems, Inc.  All rights reserved.
;       Unauthorized reproduction prohibited.

;
;	Return the first datum reference in iref before the reference imgid.
;
FUNCTION QueryDicomGetFirstBefore, oDicom, iref, imgid
	COMPILE_OPT hidden

	iIndex = iref[0]

	parent = oDicom->GetParent(imgid)
	par_iref = oDicom->GetParent(iref)
	v = WHERE(par_iref EQ parent)
	IF (v[0] NE -1) THEN BEGIN
		v_iref = iref[v]
		w = WHERE(v_iref LT imgid)
		IF (w[0] NE -1) THEN BEGIN
			iIndex = v_iref[w[N_ELEMENTS(w)-1]]
		END
	END

	p = oDicom->GetValue(REFERENCE=iIndex,/NO_COPY)

	RETURN, p[0]
END

FUNCTION QUERY_DICOM, file, info, IMAGE_INDEX = iIndex
;+
; NAME:
;	QUERY_DICOM
;
; PURPOSE:
; 	This function queries image information from a DICOM format file using
;	the IDLffDICOM object interface.
;
; CATEGORY:
;   	Input/Output
;
; CALLING SEQUENCE:
;   	Result = QUERY_DICOM(File[, info])
;
; INPUTS:
; 	File: The full path name of the file to read.
;
; OPTIONAL KEYWORDS:
;       IMAGE_INDEX - Set this keyword to the index of the image to
;                     read from the file.
;
; OUTPUTS:
;	This function returns 1 if the file can be read as a DICOM file
;	and 0 otherwise
;
; OPTIONAL OUTPUTS:
;   Info:   An anonymous structure containing information about the image.
;       This structure is valid only when the return value of the function
;       is 1.  The Info structure has the following fields:
;
;           Field       IDL data type   Description
;           -----       -------------   -----------
;           CHANNELS    Long            Number of samples per pixel
;           DIMENSIONS  2-D long array  Size of the image in pixels
;           HAS_PALETTE Integer         True if a palette is present
;           NUM_IMAGES  Long            Number of images in the file
;           IMAGE_INDEX Long            Image number for this struct
;           PIXEL_TYPE  Integer         IDL basic type code for a pixel sample
;           TYPE        String          String identifying the file format
;
; KEYWORDS:
;   IMAGE_INDEX:  For files containing multiple images this
;       keyword can be used to specify for which image in a multi-image
;       file the information should be returned.
;
; SIDE EFFECTS:
;   	IO is performed.
;
; RESTRICTIONS:
;	Only uncompressed data format is supported (as per current DICOM obj).
;
; EXAMPLE:
;
; MODIFICATION HISTORY:
;   RJF, RSI.   Sep, 1998. Original version.
;   RJF, RSI.   Jan, 1999. Filter searches by sequence value.
;   CT, RSI, September 2002: Better check for interleave dimension.
;-

; Set up error handling
CATCH, errorStatus
IF (errorStatus NE 0) THEN BEGIN
	CATCH,/CANCEL
	IF (OBJ_VALID(oDicom)) THEN OBJ_DESTROY, oDicom
	RETURN, 0L
ENDIF

IF (N_ELEMENTS(iIndex) EQ 0) THEN iIndex=0
IF (iIndex LT 0) THEN iIndex = 0

oDicom = OBJ_NEW('IDLffDICOM')   ; be sure to destroy before return
IF (NOT OBJ_VALID(oDicom)) THEN BEGIN
        MESSAGE,'IDLffDICOM object not supported on this platform.'
	RETURN, 0L
END

; DICOM has a fatal error in accessing zero-length files
; Avoid the problem by checking in advance

OPENR, unit, file, /get_lun
stat = FSTAT(unit)
FREE_LUN, unit
IF (stat.size EQ 0) THEN BEGIN
	OBJ_DESTROY, oDicom
	RETURN, 0L
ENDIF

IF (oDicom->Read(file) NE 1) THEN BEGIN
	OBJ_DESTROY, oDicom
	RETURN, 0L
END

; Get a list of the images
ref = oDicom->GetReference('7FE0'x,'0010'x)
IF (SIZE(ref,/N_DIMENSIONS) EQ 0) THEN BEGIN
        OBJ_DESTROY, oDicom
        RETURN, 0L
END
iNum = N_ELEMENTS(ref)
IF (iIndex GE iNum) THEN BEGIN
        OBJ_DESTROY, oDicom
        RETURN, 0L
END

; Get the image in question
img = oDicom->GetValue(REFERENCE=ref[iIndex],/NO_COPY)
iType = SIZE(*(img[0]),/TYPE)
iDims = SIZE(*(img[0]),/DIMENSIONS)

; Get additional image info
iSamp = 1
iref = oDicom->GetReference('0028'x,'0002'x)
IF (SIZE(iref,/N_DIMENSIONS) NE 0) THEN BEGIN
	p = QueryDicomGetFirstBefore(oDicom,iref,ref[iIndex])
	IF (PTR_VALID(p)) THEN iSamp = *p
END

iPalette = 0
iref = oDicom->GetReference('0028'x,'0004'x)
IF (SIZE(iref,/N_DIMENSIONS) NE 0) THEN BEGIN
	p = QueryDicomGetFirstBefore(oDicom,iref,ref[iIndex])
	IF ((PTR_VALID(p)) AND (STRPOS(*p,"PALETTE COLOR") NE -1)) THEN BEGIN
		iPalette = 1
	END
END

OBJ_DESTROY, oDicom

; Define the info structure after error returns so that
; info argument stays undefined in error cases.
info = {CHANNELS:       0L,	$
        DIMENSIONS:     [0L,0L],$
        HAS_PALETTE:    0, 	$
        NUM_IMAGES:     0L, 	$
        IMAGE_INDEX:    0L, 	$
        PIXEL_TYPE:     0, 	$
        TYPE:           '' 	$
        }

;   Fill in the info structure
info.CHANNELS =     iSamp

; Either indexed color, or pixel, scanline, or planar interleaved.
; Note: To determine the interleave dimension, we assume that the
; image is at least 5 pixels x 5 pixels. We use 4 for RGBA.
info.DIMENSIONS = (iSamp le 1) ? [iDims[0], iDims[1]] : $
    (iDims[0] le 4) ? [iDims[1], iDims[2]] : $
    (iDims[1] le 4) ? [iDims[0], iDims[2]] : $
    [iDims[0], iDims[1]]

info.HAS_PALETTE =  iPalette
info.NUM_IMAGES =   iNum
info.IMAGE_INDEX =  iIndex
info.PIXEL_TYPE =   iType
info.TYPE=          'DICOM'

RETURN, 1L
END

