X
68 Rate this article:
No rating

[Internal] Retrieving Data From DICOM Files Which Contain an Odd Number Of Bytes in Size

Help Article Update 2

Anonym

Note: help article for IDL version 6.3

Prior to IDL 6.4, IDL's implementation of its two DICOM-reading libraries (IDLffDicom and IDLffDicomEx) has been very intolerant of parsing files that violate NEMA's official DICOM standard. IDL 6.3 and earlier have particularly disallowed the reading of files that violate one very unequivocal DICOM rule: files should never contain an odd number of bytes; they should always have an even-numbered byte size. Unfortunately, there are at least a few medical instruments out on the market which seem to be producing well-formulated DICOM output in every way except in the odd-ness of their total byte count.

Customers with these files have observed that other readers are not intolerant of this rule violation. The competitive readers are able to display the full data payload of these odd-byte-sized files. ITT Visual Information Solutions, has, thus, starting in IDL 6.4, modified one of our two DICOM parsing classes - IDLffDicomEx - so that it also will parse DICOM files with odd-numbered byte size. (The second library class, 'IDLffDicom', based on a different third-party library, will still fail.) This Tech Tip is designed to show users of IDL version 6.3 and earlier how to open and parse the same files.

Discussion:
Here is the behavior that users of IDL's IDLffDicom and IDLffDicomEx classes see in version 6.2 or 6.3, when the target file for parsing is an odd number of bytes in size:

    ; Confirm that this is an odd-number-byte file
    IDL> file = 'PET.dcm'
    IDL> fileInfo = file_info(file)
    IDL> print, fileInfo.size
    59731
    ; Note how IDL *does* recognize that this is a DICOM file
    IDL> print, query_dicom(file, configInfo)
    1
    IDL> help, configInfo, /STRUCT
    ** Structure <104c950>, 7 tags, length=40, data length=40, refs=1:
    CHANNELS LONG 1
    DIMENSIONS LONG Array[2]
    HAS_PALETTE LONG 0
    NUM_IMAGES LONG 1
    IMAGE_INDEX LONG 0
    PIXEL_TYPE LONG 2
    TYPE STRING 'DICOM'
    IDL> print, configInfo.dimensions
    168 168
    ; Test 'IDLffDicomEx' library
    IDL> oDicomEx = obj_new('IDLffDicomEx', file)
    OBJ_NEW: Error: MC_Open_File failed - unable to read file from media, PET.dcm,
    Callback provided uneven data size
    Execution halted at: $MAIN$
    ; Test 'IDLffDicom' library
    IDL> oDicom = obj_new('IDLffDicom', file, /VERBOSE)
    OBJ_NEW: Condition 00020092, DCM failed to open file: PET.dcm
    in DCM_OpenFile
    OBJ_NEW: Condition 00170092, DCM attempt to add data element (10 20)
    with uneven length (11) in readFile
    OBJ_NEW: Could not open PET.dcm as a DICOM Part 10 file.
    Trying non-Part 10 stream format.
    OBJ_NEW: Condition 00020092, DCM failed to open file: PET.dcm in DCM_OpenFile
    OBJ_NEW: Condition 000c0092, DCM group/element out of
    order (0000 0000) in checkAttributeOrder
    OBJ_NEW: Error opening PET.dcm as a DICOM file.

The third party libraries, on which IDL's DICOM-parsing classes are based - there are two different sources - are both designed to throw errors when they detect, before opening, that the target DICOM file has an odd number of bytes. The only way to get past those libraries' restrictions is to modify the target file, so that it has an even number of bytes. However, because DICOM is a standard used in medical records-keeping, ITT Visual Information Solutions has been reluctant to take steps that would involve modification of a DICOM file in any way. Nevertheless, IDL's medical user community has reported at least a few instruments from well-established medical instrument manufacturers that are able to produce odd-number-byte output files. They have also reported that these files and the files are readable on other well-established software. As a result, ITT has taken the step of allowing this parsing starting in version 6.4 ... though in only one (the more powerful) of its two class libraries, 'IDLffDicomEx'. The detection of the odd-number-byte target file will trigger a warning message:

        OBJ_NEW:  Warning: Invalid file length. 
    Odd length files are not valid dicom files.
    Extra byte (0) appended to pixel data.
    Use this dicom data with caution.
    Use !Quiet to suppress this warning.

but this warning will not otherwise interfere with the initialization of the IDLffDicomEx object or the execution of its data querying, extracting, creating or outputting methods.

What can users of IDL 6.3 or earlier do to read these odd-number-byte files? ... or users who are parsing with the older 'IDLffDicom' class library? The basic concept is simple: Add one additional byte to the target DICOM file. The below IDL function can perform this function for you, in this case by appending one null byte to the very end of the current file contents and writing out a copy of hte file. Be aware, though, that ITT does not know that it is either safe or acceptable medical practice to replace your original DICOM source file with the file output by the below function!!!

The below function can be called in this way:

    IDL> IDL63parseableCopy = append_one_byte_and_resave('CT.dcm')
    IDL> oDICOM = obj_new('IDLffDicomEx', IDL63parseableCopy)
    IDL> image = oDICOM->GetPixelData()
    IDL> tv, image
    IDL> ; Maybe you don't need this copy after the TV
    IDL> file_delete, IDL63parseableCopy 

      

Use this at your own risk.

; This function was created to convert odd-number-byte DICOM files,
; which are in violation of the DICOM standard, into even-number-byte
; files, whose data payload can be parsed by versions of IDL 6.3 or
; older. It appends one null byte to the end of a file's contents and
; outputs the original contents plus this one byte to a file with
; the same base name as the original, but with appended suffix
; "_even_bytesized_copy.dcm". It writes out this file in the same
; directory as the original, and returns the full filepath string.
;
FUNCTION append_one_byte_and_resave, oddNumberByteFile
info = file_info(oddNumberByteFile)
fileContents = bytarr(info.size)
openr, lun, oddNumberByteFile, /GET_LUN
readu, lun, fileContents
free_lun, lun
fileContents = [fileContents, 0B]   ; Append one null byte to end
evenNumberByteFile = file_dirname(oddNumberByteFile, /MARK_DIRECTORY) + $
	file_basename(oddNumberByteFile, '.dcm')  + '_even_bytesized_copy.dcm'
openw, lun, evenNumberByteFile, /GET_LUN
writeu, lun, fileContents
free_lun, lun
return, evenNumberByteFile
END