@dcm/dicom-parser
Version:
Javascript parser for DICOM Part 10 data.
534 lines (482 loc) • 21.2 kB
TypeScript
/** Patient name object */
export interface PatientNameObject {
familyName?: string;
givenName?: string;
middleName?: string;
prefix?: string;
suffix?: string;
}
/** Time object */
export interface TimeObject {
hours: number;
minutes?: number;
seconds?: number;
fractionalSeconds?: number;
}
/** Date object */
export interface DateObject {
year: number;
month: number;
day: number;
}
/** Fragment */
export interface Fragment {
offset: number;
position: number;
length: number;
}
/** Byte array */
export type ByteArray = Uint8Array | Buffer;
/** ByteStream */
export interface ByteStream {
byteArray: ByteArray;
byteArrayParser: ByteArrayParser;
position: number;
warnings: string[];
new (byteArrayParser: ByteArrayParser, byteArray: ByteArray, position: number): ByteStream;
seek: (offset: number) => void;
readByteStream: (numBytes: number) => ByteStream;
readUint16: () => number;
readUint32: () => number;
readFixedString: (length: number) => string;
}
/** Internal helper functions for parsing different types from a big-endian byte array */
export interface ByteArrayParser {
/**
*
* Parses an unsigned int 16 from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed unsigned int 16
* @throws Error if buffer overread would occur
*/
readUint16: (byteArray: ByteArray, position: number) => number;
/**
*
* Parses a signed int 16 from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed signed int 16
* @throws Error if buffer overread would occur
*/
readInt16: (byteArray: ByteArray, position: number) => number;
/**
* Parses an unsigned int 32 from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed unsigned int 32
* @throws Error if buffer overread would occur
*/
readUint32: (byteArray: ByteArray, position: number) => number;
/**
* Parses a signed int 32 from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed signed int 32
* @throws Error if buffer overread would occur
*/
readInt32: (byteArray: ByteArray, position: number) => number;
/**
* Parses 32-bit float from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed 32-bit float
* @throws Error if buffer overread would occur
*/
readFloat: (byteArray: ByteArray, position: number) => number;
/**
* Parses 64-bit float from a big-endian byte array
*
* @param {ByteArray} byteArray The byte array to read from
* @param {number} position The position in the byte array to read from
* @returns {number} The parsed 64-bit float
* @throws Error if buffer overread would occur
*/
readDouble: (byteArray: ByteArray, position: number) => number;
}
/** Element */
export interface Element {
tag: string;
vr?: string;
length: number;
dataOffset: number;
items?: Element[];
dataSet?: DataSet;
parser?: ByteArrayParser;
hadUndefinedLength?: boolean;
encapsulatedPixelData?: boolean;
basicOffsetTable?: number[];
fragments?: Fragment[];
}
/** DataSet */
export interface DataSet {
byteArray: ByteArray;
byteArrayParser: ByteArrayParser;
/**
* Access element with the DICOM tag in the format xGGGGEEEE.
*/
elements: Record<string, Element>;
warnings: string[];
/**
* Finds the element for tag and returns an unsigned int 16 if it exists and has data. Use this function for VR type US.
*/
uint16: (tag: string, index?: number) => number;
/**
* Finds the element for tag and returns a signed int 16 if it exists and has data. Use this function for VR type SS.
*/
int16: (tag: string, index?: number) => number;
/**
* Finds the element for tag and returns an unsigned int 32 if it exists and has data. Use this function for VR type UL.
*/
uint32: (tag: string, index?: number) => number;
/**
* Finds the element for tag and returns a signed int 32 if it exists and has data. Use this function for VR type SL.
*/
int32: (tag: string, index?: number) => number;
/**
* Finds the element for tag and returns a 32 bit floating point number if it exists and has data. Use this function for VR type FL.
*/
float: (tag: string, index?: number) => number;
/**
* Finds the element for tag and returns a 64 bit floating point number if it exists and has data. Use this function for VR type FD.
*/
double: (tag: string, index?: number) => number;
/**
* Returns the actual Value Multiplicity of an element - the number of values in a multi-valued element.
*/
numStringValues: (tag: string) => number;
/**
* Finds the element for tag and returns a string if it exists and has data. Use this function for VR types AE, CS, SH, and LO.
*/
string: (tag: string, index?: number) => string;
/**
* Finds the element for tag and returns a string with the leading spaces preserved and trailing spaces removed if it exists and has data. Use this function for VR types UT, ST, and LT.
*/
text: (tag: string, index?: number) => string;
/**
* Finds the element for tag and parses a string to a float if it exists and has data. Use this function for VR type DS.
*/
floatString: (tag: string, index?: number) => number;
/**
* Finds the element for tag and parses a string to an integer if it exists and has data. Use this function for VR type IS.
*/
intString: (tag: string, index?: number) => number;
/**
* Finds the element for tag and parses an element tag according to the 'AT' VR definition if it exists and has data. Use this function for VR type AT.
*/
attributeTag: (tag: string) => string;
}
/** Explicit dataset to javascript object type */
export type ExplicitDataSetToJSType = string | { dataOffset: number; length: number };
/** Explicit dataset to javascript object options */
export interface DataSetToJSOptions {
omitPrivateAttibutes: boolean;
maxElementLength: number;
}
/** Parse dicom options */
export interface ParseDicomOptions {
untilTag?: string;
vrCallback?: (tag: string) => void;
inflater?: (arr: Uint8Array, position: number) => void;
}
/* -------------------- DicomParser -------------------- */
export interface DicomParser {
/**
* Tests to see if vr is a string or not.
*
* @param {string} vr VR
* @returns {boolean} True if string, false it not string, undefined if unknown vr or UN type
*/
isStringVr(vr: string): boolean;
/**
* Tests to see if a given tag in the format xggggeeee is a private tag or not
*
* @param {string} tag Given tag
* @returns {boolean} True if private tag
*/
isPrivateTag(tag: string): boolean;
/**
* Parses a PN formatted string into a javascript object with properties for givenName, familyName, middleName, prefix and suffix
*
* @param {string} personName A string in the PN VR format
* @returns {PatientNameObject} javascript object with properties for givenName, familyName, middleName, prefix and suffix or undefined if no element or data
*/
parsePN(personName: string): PatientNameObject;
/**
* Parses a TM formatted string into a javascript object with properties for hours, minutes, seconds and fractionalSeconds
*
* @param {string} time - A string in the TM VR format
* @param {boolean} [validate] - True if an exception should be thrown if the date is invalid
* @returns {TimeObject} Javascript object with properties for hours, minutes, seconds and fractionalSeconds or undefined if no element or data. Missing fields are set to undefined
*/
parseTM(time: string, validate?: boolean): TimeObject;
/**
* Parses a DA formatted string into a Javascript object
*
* @param {string} date A string in the DA VR format
* @param {boolean} [validate] - True if an exception should be thrown if the date is invalid
* @returns {DateObject} Javascript object with properties year, month and day or undefined if not present or not 8 bytes long
*/
parseDA(date: string, validate?: boolean): DateObject;
/**
* Converts an explicit VR element to a string or undefined if it is not possible to convert.
* Throws an error if an implicit element is supplied
*
* @param {DateSet} dataSet Dateset
* @param {Element} element An explicit VR element
* @returns {string | undefined} A string or undefined
*/
explicitElementToString(dataSet: DataSet, element: Element): string | undefined;
/**
* Converts an explicit dataSet to a javascript object
*
* @param {DataSet} dataSet Dataset
* @param {DataSetToJSOptions} [options] Explicit dataset to javascript options
*/
explicitDataSetToJS(
dataSet: DataSet,
options?: DataSetToJSOptions,
): ExplicitDataSetToJSType | ExplicitDataSetToJSType[];
/**
* Creates a basic offset table by scanning fragments for JPEG start of image and end Of Image markers
*
* @param {DataSet} dataSet The parsed dicom dataset
* @param {Element} pixelDataElement The pixel data element
* @param {Fragment[]} [fragments] Optional array of objects describing each fragment (offset, position, length)
* @returns {number[]} Basic offset table (array of offsets to beginning of each frame)
*/
createJPEGBasicOffsetTable(
dataSet: DataSet,
pixelDataElement: Element,
fragments?: Fragment[],
): number[];
/**
* Internal helper functions for parsing implicit and explicit DICOM data sets reads an explicit data set
*
* @param {DataSet} dataSet Dateset
* @param {ByteStream} byteStream The byte stream to read from
* @param {number} [maxPosition] The maximum position to read up to (optional - only needed when reading sequence items)
* @param {ParseDicomDataSetOptions} [options] Parse options
* @returns {void}
*/
parseDicomDataSetExplicit(
dataSet: DataSet,
byteStream: ByteStream,
maxPosition?: number,
options?: ParseDicomOptions,
): void;
/**
* Internal helper functions for parsing implicit and explicit DICOM data sets reads an implicit data set
*
* @param {DataSet} dataSet Dateset
* @param {ByteStream} byteStream The byte stream to read from
* @param {number} [maxPosition] The maximum position to read up to (optional - only needed when reading sequence items)
* @param {ParseDicomDataSetOptions} [options] Parse options
* @returns {void}
*/
parseDicomDataSetImplicit(
dataSet: DataSet,
byteStream: ByteStream,
maxPosition?: number,
options?: ParseDicomOptions,
): void;
/**
* Reads a string of 8-bit characters from an array of bytes and advances
* the position by length bytes. A null terminator will end the string
* but will not effect advancement of the position. Trailing and leading
* spaces are preserved (not trimmed)
*
* @param {ByteArray} byteArray The byteArray to read from
* @param {number} position The position in the byte array to read from
* @param {number} length The maximum number of bytes to parse
* @returns {string} The parsed string
* @throws Error if buffer overread would occur
*/
readFixedString(byteArray: ByteArray, position: number, length: number): string;
/**
* Creates a new byteArray of the same type (Uint8Array or Buffer) of the specified length.
*
* @param {ByteArray} byteArray the underlying byteArray (either Uint8Array or Buffer)
* @param {number} length number of bytes of the Byte Array
* @returns {ByteArray} Uint8Array or Buffer depending on the type of byteArray
*/
alloc(byteArray: ByteArray, length: number): ByteArray;
/** Software version */
version: string;
bigEndianByteArrayParser: ByteArrayParser;
ByteStream: ByteStream;
/**
* Creates a view of the underlying byteArray. The view is of the same type as the byteArray (e.g. Uint8Array or Buffer) and shares the same underlying memory (changing one changes the other)
*
* @param {ByteArray} byteArray The underlying byteArray (either Uint8Array or Buffer)
* @param {number} byteOffset Offset into the underlying byteArray to create the view of
* @param {number} length Number of bytes in the view
* @returns {ByteArray} Uint8Array or Buffer depending on the type of byteArray
*/
sharedCopy(byteArray: ByteArray, byteOffset: number, length: number): ByteArray;
DataSet: DataSet;
/**
* Reads from the byte stream until it finds the magic number for the Sequence Delimitation
* Item item and then sets the length of the element
*
* @param {ByteStream} byteStream Byte stream
* @param {Element} element Element
* @returns {void}
*/
findAndSetUNElementLength(byteStream: ByteStream, element: Element): void;
/**
* Reads an encapsulated pixel data element and adds an array of fragments to the element
* containing the offset and length of each fragment and any offsets from the basic offset
* table
*
* @param {ByteStream} byteStream Byte stream
* @param {Element} element Element
* @returns {void}
*/
findEndOfEncapsulatedElement(byteStream: ByteStream, element: Element, warnings?: string[]): void;
/**
* Reads from the byte stream until it finds the magic numbers for the item delimitation item
* and then sets the length of the element
*
* @param {ByteStream} byteStream Byte stream
* @param {Element} element Element
* @returns {void}
*/
findItemDelimitationItemAndSetElementLength(byteStream: ByteStream, element: Element): void;
littleEndianByteArrayParser: ByteArrayParser;
/**
* Parses a DICOM P10 byte array and returns a DataSet object with the parsed elements.
* If the options argument is supplied and it contains the untilTag property, parsing
* will stop once that tag is encoutered. This can be used to parse partial byte streams.
*
* @param {Uint8Array} byteArray The byte array
* @param {ParseDicomOptions} [options] Object to control parsing behavior (optional)
* @returns {DataSet} Parsed dicom dataset
* @throws Error if an error occurs while parsing. The exception object will contain a property dataSet with the elements successfully parsed before the error.
*/
parseDicom(arr: Uint8Array, option?: ParseDicomOptions): DataSet;
/**
* Read DICOM element explicit
*
* @param {ByteStream} byteStream Byte Stream
* @param {string[]} [warnings] Warning list
* @param {string} [untilTag] Untile tag
* @returns {Element} Element
*/
readDicomElementExplicit(byteStream: ByteStream, warnings?: string[], untilTag?: string): Element;
/**
* Read DICOM element implicit
*
* @param {ByteStream} byteStream Byte Stream
* @param {string} [untilTag] Untile tag
* @param {(tag: string) => string} [vrCallback] VR Callback
* @returns {Element} Element
*/
readDicomElementImplicit(
byteStream: ByteStream,
untilTag?: string,
vrCallback?: (tag: string) => string,
): Element;
/**
* Returns the pixel data for the specified frame in an encapsulated pixel data element that has a non empty basic offset table. Note that this function will fail if the basic offset table is empty - in that case you need to determine which fragments map to which frames and read them using readEncapsulatedPixelDataFromFragments(). Also see the function createJEPGBasicOffsetTable() to see how a basic offset table can be created for JPEG images
*
* @param {DataSet} dataSet The dataSet containing the encapsulated pixel data
* @param {Element} pixelDataElement The pixel data element (x7fe00010) to extract the frame from
* @param {number} frameIndex The zero based frame index
* @param {number[]} [basicOffsetTable] Optional array of starting offsets for frames
* @param {Fragment[]} [fragments] Optional array of objects describing each fragment (offset, position, length)
* @returns {ByteStream} With the encapsulated pixel data
*/
readEncapsulatedImageFrame(
dataSet: DataSet,
pixelDataElement: Element,
frameIndex: number,
basicOffsetTable?: number[],
fragments?: Fragment[],
): ByteStream;
/**
* Returns the pixel data for the specified frame in an encapsulated pixel data element. If no basic offset table is present, it assumes that all fragments are for one frame. Note that this assumption/logic is not valid for multi-frame instances so this function has been deprecated and will eventually be removed. Code should be updated to use readEncapsulatedPixelDataFromFragments() or readEncapsulatedImageFrame()
*
* @param {DataSet} dataSet The dataSet containing the encapsulated pixel data
* @param {Element} pixelDataElement The pixel data element (x7fe00010) to extract the frame from
* @param {number} frame The zero based frame index
* @returns {ByteStream} With the encapsulated pixel data
* @deprecated Since version 1.6 - use readEncapsulatedPixelDataFromFragments() or readEncapsulatedImageFrame()
*/
readEncapsulatedPixelData(dataSet: DataSet, pixelDataElement: Element, frame: number): ByteStream;
/**
* Returns the encapsulated pixel data from the specified fragments. Use this function when you know the fragments you want to extract data from
*
* @param {DataSet} dataSet The dataSet containing the encapsulated pixel data
* @param {Element} pixelDataElement The pixel data element (x7fe00010) to extract the fragment data from
* @param {number} startFragmentIndex Zero based index of the first fragment to extract from
* @param {number} [numFragments] The number of fragments to extract from, default is 1
* @param {Fragment[]} [fragments] Optional array of objects describing each fragment (offset, position, length)
* @returns {ByteStream} Byte array with the encapsulated pixel data
*/
readEncapsulatedPixelDataFromFragments(
dataSet: DataSet,
pixelDataElement: Element,
startFragmentIndex: number,
numFragments?: number,
fragments?: Fragment[],
): ByteStream;
/**
* Parses a DICOM P10 byte array and returns a DataSet object with the parsed elements. If the options argument is supplied and it contains the untilTag property, parsing will stop once that tag is encoutered. This can be used to parse partial byte streams.
*
* @param {ByteArray} byteArray The byte array
* @param {ParseDicomOptions} [options] Object to control parsing behavior (optional)
* @returns {DataSet} Dataset
* @throws Error if an error occurs while parsing. The exception object will contain a property dataSet with the elements successfully parsed before the error.
*/
readPart10Header(byteArray: ByteArray, options?: ParseDicomOptions): DataSet;
/**
* Reads sequence items for an element in an explicit little endian byte stream
*
* @param {ByteStream} byteStream The implicit little endian byte stream
* @param {Element} element The element to read the sequence items for
* @param {string[]} [warnings] Warning list
* @returns {void}
*/
readSequenceItemsExplicit(byteStream: ByteStream, element: Element, warnings?: string[]): void;
/**
* Reads sequence items for an element in an implicit little endian byte stream
*
* @param {ByteStream} byteStream The implicit little endian byte stream
* @param {Element} element The element to read the sequence items for
* @param {(tag: string) => string} vrCallback An optional method that returns a VR string given a tag
* @returns {void}
*/
readSequenceItemsImplicit(
byteStream: ByteStream,
element: Element,
callback?: (tag: string) => string,
): void;
/**
* Reads the tag and length of a sequence item and returns them as an object with the following properties
*
* - tag : string for the tag of this element in the format xggggeeee
* - length: the number of bytes in this item or 4294967295 if undefined
* - dataOffset: the offset into the byteStream of the data for this item
*
* @param {ByteStream} byteStream The byteStream
* @returns {Pick<Element, 'tag' | 'length' | 'dataOffset'>} Pick properties of element
*/
readSequenceItem(byteStream: ByteStream): Pick<Element, 'tag' | 'length' | 'dataOffset'>;
/**
* Reads a tag (group number and element number) from a byteStream
*
* @param {ByteStream} byteStream The byte stream to read from
* @returns {string} The tag in format xggggeeee where gggg is the lowercase hex value of the group number and eeee is the lower case hex value of the element number
*/
readTag(byteStream: ByteStream): string;
}
declare const dicomParser: DicomParser;
declare module '@dcm/dicom-parser' {
export = dicomParser;
}