dcmjs 0.49.3 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/build/dcmjs.es.js +1071 -112
- package/build/dcmjs.es.js.map +1 -1
- package/build/dcmjs.js +1071 -112
- package/build/dcmjs.js.map +1 -1
- package/build/dcmjs.min.js +2 -2
- package/build/dcmjs.min.js.map +1 -1
- package/generate/dictionary.mjs +56029 -0
- package/package.json +18 -2
- package/.babelrc +0 -9
- package/.github/workflows/lint-and-format.yml +0 -27
- package/.github/workflows/publish-package.yml +0 -45
- package/.github/workflows/tests.yml +0 -24
- package/.prettierrc +0 -5
- package/.vscode/extensions.json +0 -7
- package/.vscode/settings.json +0 -8
- package/changelog.md +0 -31
- package/docs/ArrayBufferExpanderListener.md +0 -303
- package/docs/AsyncDicomReader-skill.md +0 -730
- package/eslint.config.mjs +0 -30
- package/generate-dictionary.js +0 -145
- package/jest.setup.js +0 -39
- package/netlify.toml +0 -22
- package/rollup.config.mjs +0 -57
- package/test/ArrayBufferExpanderListener.test.js +0 -365
- package/test/DICOMWEB.test.js +0 -1
- package/test/DicomMetaDictionary.test.js +0 -73
- package/test/SequenceOfItems.test.js +0 -86
- package/test/adapters.test.js +0 -43
- package/test/anonymizer.test.js +0 -176
- package/test/arrayItem.json +0 -351
- package/test/async-data.test.js +0 -575
- package/test/data-encoding.test.js +0 -59
- package/test/data-options.test.js +0 -199
- package/test/data.test.js +0 -1776
- package/test/derivations.test.js +0 -1
- package/test/helper/DicomDataReadBufferStreamBuilder.js +0 -89
- package/test/information-filter.test.js +0 -165
- package/test/integration/DicomMessage.readFile.test.js +0 -50
- package/test/lossless-read-write.test.js +0 -1407
- package/test/mocks/minimal_fields_dataset.json +0 -17
- package/test/mocks/null_number_vrs_dataset.json +0 -102
- package/test/normalizers.test.js +0 -38
- package/test/odd-frame-bit-data.js +0 -138
- package/test/rawTags.js +0 -170
- package/test/readBufferStream.test.js +0 -158
- package/test/sample-dicom.json +0 -904
- package/test/sample-op.lei +0 -0
- package/test/sample-sr.json +0 -997
- package/test/sr-tid.test.js +0 -251
- package/test/testUtils.js +0 -85
- package/test/utilities/deepEqual.test.js +0 -87
- package/test/utilities.test.js +0 -205
- package/test/video-test-dict.js +0 -40
- package/test/writeBufferStream.test.js +0 -149
package/test/derivations.test.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
it("No tests yet", () => {});
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { ReadBufferStream } from "../../src/BufferStream";
|
|
2
|
-
import {
|
|
3
|
-
ITEM_DELIMITATION_LENGTH,
|
|
4
|
-
SEQUENCE_DELIMITATION_VALUE,
|
|
5
|
-
UNDEFINED_LENGTH
|
|
6
|
-
} from "../../src/constants/dicom";
|
|
7
|
-
import { DicomMetaDictionary } from "../../src/DicomMetaDictionary";
|
|
8
|
-
|
|
9
|
-
export class DicomDataReadBufferStreamBuilder {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.itemArray = [];
|
|
12
|
-
this.options = {
|
|
13
|
-
ignoreErrors: false,
|
|
14
|
-
untilTag: null,
|
|
15
|
-
includeUntilTagValue: false,
|
|
16
|
-
noCopy: false
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
addSequenceDelimitationTagAndValue() {
|
|
21
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(
|
|
22
|
-
DicomMetaDictionary.tagAsIntegerFromName("SequenceDelimitationItem")
|
|
23
|
-
);
|
|
24
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(
|
|
25
|
-
SEQUENCE_DELIMITATION_VALUE
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
addUndefinedLengthItem() {
|
|
30
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(
|
|
31
|
-
DicomMetaDictionary.tagAsIntegerFromName("Item")
|
|
32
|
-
);
|
|
33
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(UNDEFINED_LENGTH);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
addUndefinedLengthItemDelimitation() {
|
|
37
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(
|
|
38
|
-
DicomMetaDictionary.tagAsIntegerFromName("ItemDelimitationItem")
|
|
39
|
-
);
|
|
40
|
-
this.splitIntoFourTwoByteItemsAndAddToDataArray(
|
|
41
|
-
ITEM_DELIMITATION_LENGTH
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Converts a 8 byte hexadecimal value into a 4 * 2 byte String values array.
|
|
47
|
-
* (0xfffee00d -> ['0xff', '0xfe', '0xe0', 0x0d'])
|
|
48
|
-
*/
|
|
49
|
-
splitIntoFourTwoByteItemsAndAddToDataArray(hexValue) {
|
|
50
|
-
let hexValueItemArray = [];
|
|
51
|
-
|
|
52
|
-
for (
|
|
53
|
-
let index = 0;
|
|
54
|
-
index < hexValue.toString(16).length;
|
|
55
|
-
index = index + 2
|
|
56
|
-
) {
|
|
57
|
-
hexValueItemArray.push(
|
|
58
|
-
"0x" + hexValue.toString(16).slice(index, index + 2)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ensure 4 items in the array
|
|
63
|
-
while (hexValueItemArray.length < 4) {
|
|
64
|
-
hexValueItemArray = ["0x00"].concat(hexValueItemArray);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.itemArray = this.itemArray.concat(hexValueItemArray);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Adds a "File Meta Information Group Length" tag (0002,0000) with the length 4 and the value 4 to the stream.
|
|
72
|
-
*/
|
|
73
|
-
addUlExampleItem() {
|
|
74
|
-
const fileMetaInfoGroupLengthTag = ["0x02", "0x00", "0x00", "0x00"];
|
|
75
|
-
const length = ["0x04", "0x00", "0x00", "0x00"];
|
|
76
|
-
const item = ["0x04", "0x00", "0x00", "0x00"];
|
|
77
|
-
|
|
78
|
-
this.itemArray = this.itemArray.concat(fileMetaInfoGroupLengthTag);
|
|
79
|
-
this.itemArray = this.itemArray.concat(length);
|
|
80
|
-
this.itemArray = this.itemArray.concat(item);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
build() {
|
|
84
|
-
const byteArray = new Uint8Array(this.itemArray);
|
|
85
|
-
return new ReadBufferStream(byteArray.buffer, null, {
|
|
86
|
-
noCopy: this.options.noCopy
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import { AsyncDicomReader } from "../src/AsyncDicomReader";
|
|
3
|
-
import {
|
|
4
|
-
DicomMetadataListener,
|
|
5
|
-
createInformationFilter
|
|
6
|
-
} from "../src/utilities/DicomMetadataListener";
|
|
7
|
-
import { TagHex } from "../src/constants/dicom";
|
|
8
|
-
|
|
9
|
-
describe("Information Filter", () => {
|
|
10
|
-
test("listener.information is populated with default tags", async () => {
|
|
11
|
-
const buffer = fs.readFileSync("test/sample-dicom.dcm");
|
|
12
|
-
const reader = new AsyncDicomReader();
|
|
13
|
-
const listener = new DicomMetadataListener();
|
|
14
|
-
|
|
15
|
-
reader.stream.addBuffer(buffer);
|
|
16
|
-
reader.stream.setComplete();
|
|
17
|
-
|
|
18
|
-
await reader.readFile({ listener });
|
|
19
|
-
|
|
20
|
-
// Verify that information object exists
|
|
21
|
-
expect(listener.information).toBeDefined();
|
|
22
|
-
|
|
23
|
-
// Verify that tracked tags are present in information
|
|
24
|
-
expect(listener.information.rows).toBe(512);
|
|
25
|
-
expect(listener.information.columns).toBe(512);
|
|
26
|
-
|
|
27
|
-
// Check that UIDs are populated if available in the test file
|
|
28
|
-
if (listener.information.studyInstanceUid) {
|
|
29
|
-
expect(typeof listener.information.studyInstanceUid).toBe("string");
|
|
30
|
-
}
|
|
31
|
-
if (listener.information.seriesInstanceUid) {
|
|
32
|
-
expect(typeof listener.information.seriesInstanceUid).toBe(
|
|
33
|
-
"string"
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
if (listener.information.sopInstanceUid) {
|
|
37
|
-
expect(typeof listener.information.sopInstanceUid).toBe("string");
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("listener.information can be accessed for pixel data processing", async () => {
|
|
42
|
-
const buffer = fs.readFileSync("test/sample-dicom.dcm");
|
|
43
|
-
const reader = new AsyncDicomReader();
|
|
44
|
-
const listener = new DicomMetadataListener();
|
|
45
|
-
|
|
46
|
-
reader.stream.addBuffer(buffer);
|
|
47
|
-
reader.stream.setComplete();
|
|
48
|
-
|
|
49
|
-
const { dict } = await reader.readFile({ listener });
|
|
50
|
-
|
|
51
|
-
// Verify that pixel data was read correctly using information
|
|
52
|
-
expect(dict[TagHex.PixelData]).toBeDefined();
|
|
53
|
-
expect(dict[TagHex.PixelData].Value[0]).toBeDefined();
|
|
54
|
-
|
|
55
|
-
// Verify information was used correctly (no errors during reading)
|
|
56
|
-
expect(listener.information.rows).toBe(512);
|
|
57
|
-
expect(listener.information.columns).toBe(512);
|
|
58
|
-
expect(listener.information.bitsAllocated).toBe(16);
|
|
59
|
-
expect(listener.information.samplesPerPixel).toBe(1);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("custom information tags can be specified", async () => {
|
|
63
|
-
const buffer = fs.readFileSync("test/sample-dicom.dcm");
|
|
64
|
-
const reader = new AsyncDicomReader();
|
|
65
|
-
|
|
66
|
-
// Only track specific tags
|
|
67
|
-
const customTags = new Set([TagHex.Rows, TagHex.Columns]);
|
|
68
|
-
const listener = new DicomMetadataListener({
|
|
69
|
-
informationTags: customTags
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
reader.stream.addBuffer(buffer);
|
|
73
|
-
reader.stream.setComplete();
|
|
74
|
-
|
|
75
|
-
await reader.readFile({ listener });
|
|
76
|
-
|
|
77
|
-
// Verify that only tracked tags are present
|
|
78
|
-
expect(listener.information.rows).toBe(512);
|
|
79
|
-
expect(listener.information.columns).toBe(512);
|
|
80
|
-
|
|
81
|
-
// Other default tags should not be tracked
|
|
82
|
-
expect(listener.information.bitsAllocated).toBeUndefined();
|
|
83
|
-
expect(listener.information.samplesPerPixel).toBeUndefined();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("information contains normalized camelCase names", async () => {
|
|
87
|
-
const buffer = fs.readFileSync("test/sample-dicom.dcm");
|
|
88
|
-
const reader = new AsyncDicomReader();
|
|
89
|
-
const listener = new DicomMetadataListener();
|
|
90
|
-
|
|
91
|
-
reader.stream.addBuffer(buffer);
|
|
92
|
-
reader.stream.setComplete();
|
|
93
|
-
|
|
94
|
-
await reader.readFile({ listener });
|
|
95
|
-
|
|
96
|
-
// Verify normalized naming (lower camel case)
|
|
97
|
-
expect(listener.information).toHaveProperty("rows");
|
|
98
|
-
expect(listener.information).toHaveProperty("columns");
|
|
99
|
-
expect(listener.information).toHaveProperty("samplesPerPixel");
|
|
100
|
-
expect(listener.information).toHaveProperty("bitsAllocated");
|
|
101
|
-
|
|
102
|
-
// Verify UID becomes Uid (not UID)
|
|
103
|
-
if (listener.information.studyInstanceUid !== undefined) {
|
|
104
|
-
expect(listener.information).toHaveProperty("studyInstanceUid");
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("multiframe data uses information for frame processing", async () => {
|
|
109
|
-
const url =
|
|
110
|
-
"https://github.com/dcmjs-org/data/releases/download/binary-parsing-stressors/multiframe-ultrasound.dcm";
|
|
111
|
-
const dcmPath = await import("./testUtils.js").then(m =>
|
|
112
|
-
m.getTestDataset(url, "multiframe-ultrasound.dcm")
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const reader = new AsyncDicomReader();
|
|
116
|
-
const listener = new DicomMetadataListener();
|
|
117
|
-
|
|
118
|
-
const stream = fs.createReadStream(dcmPath, {
|
|
119
|
-
highWaterMark: 4001
|
|
120
|
-
});
|
|
121
|
-
reader.stream.fromAsyncStream(stream);
|
|
122
|
-
|
|
123
|
-
const { dict } = await reader.readFile({ listener });
|
|
124
|
-
|
|
125
|
-
// Verify information was populated
|
|
126
|
-
expect(listener.information.numberOfFrames).toBe(29);
|
|
127
|
-
|
|
128
|
-
// Verify frames were read correctly
|
|
129
|
-
const frames = dict[TagHex.PixelData].Value;
|
|
130
|
-
expect(frames.length).toBe(29);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("custom informationFilter can be passed to listener", async () => {
|
|
134
|
-
const buffer = fs.readFileSync("test/sample-dicom.dcm");
|
|
135
|
-
const reader = new AsyncDicomReader();
|
|
136
|
-
|
|
137
|
-
// Create a custom information object to track the filter was used
|
|
138
|
-
const customInformation = {};
|
|
139
|
-
const customFilter = createInformationFilter();
|
|
140
|
-
|
|
141
|
-
// Pass the custom filter via options
|
|
142
|
-
const listener = new DicomMetadataListener({
|
|
143
|
-
information: customInformation,
|
|
144
|
-
informationFilter: customFilter
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
reader.stream.addBuffer(buffer);
|
|
148
|
-
reader.stream.setComplete();
|
|
149
|
-
|
|
150
|
-
const { meta } = await reader.readFile({ listener });
|
|
151
|
-
|
|
152
|
-
// Verify that the custom information object was populated
|
|
153
|
-
expect(listener.information).toBe(customInformation);
|
|
154
|
-
expect(listener.information).toBeDefined();
|
|
155
|
-
|
|
156
|
-
// Verify rows and columns are accessible
|
|
157
|
-
expect(listener.information.rows).toBe(512);
|
|
158
|
-
expect(listener.information.columns).toBe(512);
|
|
159
|
-
|
|
160
|
-
// Verify transfer syntax UID is accessible from meta
|
|
161
|
-
expect(meta[TagHex.TransferSyntaxUID].Value[0]).toBe(
|
|
162
|
-
"1.2.840.10008.1.2"
|
|
163
|
-
);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import dcmjs from "../../src/index.js";
|
|
4
|
-
import { validationLog } from "./../../src/log.js";
|
|
5
|
-
|
|
6
|
-
// Ignore validation errors
|
|
7
|
-
validationLog.setLevel(5);
|
|
8
|
-
|
|
9
|
-
const { DicomMessage } = dcmjs.data;
|
|
10
|
-
|
|
11
|
-
describe("test parsing of sample-dicom.dcm file", () => {
|
|
12
|
-
const dicomTestFilesDataPath = path.join(
|
|
13
|
-
__dirname,
|
|
14
|
-
"./../sample-dicom.dcm"
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
const arrayBuffer = fs.readFileSync(dicomTestFilesDataPath).buffer;
|
|
18
|
-
const dicomDict = DicomMessage.readFile(arrayBuffer);
|
|
19
|
-
|
|
20
|
-
it("has dict and meta section", () => {
|
|
21
|
-
expect(dicomDict["dict"]).not.toBeNull();
|
|
22
|
-
expect(dicomDict["meta"]).not.toBeNull();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe("test some tags from the dict section", () => {
|
|
26
|
-
const dictTags = dicomDict["dict"];
|
|
27
|
-
|
|
28
|
-
it("has the StudyDate", () => {
|
|
29
|
-
expect(dictTags).toHaveProperty("00080020.Value[0]", "20010101");
|
|
30
|
-
});
|
|
31
|
-
// testing nested sequence parsing
|
|
32
|
-
it("has the RequestAttributesSequence -> ScheduledProtocolCodeSequence -> CodeValue", () => {
|
|
33
|
-
expect(dictTags).toHaveProperty(
|
|
34
|
-
"00400275.Value[0].00400008.Value[0].00080100.Value[0]",
|
|
35
|
-
"6310"
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe("test some tags from the meta section", () => {
|
|
41
|
-
const metaTags = dicomDict["meta"];
|
|
42
|
-
|
|
43
|
-
it("has the TransferSyntaxUID", () => {
|
|
44
|
-
expect(metaTags).toHaveProperty(
|
|
45
|
-
"00020010.Value[0]",
|
|
46
|
-
"1.2.840.10008.1.2"
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|