Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1474 data element #1480

Merged
merged 4 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/dicom/dataElement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// doc imports
/* eslint-disable no-unused-vars */
import {Tag} from './dicomTag';
/* eslint-enable no-unused-vars */

/**
* DICOM data element.
*/
export class DataElement {
/**
* The element Value Representation.
*
* @type {string}
*/
vr;
/**
* The element value.
*
* @type {Array}
*/
value;

// [start] internal values
// only present during parsing or writing otherwise not set

/**
* The element dicom tag.
*
* @type {Tag}
*/
tag;

/**
* The element Value Length.
*
* @type {number}
*/
vl;

/**
* Flag to know if defined or undefined sequence length.
*
* @type {boolean}
*/
undefinedLength;

/**
* The element start offset.
*
* @type {number}
*/
startOffset;

/**
* The element end offset.
*
* @type {number}
*/
endOffset;

/**
* The sequence items.
*
* @type {Array}
*/
items;

// [end] internal values

/**
* @param {string} vr The element VR (Value Representation).
*/
constructor(vr) {
this.vr = vr;
}
}
3 changes: 2 additions & 1 deletion src/dicom/dicomElementsWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// doc imports
/* eslint-disable no-unused-vars */
import {Tag} from './dicomTag';
import {DataElement} from './dataElement';
/* eslint-enable no-unused-vars */

/**
Expand Down Expand Up @@ -749,7 +750,7 @@
/**
* Get the time.
*
* @param {object} _elements The DICOM elements.
* @param {Object<string, DataElement>} _elements The DICOM elements.

Check warning on line 753 in src/dicom/dicomElementsWrapper.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`

Check warning on line 753 in src/dicom/dicomElementsWrapper.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`
* @returns {number|undefined} The time value if available.
*/
getTime(_elements) {
Expand Down
86 changes: 48 additions & 38 deletions src/dicom/dicomParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@
import {logger} from '../utils/logger';
import {arrayEquals} from '../utils/array';

// doc imports
/* eslint-disable no-unused-vars */
import {DataElement} from '../dicom/dataElement';
/* eslint-enable no-unused-vars */

/**
* List of DICOM data elements indexed via a 8 character string formed from
* the group and element numbers.
*
* @typedef {Object<string, DataElement>} DataElements

Check warning on line 25 in src/dicom/dicomParser.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`

Check warning on line 25 in src/dicom/dicomParser.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`
*/

/**
* Get the version of the library.
*
Expand Down Expand Up @@ -382,8 +394,9 @@
* See https://github.com/ivmartel/dwv/issues/188
* (Allow to load DICOM with no DICM preamble) for more details.
*
* @param {object} firstDataElement The first data element of the DICOM header.
* @returns {object} The transfer syntax data element.
* @param {DataElement} firstDataElement The first data element
* of the DICOM header.
* @returns {DataElement} The transfer syntax data element.
*/
function guessTransferSyntax(firstDataElement) {
const oEightGroupBigEndian = '0800';
Expand Down Expand Up @@ -426,10 +439,8 @@
}
}
// set transfer syntax data element
const dataElement = {
tag: new Tag('0002', '0010'),
vr: 'UI'
};
const dataElement = new DataElement('UI');
dataElement.tag = new Tag('0002', '0010');
dataElement.value = [syntax + ' ']; // even length
dataElement.vl = dataElement.value[0].length;
dataElement.startOffset = firstDataElement.startOffset;
Expand Down Expand Up @@ -539,9 +550,9 @@
/**
* The list of DICOM elements.
*
* @type {object}
* @type {DataElements}
*/
#dicomElements = {};
#dataElements = {};

/**
* Default character set (optional).
Expand Down Expand Up @@ -617,13 +628,15 @@
this.#textDecoder = new TextDecoder(characterSet);
}

// not using type DataElements since the typedef is not exported with the API

/**
* Get the raw DICOM data elements.
* Get the DICOM data elements.
*
* @returns {object} The raw DICOM elements.
* @returns {Object<string, DataElement>} The data elements.

Check warning on line 636 in src/dicom/dicomParser.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`

Check warning on line 636 in src/dicom/dicomParser.js

View workflow job for this annotation

GitHub Actions / build

Use object shorthand or index signatures instead of `Object`, e.g., `{[key: string]: string}`
*/
getDicomElements() {
return this.#dicomElements;
return this.#dataElements;
}

/**
Expand Down Expand Up @@ -753,8 +766,7 @@
* @param {DataReader} reader The raw data reader.
* @param {number} offset The offset where to start to read.
* @param {boolean} implicit Is the DICOM VR implicit?
* @returns {object} An object containing the element
* 'tag', 'vl', 'vr', 'data' and 'endOffset'.
* @returns {DataElement} The data element.
*/
#readDataElement(reader, offset, implicit) {
// Tag: group, element
Expand Down Expand Up @@ -813,7 +825,7 @@
let endOffset = startOffset + vl;

// read sequence elements
let data = null;
let data;
if (isPixelDataTag(tag) && undefinedLength) {
// pixel data sequence (implicit)
const pixItemData =
Expand Down Expand Up @@ -857,13 +869,11 @@
}

