forked from cornerstonejs/dicomParser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparseDicom.js
152 lines (136 loc) · 6.75 KB
/
parseDicom.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* 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 the byte array
* @param options object to control parsing behavior (optional)
* @returns {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.
*/
var dicomParser = (function(dicomParser) {
if(dicomParser === undefined)
{
dicomParser = {};
}
dicomParser.parseDicom = function(byteArray, options) {
if(byteArray === undefined)
{
throw "dicomParser.parseDicom: missing required parameter 'byteArray'";
}
function readTransferSyntax(metaHeaderDataSet) {
if(metaHeaderDataSet.elements.x00020010 === undefined) {
throw 'dicomParser.parseDicom: missing required meta header attribute 0002,0010';
}
var transferSyntaxElement = metaHeaderDataSet.elements.x00020010;
return dicomParser.readFixedString(byteArray, transferSyntaxElement.dataOffset, transferSyntaxElement.length);
}
function isExplicit(transferSyntax) {
if(transferSyntax === '1.2.840.10008.1.2') // implicit little endian
{
return false;
}
// all other transfer syntaxes should be explicit
return true;
}
function getDataSetByteStream(transferSyntax, position) {
if(transferSyntax === '1.2.840.10008.1.2.1.99')
{
// if an infalter callback is registered, use it
if (options && options.inflater) {
var fullByteArrayCallback = options.inflater(byteArray, position);
return new dicomParser.ByteStream(dicomParser.littleEndianByteArrayParser, fullByteArrayCallback, 0);
}
// if running on node, use the zlib library to inflate
// http://stackoverflow.com/questions/4224606/how-to-check-whether-a-script-is-running-under-node-js
else if (typeof module !== 'undefined' && this.module !== module) {
// inflate it
var zlib = require('zlib');
var deflatedBuffer = dicomParser.sharedCopy(byteArray, position, byteArray.length - position);
var inflatedBuffer = zlib.inflateRawSync(deflatedBuffer);
// create a single byte array with the full header bytes and the inflated bytes
var fullByteArrayBuffer = dicomParser.alloc(byteArray, inflatedBuffer.length + position);
byteArray.copy(fullByteArrayBuffer, 0, 0, position);
inflatedBuffer.copy(fullByteArrayBuffer, position);
return new dicomParser.ByteStream(dicomParser.littleEndianByteArrayParser, fullByteArrayBuffer, 0);
}
// if pako is defined - use it. This is the web browser path
// https://github.com/nodeca/pako
else if(typeof pako !== "undefined") {
// inflate it
var deflated = byteArray.slice(position);
var inflated = pako.inflateRaw(deflated);
// create a single byte array with the full header bytes and the inflated bytes
var fullByteArray = dicomParser.alloc(byteArray, inflated.length + position);
fullByteArray.set(byteArray.slice(0, position), 0);
fullByteArray.set(inflated, position);
return new dicomParser.ByteStream(dicomParser.littleEndianByteArrayParser, fullByteArray, 0);
}
// throw exception since no inflater is available
else {
throw 'dicomParser.parseDicom: no inflater available to handle deflate transfer syntax';
}
}
if(transferSyntax === '1.2.840.10008.1.2.2') // explicit big endian
{
return new dicomParser.ByteStream(dicomParser.bigEndianByteArrayParser, byteArray, position);
}
else
{
// all other transfer syntaxes are little endian; only the pixel encoding differs
// make a new stream so the metaheader warnings don't come along for the ride
return new dicomParser.ByteStream(dicomParser.littleEndianByteArrayParser, byteArray, position);
}
}
function mergeDataSets(metaHeaderDataSet, instanceDataSet)
{
for (var propertyName in metaHeaderDataSet.elements)
{
if(metaHeaderDataSet.elements.hasOwnProperty(propertyName))
{
instanceDataSet.elements[propertyName] = metaHeaderDataSet.elements[propertyName];
}
}
if (metaHeaderDataSet.warnings !== undefined) {
instanceDataSet.warnings = metaHeaderDataSet.warnings.concat(instanceDataSet.warnings);
}
return instanceDataSet;
}
function readDataSet(metaHeaderDataSet)
{
var transferSyntax = readTransferSyntax(metaHeaderDataSet);
var explicit = isExplicit(transferSyntax);
var dataSetByteStream = getDataSetByteStream(transferSyntax, metaHeaderDataSet.position);
var elements = {};
var dataSet = new dicomParser.DataSet(dataSetByteStream.byteArrayParser, dataSetByteStream.byteArray, elements);
dataSet.warnings = dataSetByteStream.warnings;
try{
if(explicit) {
dicomParser.parseDicomDataSetExplicit(dataSet, dataSetByteStream, dataSetByteStream.byteArray.length, options);
}
else
{
dicomParser.parseDicomDataSetImplicit(dataSet, dataSetByteStream, dataSetByteStream.byteArray.length, options);
}
}
catch(e) {
var ex = {
exception: e,
dataSet: dataSet
};
throw ex;
}
return dataSet;
}
// main function here
function parseTheByteStream() {
var metaHeaderDataSet = dicomParser.readPart10Header(byteArray, options);
var dataSet = readDataSet(metaHeaderDataSet);
return mergeDataSets(metaHeaderDataSet, dataSet);
}
// This is where we actually start parsing
return parseTheByteStream();
};
return dicomParser;
})(dicomParser);