in src/engine/loaders/LoaderDicom.js [1036:1215]
getNextTag(dataView, offset) {
// check end of buffer
if (offset >= dataView.byteLengh) {
return null;
}
const SIZE_SHORT = 2;
const SIZE_DWORD = 4;
let little = true;
let group = 0;
let element = 0;
let lenData = 0;
const offsetStart = offset;
let vr = '';
const MAGIC_GROUP = 0x0002;
if (this.m_metaFinished) {
little = this.m_littleEndian;
group = dataView.getUint16(offset, little);
} else {
group = dataView.getUint16(offset, 1);
if ((this.m_metaFinishedOffset !== -1 && offset >= this.m_metaFinishedOffset) || group !== MAGIC_GROUP) {
this.m_metaFinished = 1;
little = this.m_littleEndian;
group = dataView.getUint16(offset, little);
} else {
little = true;
}
}
if (!this.m_metaFound && group === MAGIC_GROUP) {
this.m_metaFound = true;
}
offset += SIZE_SHORT; // skip group number
element = dataView.getUint16(offset, little);
offset += SIZE_SHORT; // skip element number
if (this.m_explicit || !this.m_metaFinished) {
vr = LoaderDicom.getStringAt(dataView, offset, SIZE_SHORT);
if (!this.m_metaFound && this.m_metaFinished && LoaderDicom.getVrsStringIndex(vr) === -1) {
vr = DicomDictionary.getVr(group, element);
lenData = dataView.getUint32(offset, little);
// assert for lenData < 1024 * 1024 * 32
offset += SIZE_DWORD;
this.m_explicit = false;
} else {
offset += SIZE_SHORT;
if (LoaderDicom.getDataVrsStringIndex(vr) !== -1) {
offset += SIZE_SHORT;
lenData = dataView.getUint32(offset, little);
// assert for lenData < 1024 * 1024 * 32
offset += SIZE_DWORD;
} else {
lenData = dataView.getUint16(offset, little);
// assert for lenData < 1024 * 1024 * 32
offset += SIZE_SHORT;
}
}
} else {
vr = this.m_dictionary.getVr(group, element);
lenData = dataView.getUint32(offset, little);
// assert for lenData < 1024 * 1024 * 32
if (lenData === UNDEFINED_LENGTH) {
vr = 'SQ';
}
offset += SIZE_DWORD;
}
const offsetValue = offset;
let dataValue = null;
if (vr === 'SQ') {
// see nema dicom Table 7.5-3
// for now just skip sequence items
if (lenData === UNDEFINED_LENGTH) {
let sqGroup = 0;
let sqElement = 0;
while (!(sqGroup === TAG_END_OF_SEQUENCE[0] && sqElement === TAG_END_OF_SEQUENCE[1])) {
sqGroup = dataView.getUint16(offset, little);
offset += SIZE_SHORT;
sqElement = dataView.getUint16(offset, little);
offset += SIZE_SHORT;
const sqLength = dataView.getUint32(offset, little);
offset += SIZE_DWORD;
if (sqLength === UNDEFINED_LENGTH) {
// item delim. tag (fffe, e00d)
while (
!(
(sqGroup === TAG_END_OF_ITEMS[0] && sqElement === TAG_END_OF_ITEMS[1]) ||
(sqGroup === TAG_END_OF_SEQUENCE[0] && sqElement === TAG_END_OF_SEQUENCE[1])
)
) {
const tagNew = this.getNextTag(dataView, offset);
offset = tagNew.m_offsetEnd;
sqGroup = dataView.getUint16(offset, little);
sqElement = dataView.getUint16(offset + SIZE_SHORT, little);
}
offset += SIZE_DWORD + SIZE_DWORD; // 4 for group and element + 4 for length field
} else {
// if sqLength is ffffffff
offset += sqLength;
}
} // while not end tag sequence
lenData = 0;
} // if length equal to ffffffff
} else if (lenData > 0) {
if (lenData === UNDEFINED_LENGTH) {
if (group === TAG_PIXEL_DATA[0] && element === TAG_PIXEL_DATA[1]) {
lenData = dataView.byteLength - offset;
}
}
// Get data from buffer, starting from offset
dataValue = dataView.buffer.slice(offset, offset + lenData);
}
const VAL_16 = 16;
if (DEBUG_PRINT_TAGS_INFO) {
const strDesc = this.m_dictionary.getTextDesc(group, element);
const strGr = group.toString(VAL_16);
const strEl = element.toString(VAL_16);
console.log(`Tag {${strGr},${strEl}}, VR='${vr}', Length=${lenData}, Desc=${strDesc}`);
}
const VAL_MIN_ONE = 0xffffffff;
if (lenData === VAL_MIN_ONE) {
return null;
}
offset += lenData;
const tag = new DicomTag(group, element, vr, dataValue, offsetStart, offsetValue, offset, this.m_littleEndian);
if (tag) {
this.m_newTagEvent.detail.group = group.toString(VAL_16);
this.m_newTagEvent.detail.element = element.toString(VAL_16);
this.m_newTagEvent.detail.desc = this.m_dictionary.getTextDesc(group, element);
this.m_newTagEvent.detail.value = LoaderDicom.getAttrValueAsString(tag);
if (group === TAG_IMAGE_INSTANCE_NUMBER[0] && element === TAG_IMAGE_INSTANCE_NUMBER[1]) {
this.m_newTagEvent.detail.imageNumber = parseInt(this.m_newTagEvent.detail.value, 10);
} else {
this.m_newTagEvent.detail.imageNumber = -1;
}
dispatchEvent(this.m_newTagEvent);
}
if (tag.isTransformSyntax()) {
const tagDataLen = tag.m_value.byteLength;
const dvTag = new DataView(tag.m_value);
const strTagVal = LoaderDicom.getStringAt(dvTag, 0, tagDataLen);
if (strTagVal === TRANSFER_SYNTAX_IMPLICIT_LITTLE) {
this.m_explicit = false;
this.m_littleEndian = true;
} else if (strTagVal === TRANSFER_SYNTAX_EXPLICIT_BIG) {
this.m_explicit = true;
this.m_littleEndian = false;
} else if (strTagVal === TRANSFER_SYNTAX_COMPRESSION_DEFLATE) {
this.m_needsDeflate = true;
this.m_explicit = true;
this.m_littleEndian = true;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS_SEL1) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS_SEL1;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_LOSSLESS;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_8BIT) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_8BIT;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_12BIT) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_BASELINE_12BIT;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_2000_LOSSLESS) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_2000_LOSSLESS;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_JPEG_2000) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_JPEG_2000;
} else if (strTagVal == TRANSFER_SYNTAX_COMPRESSION_RLE) {
this.m_transformSyntax = TRANSFER_SYNTAX_COMPRESSION_RLE;
} else {
this.m_explicit = true;
this.m_littleEndian = true;
}
} else if (tag.isMetaLength()) {
this.m_metaFinishedOffset = tag.m_value[0] + offset;
}
return tag;
} // getNextTag