// return
const element = {
tag: tag,
vr: vr,
vl: vl,
startOffset: startOffset,
endOffset: endOffset
};
const element = new DataElement(vr);
element.tag = tag;
element.vl = vl;
element.startOffset = startOffset;
element.endOffset = endOffset;
// only set if true (only for sequences and items)
if (undefinedLength) {
element.undefinedLength = undefinedLength;
Expand All @@ -877,7 +887,7 @@
/**
* Interpret the data of an element.
*
* @param {object} element The data element.
* @param {DataElement} element The data element.
* @param {DataReader} reader The raw data reader.
* @param {number} [pixelRepresentation] PixelRepresentation 0->unsigned,
* 1->signed (needed for pixel data or VR=xs).
Expand Down Expand Up @@ -1041,7 +1051,7 @@
/**
* Interpret the data of a list of elements.
*
* @param {Array} elements A list of data elements.
* @param {DataElements} elements A list of data elements.
* @param {DataReader} reader The raw data reader.
* @param {number} pixelRepresentation PixelRepresentation 0->unsigned,
* 1->signed.
Expand All @@ -1068,7 +1078,7 @@

/**
* Parse the complete DICOM file (given as input to the class).
* Fills in the member object 'dicomElements'.
* Fills in the member object 'dataElements'.
*
* @param {ArrayBuffer} buffer The input array buffer.
*/
Expand All @@ -1091,7 +1101,7 @@
// increment offset
offset = dataElement.endOffset;
// store the data element
this.#dicomElements[dataElement.tag.getKey()] = dataElement;
this.#dataElements[dataElement.tag.getKey()] = dataElement;
// get meta length
const metaLength = dataElement.value[0];

Expand All @@ -1102,11 +1112,11 @@
dataElement = this.#readDataElement(metaReader, offset, false);
offset = dataElement.endOffset;
// store the data element
this.#dicomElements[dataElement.tag.getKey()] = dataElement;
this.#dataElements[dataElement.tag.getKey()] = dataElement;
}

// check the TransferSyntaxUID (has to be there!)
dataElement = this.#dicomElements['00020010'];
dataElement = this.#dataElements['00020010'];
if (typeof dataElement === 'undefined') {
throw new Error('Not a valid DICOM file (no TransferSyntaxUID found)');
}
Expand All @@ -1120,7 +1130,7 @@
// guess transfer syntax
const tsElement = guessTransferSyntax(dataElement);
// store
this.#dicomElements[tsElement.tag.getKey()] = tsElement;
this.#dataElements[tsElement.tag.getKey()] = tsElement;
syntax = tsElement.value[0];
// reset offset
offset = 0;
Expand Down Expand Up @@ -1151,8 +1161,8 @@
offset = dataElement.endOffset;
// store the data element
const key = dataElement.tag.getKey();
if (typeof this.#dicomElements[key] === 'undefined') {
this.#dicomElements[key] = dataElement;
if (typeof this.#dataElements[key] === 'undefined') {
this.#dataElements[key] = dataElement;
} else {
logger.warn('Not saving duplicate tag: ' + key);
}
Expand All @@ -1173,9 +1183,9 @@
// pixel specific
let pixelRepresentation = 0;
let bitsAllocated = 16;
if (typeof this.#dicomElements['7FE00010'] !== 'undefined') {
if (typeof this.#dataElements['7FE00010'] !== 'undefined') {
// PixelRepresentation 0->unsigned, 1->signed
dataElement = this.#dicomElements['00280103'];
dataElement = this.#dataElements['00280103'];
if (typeof dataElement !== 'undefined') {
dataElement.value = this.#interpretElement(dataElement, dataReader);
pixelRepresentation = dataElement.value[0];
Expand All @@ -1185,7 +1195,7 @@
}

// BitsAllocated
dataElement = this.#dicomElements['00280100'];
dataElement = this.#dataElements['00280100'];
if (typeof dataElement !== 'undefined') {
dataElement.value = this.#interpretElement(dataElement, dataReader);
bitsAllocated = dataElement.value[0];
Expand All @@ -1200,7 +1210,7 @@
}

// SpecificCharacterSet
dataElement = this.#dicomElements['00080005'];
dataElement = this.#dataElements['00080005'];
if (typeof dataElement !== 'undefined') {
dataElement.value = this.#interpretElement(dataElement, dataReader);
let charSetTerm;
Expand All @@ -1216,19 +1226,19 @@

// interpret the dicom elements
this.#interpret(
this.#dicomElements, dataReader,
this.#dataElements, dataReader,
pixelRepresentation, bitsAllocated
);

// handle fragmented pixel buffer
// Reference: http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_8.2.html
// (third note, "Depending on the transfer syntax...")
dataElement = this.#dicomElements['7FE00010'];
dataElement = this.#dataElements['7FE00010'];
if (typeof dataElement !== 'undefined') {
if (dataElement.undefinedLength) {
let numberOfFrames = 1;
if (typeof this.#dicomElements['00280008'] !== 'undefined') {
numberOfFrames = Number(this.#dicomElements['00280008'].value[0]);
if (typeof this.#dataElements['00280008'] !== 'undefined') {
numberOfFrames = Number(this.#dataElements['00280008'].value[0]);
}
const pixItems = dataElement.value;
if (pixItems.length > 1 && pixItems.length > numberOfFrames) {
Expand Down
Loading
Loading