@cornerstonejs/dicom-image-loader 5.0.0-beta.1 → 5.0.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/dist/esm/decodeImageFrameWorker.js +0 -4
- package/dist/esm/imageLoader/colorSpaceConverters/convertPALETTECOLOR.js +1 -1
- package/dist/esm/imageLoader/createImage.js +99 -4
- package/dist/esm/imageLoader/getInstanceModule.js +0 -2
- package/dist/esm/imageLoader/getScalingParameters.js +8 -2
- package/dist/esm/imageLoader/index.d.ts +2 -1
- package/dist/esm/imageLoader/registerLoaders.d.ts +3 -1
- package/dist/esm/imageLoader/registerLoaders.js +11 -3
- package/dist/esm/imageLoader/wadors/metaData/metaDataProvider.js +0 -51
- package/dist/esm/imageLoader/wadors/register.d.ts +3 -1
- package/dist/esm/imageLoader/wadors/register.js +8 -1
- package/dist/esm/imageLoader/wadouri/dataSetCacheManager.js +2 -2
- package/dist/esm/imageLoader/wadouri/dataset-from-partial-content.js +3 -3
- package/dist/esm/imageLoader/wadouri/index.d.ts +4 -3
- package/dist/esm/imageLoader/wadouri/index.js +3 -2
- package/dist/esm/imageLoader/wadouri/loadImage.d.ts +4 -2
- package/dist/esm/imageLoader/wadouri/loadImage.js +84 -10
- package/dist/esm/imageLoader/wadouri/parseDicomWithInflater.d.ts +7 -0
- package/dist/esm/imageLoader/wadouri/parseDicomWithInflater.js +17 -0
- package/dist/esm/imageLoader/wadouri/register.d.ts +4 -1
- package/dist/esm/imageLoader/wadouri/register.js +16 -6
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/init.js +1 -1
- package/dist/esm/types/LoaderOptions.d.ts +1 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +13 -7
|
@@ -81,10 +81,6 @@ export function postProcessDecodedPixels(imageFrame, options, start, decodeConfi
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
else if (disableScale) {
|
|
84
|
-
imageFrame.preScale = {
|
|
85
|
-
enabled: true,
|
|
86
|
-
scaled: false,
|
|
87
|
-
};
|
|
88
84
|
minAfterScale = minBeforeScale;
|
|
89
85
|
maxAfterScale = maxBeforeScale;
|
|
90
86
|
}
|
|
@@ -21,7 +21,7 @@ export default function convertPaletteColor(imageFrame, colorBuffer, useRGBA) {
|
|
|
21
21
|
let bufferIndex = 0;
|
|
22
22
|
const start = imageFrame.redPaletteColorLookupTableDescriptor[1];
|
|
23
23
|
const bitsStored = imageFrame.redPaletteColorLookupTableDescriptor[2];
|
|
24
|
-
const shift = bitsStored > 8
|
|
24
|
+
const shift = bitsStored > 8 && rData.some((num) => num > 255) ? 8 : 0;
|
|
25
25
|
const rDataCleaned = convertLUTto8Bit(rData, shift);
|
|
26
26
|
const gDataCleaned = convertLUTto8Bit(gData, shift);
|
|
27
27
|
const bDataCleaned = convertLUTto8Bit(bData, shift);
|
|
@@ -28,6 +28,13 @@ async function createImage(imageId, pixelData, transferSyntax, options = {}) {
|
|
|
28
28
|
imageFrame.decodeLevel = options.decodeLevel;
|
|
29
29
|
options.allowFloatRendering = canRenderFloatTextures();
|
|
30
30
|
let redData, greenData, blueData;
|
|
31
|
+
const paletteDescriptors = imageFrame.photometricInterpretation === 'PALETTE COLOR'
|
|
32
|
+
? {
|
|
33
|
+
red: imageFrame.redPaletteColorLookupTableDescriptor,
|
|
34
|
+
green: imageFrame.greenPaletteColorLookupTableDescriptor,
|
|
35
|
+
blue: imageFrame.bluePaletteColorLookupTableDescriptor,
|
|
36
|
+
}
|
|
37
|
+
: null;
|
|
31
38
|
if (imageFrame.photometricInterpretation === 'PALETTE COLOR') {
|
|
32
39
|
[redData, greenData, blueData] = await Promise.all([
|
|
33
40
|
fetchPaletteData(imageFrame, 'red', null),
|
|
@@ -43,6 +50,9 @@ async function createImage(imageId, pixelData, transferSyntax, options = {}) {
|
|
|
43
50
|
scalingParameters: scalingParameters,
|
|
44
51
|
};
|
|
45
52
|
}
|
|
53
|
+
else {
|
|
54
|
+
options.preScale.enabled = false;
|
|
55
|
+
}
|
|
46
56
|
}
|
|
47
57
|
const { decodeConfig } = getOptions();
|
|
48
58
|
Object.keys(imageFrame).forEach((key) => {
|
|
@@ -94,7 +104,42 @@ async function createImage(imageId, pixelData, transferSyntax, options = {}) {
|
|
|
94
104
|
const sopCommonModule = metaData.get(MetadataModules.SOP_COMMON, imageId) || {};
|
|
95
105
|
const calibrationModule = metaData.get(MetadataModules.CALIBRATION, imageId) || {};
|
|
96
106
|
const { rows, columns } = imageFrame;
|
|
97
|
-
if (imageFrame.photometricInterpretation === 'PALETTE COLOR'
|
|
107
|
+
if (imageFrame.photometricInterpretation === 'PALETTE COLOR' &&
|
|
108
|
+
paletteDescriptors) {
|
|
109
|
+
const normalizeLutIfBytes = (data, descriptor) => {
|
|
110
|
+
if (data == null || !descriptor || descriptor.length < 3)
|
|
111
|
+
return data;
|
|
112
|
+
const tableLen = descriptor[0];
|
|
113
|
+
const bits = descriptor[2];
|
|
114
|
+
if (bits !== 16 || tableLen <= 0)
|
|
115
|
+
return data;
|
|
116
|
+
const expectedBytes = tableLen * 2;
|
|
117
|
+
let view = null;
|
|
118
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
119
|
+
const first = data[0];
|
|
120
|
+
if (first instanceof ArrayBuffer) {
|
|
121
|
+
view = new Uint8Array(first);
|
|
122
|
+
}
|
|
123
|
+
else if (ArrayBuffer.isView(first)) {
|
|
124
|
+
view = first;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (data instanceof ArrayBuffer) {
|
|
128
|
+
view = new Uint8Array(data);
|
|
129
|
+
}
|
|
130
|
+
else if (ArrayBuffer.isView(data)) {
|
|
131
|
+
view = data;
|
|
132
|
+
}
|
|
133
|
+
if (view && view.byteLength === expectedBytes) {
|
|
134
|
+
return new Uint16Array(view.buffer, view.byteOffset, tableLen);
|
|
135
|
+
}
|
|
136
|
+
return data;
|
|
137
|
+
};
|
|
138
|
+
imageFrame.redPaletteColorLookupTableData = normalizeLutIfBytes(redData, paletteDescriptors.red);
|
|
139
|
+
imageFrame.greenPaletteColorLookupTableData = normalizeLutIfBytes(greenData, paletteDescriptors.green);
|
|
140
|
+
imageFrame.bluePaletteColorLookupTableData = normalizeLutIfBytes(blueData, paletteDescriptors.blue);
|
|
141
|
+
}
|
|
142
|
+
else if (imageFrame.photometricInterpretation === 'PALETTE COLOR') {
|
|
98
143
|
imageFrame.redPaletteColorLookupTableData = redData;
|
|
99
144
|
imageFrame.greenPaletteColorLookupTableData = greenData;
|
|
100
145
|
imageFrame.bluePaletteColorLookupTableData = blueData;
|
|
@@ -111,6 +156,55 @@ async function createImage(imageId, pixelData, transferSyntax, options = {}) {
|
|
|
111
156
|
data: new Uint8ClampedArray(3 * imageFrame.columns * imageFrame.rows),
|
|
112
157
|
};
|
|
113
158
|
}
|
|
159
|
+
if (imageFrame.photometricInterpretation === 'PALETTE COLOR') {
|
|
160
|
+
const pd = imageFrame.pixelData;
|
|
161
|
+
const len = pd?.length ?? 0;
|
|
162
|
+
const sliceSize = Math.min(40, len);
|
|
163
|
+
const r = imageFrame.redPaletteColorLookupTableData;
|
|
164
|
+
const g = imageFrame.greenPaletteColorLookupTableData;
|
|
165
|
+
const b = imageFrame.bluePaletteColorLookupTableData;
|
|
166
|
+
const desc = imageFrame.redPaletteColorLookupTableDescriptor;
|
|
167
|
+
const lutLen = (x) => x != null &&
|
|
168
|
+
typeof x.length === 'number'
|
|
169
|
+
? x.length
|
|
170
|
+
: null;
|
|
171
|
+
const lutByteLen = (x) => {
|
|
172
|
+
if (x == null)
|
|
173
|
+
return null;
|
|
174
|
+
if (x instanceof ArrayBuffer)
|
|
175
|
+
return x.byteLength;
|
|
176
|
+
if (ArrayBuffer.isView(x))
|
|
177
|
+
return x.byteLength;
|
|
178
|
+
return null;
|
|
179
|
+
};
|
|
180
|
+
const first10 = (x) => x != null &&
|
|
181
|
+
typeof x.length === 'number'
|
|
182
|
+
? Array.from(x).slice(0, 10)
|
|
183
|
+
: null;
|
|
184
|
+
console.log('[createImage] PALETTE COLOR before convertColorSpace', {
|
|
185
|
+
imageId,
|
|
186
|
+
descriptor: desc,
|
|
187
|
+
pixelDataLength: len,
|
|
188
|
+
pixelDataSlice: sliceSize > 0 && pd
|
|
189
|
+
? Array.from({ length: sliceSize }, (_, i) => pd[i])
|
|
190
|
+
: [],
|
|
191
|
+
redLUT: {
|
|
192
|
+
length: lutLen(r),
|
|
193
|
+
byteLength: lutByteLen(r),
|
|
194
|
+
first10: first10(r),
|
|
195
|
+
},
|
|
196
|
+
greenLUT: {
|
|
197
|
+
length: lutLen(g),
|
|
198
|
+
byteLength: lutByteLen(g),
|
|
199
|
+
first10: first10(g),
|
|
200
|
+
},
|
|
201
|
+
blueLUT: {
|
|
202
|
+
length: lutLen(b),
|
|
203
|
+
byteLength: lutByteLen(b),
|
|
204
|
+
first10: first10(b),
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
114
208
|
convertColorSpace(imageFrame, imageData.data, useRGBA);
|
|
115
209
|
imageFrame.imageData = imageData;
|
|
116
210
|
imageFrame.pixelData = imageData.data;
|
|
@@ -165,9 +259,10 @@ async function createImage(imageId, pixelData, transferSyntax, options = {}) {
|
|
|
165
259
|
windowWidth: voiLutModule.windowWidth
|
|
166
260
|
? voiLutModule.windowWidth[0]
|
|
167
261
|
: undefined,
|
|
168
|
-
voiLUTFunction: voiLutModule.voiLUTFunction
|
|
169
|
-
|
|
170
|
-
|
|
262
|
+
voiLUTFunction: (voiLutModule.voiLUTFunction?.length &&
|
|
263
|
+
voiLutModule.voiLUTFunction[0]) ||
|
|
264
|
+
voiLutModule.voiLutFunction ||
|
|
265
|
+
undefined,
|
|
171
266
|
decodeTimeInMS: imageFrame.decodeTimeInMS,
|
|
172
267
|
floatPixelData: undefined,
|
|
173
268
|
imageFrame,
|
|
@@ -3,9 +3,15 @@ export default function getScalingParameters(metaData, imageId) {
|
|
|
3
3
|
const generalSeriesModule = (metaData.get('generalSeriesModule', imageId) ||
|
|
4
4
|
{});
|
|
5
5
|
const { modality } = generalSeriesModule;
|
|
6
|
+
const rescaleSlope = modalityLutModule.rescaleSlope;
|
|
7
|
+
const rescaleIntercept = modalityLutModule.rescaleIntercept;
|
|
8
|
+
if (rescaleSlope === 1 &&
|
|
9
|
+
(rescaleIntercept === 0 || rescaleIntercept == null)) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
6
12
|
const scalingParameters = {
|
|
7
|
-
rescaleSlope
|
|
8
|
-
rescaleIntercept
|
|
13
|
+
rescaleSlope,
|
|
14
|
+
rescaleIntercept,
|
|
9
15
|
modality,
|
|
10
16
|
};
|
|
11
17
|
const scalingModules = metaData.get('scalingModule', imageId) || {};
|
|
@@ -53,7 +53,8 @@ declare const cornerstoneDICOMImageLoader: {
|
|
|
53
53
|
loadImageFromPromise: typeof import("./wadouri/loadImage").loadImageFromPromise;
|
|
54
54
|
getLoaderForScheme: typeof import("./wadouri/loadImage").getLoaderForScheme;
|
|
55
55
|
getPixelData: typeof import("./wadouri/getPixelData").default;
|
|
56
|
-
loadImage:
|
|
56
|
+
loadImage: (imageId: string, options?: import("../types").DICOMLoaderImageOptions) => import("packages/core/dist/esm/types").IImageLoadObject;
|
|
57
|
+
loadImageFromNaturalizedMetadata: typeof import("./wadouri/loadImage").loadImageFromNaturalizedMetadata;
|
|
57
58
|
parseImageId: typeof import("./wadouri/parseImageId").default;
|
|
58
59
|
unpackBinaryFrame: typeof import("./wadouri/unpackBinaryFrame").default;
|
|
59
60
|
register: typeof import("./wadouri/register").default;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { cache } from '@cornerstonejs/core';
|
|
2
|
+
import { utilities } from '@cornerstonejs/metadata';
|
|
3
|
+
import dataSetCacheManager from './wadouri/dataSetCacheManager';
|
|
4
|
+
import wadorsMetaDataManager from './wadors/metaDataManager';
|
|
1
5
|
import wadouriRegister from './wadouri/register';
|
|
2
6
|
import wadorsRegister from './wadors/register';
|
|
3
|
-
function registerLoaders() {
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
function registerLoaders(options) {
|
|
8
|
+
cache.purgeCache();
|
|
9
|
+
dataSetCacheManager.purge();
|
|
10
|
+
wadorsMetaDataManager.purge();
|
|
11
|
+
utilities.clearCacheData();
|
|
12
|
+
wadorsRegister(options);
|
|
13
|
+
wadouriRegister(options);
|
|
6
14
|
}
|
|
7
15
|
export default registerLoaders;
|
|
@@ -10,7 +10,6 @@ import { getImageTypeSubItemFromMetadata } from './NMHelpers';
|
|
|
10
10
|
import isNMReconstructable from '../../isNMReconstructable';
|
|
11
11
|
import { instanceModuleNames } from '../../getInstanceModule';
|
|
12
12
|
import { getUSEnhancedRegions } from './USHelpers';
|
|
13
|
-
import { getECGModule } from './ECGHelpers';
|
|
14
13
|
function metaDataProvider(type, imageId) {
|
|
15
14
|
const { MetadataModules } = Enums;
|
|
16
15
|
if (type === MetadataModules.MULTIFRAME) {
|
|
@@ -154,20 +153,6 @@ function metaDataProvider(type, imageId) {
|
|
|
154
153
|
if (type === MetadataModules.ULTRASOUND_ENHANCED_REGION) {
|
|
155
154
|
return getUSEnhancedRegions(metaData);
|
|
156
155
|
}
|
|
157
|
-
if (type === MetadataModules.ECG) {
|
|
158
|
-
const imageUri = imageId.replace('wadors:', '');
|
|
159
|
-
const studiesIndex = imageUri.indexOf('/studies/');
|
|
160
|
-
let wadoRsRoot;
|
|
161
|
-
let studyUID;
|
|
162
|
-
if (studiesIndex !== -1) {
|
|
163
|
-
wadoRsRoot = imageUri.substring(0, studiesIndex);
|
|
164
|
-
const afterStudies = imageUri.substring(studiesIndex + 9);
|
|
165
|
-
const nextSlash = afterStudies.indexOf('/');
|
|
166
|
-
studyUID =
|
|
167
|
-
nextSlash !== -1 ? afterStudies.substring(0, nextSlash) : afterStudies;
|
|
168
|
-
}
|
|
169
|
-
return getECGModule(metaData, wadoRsRoot, studyUID);
|
|
170
|
-
}
|
|
171
156
|
if (type === MetadataModules.CALIBRATION) {
|
|
172
157
|
const modality = getValue(metaData['00080060']);
|
|
173
158
|
if (modality === 'US') {
|
|
@@ -176,42 +161,6 @@ function metaDataProvider(type, imageId) {
|
|
|
176
161
|
sequenceOfUltrasoundRegions: enhancedRegion,
|
|
177
162
|
};
|
|
178
163
|
}
|
|
179
|
-
const imageUri = imageId.replace('wadors:', '');
|
|
180
|
-
const studiesIndex = imageUri.indexOf('/studies/');
|
|
181
|
-
let wadoRsRoot;
|
|
182
|
-
let studyUID;
|
|
183
|
-
if (studiesIndex !== -1) {
|
|
184
|
-
wadoRsRoot = imageUri.substring(0, studiesIndex);
|
|
185
|
-
const afterStudies = imageUri.substring(studiesIndex + 9);
|
|
186
|
-
const nextSlash = afterStudies.indexOf('/');
|
|
187
|
-
studyUID =
|
|
188
|
-
nextSlash !== -1 ? afterStudies.substring(0, nextSlash) : afterStudies;
|
|
189
|
-
}
|
|
190
|
-
const ecgModule = getECGModule(metaData, wadoRsRoot, studyUID);
|
|
191
|
-
if (ecgModule) {
|
|
192
|
-
const { numberOfWaveformSamples, samplingFrequency } = ecgModule;
|
|
193
|
-
const physicalDeltaX = 1 / (samplingFrequency || 1);
|
|
194
|
-
const physicalDeltaY = 0.001;
|
|
195
|
-
const ECG_AMPLITUDE_INDEX_SIZE = 65536;
|
|
196
|
-
const ECG_AMPLITUDE_OFFSET = 32768;
|
|
197
|
-
return {
|
|
198
|
-
sequenceOfUltrasoundRegions: [
|
|
199
|
-
{
|
|
200
|
-
regionLocationMinX0: 0,
|
|
201
|
-
regionLocationMaxX1: numberOfWaveformSamples,
|
|
202
|
-
regionLocationMinY0: 0,
|
|
203
|
-
regionLocationMaxY1: ECG_AMPLITUDE_INDEX_SIZE - 1,
|
|
204
|
-
referencePixelX0: 0,
|
|
205
|
-
referencePixelY0: ECG_AMPLITUDE_OFFSET,
|
|
206
|
-
physicalDeltaX,
|
|
207
|
-
physicalDeltaY,
|
|
208
|
-
physicalUnitsXDirection: 4,
|
|
209
|
-
physicalUnitsYDirection: -1,
|
|
210
|
-
regionDataType: 1,
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
164
|
}
|
|
216
165
|
if (type === MetadataModules.IMAGE_URL) {
|
|
217
166
|
return getImageUrlModule(imageId, metaData);
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { metaData, registerImageLoader } from '@cornerstonejs/core';
|
|
2
2
|
import loadImage from './loadImage';
|
|
3
3
|
import { metaDataProvider } from './metaData';
|
|
4
|
-
|
|
4
|
+
import { registerDefaultProviders } from '@cornerstonejs/metadata';
|
|
5
|
+
export default function (options) {
|
|
5
6
|
registerImageLoader('wadors', loadImage);
|
|
7
|
+
if (options?.useLegacyMetadataProvider) {
|
|
8
|
+
console.warn('wadors metaDataProvider is deprecated. Use addDicomWebInstance from @cornerstonejs/metadata instead.');
|
|
9
|
+
metaData.addProvider(metaDataProvider);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
registerDefaultProviders();
|
|
6
13
|
metaData.addProvider(metaDataProvider);
|
|
7
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as dicomParser from 'dicom-parser';
|
|
2
1
|
import { xhrRequest } from '../internal/index';
|
|
2
|
+
import { parseDicom } from './parseDicomWithInflater';
|
|
3
3
|
import dataSetFromPartialContent from './dataset-from-partial-content';
|
|
4
4
|
import { combineFrameInstanceDataset } from './combineFrameInstanceDataset';
|
|
5
5
|
import multiframeDataset from './retrieveMultiframeDataset';
|
|
@@ -76,7 +76,7 @@ function load(uri, loadRequest = xhrRequest, imageId) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
else {
|
|
79
|
-
dataSet =
|
|
79
|
+
dataSet = parseDicom(byteArray);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { parseDicom } from './parseDicomWithInflater';
|
|
2
2
|
function fixFragments(dataSet) {
|
|
3
3
|
const fragments = dataSet.elements.x7fe00010.fragments;
|
|
4
4
|
const totalLength = dataSet.byteArray.length;
|
|
@@ -12,7 +12,7 @@ function fixFragments(dataSet) {
|
|
|
12
12
|
return dataSet;
|
|
13
13
|
}
|
|
14
14
|
function parsePartialByteArray(byteArray) {
|
|
15
|
-
let dataSet =
|
|
15
|
+
let dataSet = parseDicom(byteArray, {
|
|
16
16
|
untilTag: 'x7fe00010',
|
|
17
17
|
});
|
|
18
18
|
if (!dataSet.elements.x7fe00010) {
|
|
@@ -20,7 +20,7 @@ function parsePartialByteArray(byteArray) {
|
|
|
20
20
|
}
|
|
21
21
|
let pixelDataSet;
|
|
22
22
|
try {
|
|
23
|
-
pixelDataSet =
|
|
23
|
+
pixelDataSet = parseDicom(byteArray);
|
|
24
24
|
}
|
|
25
25
|
catch (err) {
|
|
26
26
|
console.error(err);
|
|
@@ -5,7 +5,7 @@ import getEncapsulatedImageFrame from './getEncapsulatedImageFrame';
|
|
|
5
5
|
import getUncompressedImageFrame from './getUncompressedImageFrame';
|
|
6
6
|
import loadFileRequest from './loadFileRequest';
|
|
7
7
|
import getPixelData from './getPixelData';
|
|
8
|
-
import { loadImageFromPromise, getLoaderForScheme, loadImage } from './loadImage';
|
|
8
|
+
import { loadImageFromPromise, getLoaderForScheme, loadImage, loadImageFromNaturalizedMetadata } from './loadImage';
|
|
9
9
|
import parseImageId from './parseImageId';
|
|
10
10
|
import unpackBinaryFrame from './unpackBinaryFrame';
|
|
11
11
|
import register from './register';
|
|
@@ -47,10 +47,11 @@ declare const _default: {
|
|
|
47
47
|
loadImageFromPromise: typeof loadImageFromPromise;
|
|
48
48
|
getLoaderForScheme: typeof getLoaderForScheme;
|
|
49
49
|
getPixelData: typeof getPixelData;
|
|
50
|
-
loadImage:
|
|
50
|
+
loadImage: (imageId: string, options?: import("../../types").DICOMLoaderImageOptions) => import("packages/core/dist/esm/types").IImageLoadObject;
|
|
51
|
+
loadImageFromNaturalizedMetadata: typeof loadImageFromNaturalizedMetadata;
|
|
51
52
|
parseImageId: typeof parseImageId;
|
|
52
53
|
unpackBinaryFrame: typeof unpackBinaryFrame;
|
|
53
54
|
register: typeof register;
|
|
54
55
|
};
|
|
55
56
|
export default _default;
|
|
56
|
-
export { metaData, dataSetCacheManager, fileManager, getEncapsulatedImageFrame, getUncompressedImageFrame, loadFileRequest, loadImageFromPromise, getLoaderForScheme, getPixelData, loadImage, parseImageId, unpackBinaryFrame, register, };
|
|
57
|
+
export { metaData, dataSetCacheManager, fileManager, getEncapsulatedImageFrame, getUncompressedImageFrame, loadFileRequest, loadImageFromPromise, getLoaderForScheme, getPixelData, loadImage, loadImageFromNaturalizedMetadata, parseImageId, unpackBinaryFrame, register, };
|
|
@@ -5,7 +5,7 @@ import getEncapsulatedImageFrame from './getEncapsulatedImageFrame';
|
|
|
5
5
|
import getUncompressedImageFrame from './getUncompressedImageFrame';
|
|
6
6
|
import loadFileRequest from './loadFileRequest';
|
|
7
7
|
import getPixelData from './getPixelData';
|
|
8
|
-
import { loadImageFromPromise, getLoaderForScheme, loadImage, } from './loadImage';
|
|
8
|
+
import { loadImageFromPromise, getLoaderForScheme, loadImage, loadImageFromNaturalizedMetadata, } from './loadImage';
|
|
9
9
|
import parseImageId from './parseImageId';
|
|
10
10
|
import unpackBinaryFrame from './unpackBinaryFrame';
|
|
11
11
|
import register from './register';
|
|
@@ -28,8 +28,9 @@ export default {
|
|
|
28
28
|
getLoaderForScheme,
|
|
29
29
|
getPixelData,
|
|
30
30
|
loadImage,
|
|
31
|
+
loadImageFromNaturalizedMetadata,
|
|
31
32
|
parseImageId,
|
|
32
33
|
unpackBinaryFrame,
|
|
33
34
|
register,
|
|
34
35
|
};
|
|
35
|
-
export { metaData, dataSetCacheManager, fileManager, getEncapsulatedImageFrame, getUncompressedImageFrame, loadFileRequest, loadImageFromPromise, getLoaderForScheme, getPixelData, loadImage, parseImageId, unpackBinaryFrame, register, };
|
|
36
|
+
export { metaData, dataSetCacheManager, fileManager, getEncapsulatedImageFrame, getUncompressedImageFrame, loadFileRequest, loadImageFromPromise, getLoaderForScheme, getPixelData, loadImage, loadImageFromNaturalizedMetadata, parseImageId, unpackBinaryFrame, register, };
|
|
@@ -4,6 +4,8 @@ import type { LoadRequestFunction, DICOMLoaderIImage, DICOMLoaderImageOptions }
|
|
|
4
4
|
declare function loadImageFromPromise(dataSetPromise: Promise<DataSet>, imageId: string, frame: number, sharedCacheKey: string, options: DICOMLoaderImageOptions, callbacks?: {
|
|
5
5
|
imageDoneCallback: (image: DICOMLoaderIImage) => void;
|
|
6
6
|
}): Types.IImageLoadObject;
|
|
7
|
+
declare function loadImageFromDataSet(dataSet: any, imageId: string, frame: number, _sharedCacheKey: any, options: any): Types.IImageLoadObject;
|
|
7
8
|
declare function getLoaderForScheme(scheme: string): LoadRequestFunction;
|
|
8
|
-
declare function
|
|
9
|
-
|
|
9
|
+
declare function loadImageFromNaturalizedMetadata(imageId: string, options?: DICOMLoaderImageOptions): Types.IImageLoadObject;
|
|
10
|
+
declare const loadImage: (imageId: string, options?: DICOMLoaderImageOptions) => Types.IImageLoadObject;
|
|
11
|
+
export { loadImageFromPromise, getLoaderForScheme, loadImage, loadImageFromNaturalizedMetadata, loadImageFromDataSet, };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Enums } from '@cornerstonejs/core';
|
|
1
|
+
import { Enums, metaData } from '@cornerstonejs/core';
|
|
2
|
+
import { Enums as MetadataEnums, utilities } from '@cornerstonejs/metadata';
|
|
2
3
|
import createImage from '../createImage';
|
|
3
4
|
import { xhrRequest } from '../internal/index';
|
|
4
5
|
import dataSetCacheManager from './dataSetCacheManager';
|
|
@@ -6,6 +7,8 @@ import getPixelData from './getPixelData';
|
|
|
6
7
|
import loadFileRequest from './loadFileRequest';
|
|
7
8
|
import parseImageId from './parseImageId';
|
|
8
9
|
const { ImageQualityStatus } = Enums;
|
|
10
|
+
const { addDicomPart10Instance } = utilities;
|
|
11
|
+
const NATURALIZED = MetadataEnums.MetadataModules.NATURALIZED;
|
|
9
12
|
function addDecache(imageLoadObject, imageId) {
|
|
10
13
|
imageLoadObject.decache = function () {
|
|
11
14
|
const parsedImageId = parseImageId(imageId);
|
|
@@ -28,7 +31,6 @@ function loadImageFromPromise(dataSetPromise, imageId, frame = 0, sharedCacheKey
|
|
|
28
31
|
imagePromise.then((image) => {
|
|
29
32
|
image = image;
|
|
30
33
|
image.data = dataSet;
|
|
31
|
-
image.sharedCacheKey = sharedCacheKey;
|
|
32
34
|
const end = new Date().getTime();
|
|
33
35
|
image.loadTimeInMS = loadEnd - start;
|
|
34
36
|
image.totalTimeInMS = end - start;
|
|
@@ -52,7 +54,7 @@ function loadImageFromPromise(dataSetPromise, imageId, frame = 0, sharedCacheKey
|
|
|
52
54
|
});
|
|
53
55
|
return imageLoadObject;
|
|
54
56
|
}
|
|
55
|
-
function loadImageFromDataSet(dataSet, imageId, frame = 0,
|
|
57
|
+
function loadImageFromDataSet(dataSet, imageId, frame = 0, _sharedCacheKey, options) {
|
|
56
58
|
const start = new Date().getTime();
|
|
57
59
|
const promise = new Promise((resolve, reject) => {
|
|
58
60
|
const loadEnd = new Date().getTime();
|
|
@@ -92,16 +94,88 @@ function getLoaderForScheme(scheme) {
|
|
|
92
94
|
return loadFileRequest;
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
|
-
|
|
97
|
+
const asByteArray = (data) => data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
98
|
+
function concatPixelData(pixelData) {
|
|
99
|
+
if (!Array.isArray(pixelData)) {
|
|
100
|
+
return asByteArray(pixelData);
|
|
101
|
+
}
|
|
102
|
+
if (pixelData.length === 0) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
if (pixelData.length === 1) {
|
|
106
|
+
return asByteArray(pixelData[0]);
|
|
107
|
+
}
|
|
108
|
+
let totalLength = 0;
|
|
109
|
+
for (const frame of pixelData) {
|
|
110
|
+
totalLength += asByteArray(frame).length;
|
|
111
|
+
}
|
|
112
|
+
const result = new Uint8Array(totalLength);
|
|
113
|
+
let offset = 0;
|
|
114
|
+
for (const frame of pixelData) {
|
|
115
|
+
const view = asByteArray(frame);
|
|
116
|
+
result.set(view, offset);
|
|
117
|
+
offset += view.length;
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
function loadImageFromNaturalizedMetadata(imageId, options = {}) {
|
|
96
122
|
const parsedImageId = parseImageId(imageId);
|
|
97
123
|
options = Object.assign({}, options);
|
|
98
124
|
delete options.loader;
|
|
99
125
|
const schemeLoader = getLoaderForScheme(parsedImageId.scheme);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
126
|
+
const frameIndex = parsedImageId.pixelDataFrame !== undefined
|
|
127
|
+
? parsedImageId.pixelDataFrame
|
|
128
|
+
: 0;
|
|
129
|
+
const promise = (async () => {
|
|
130
|
+
const start = Date.now();
|
|
131
|
+
console.log('[dicomImageLoader/wadouri] loadImageFromNaturalizedMetadata: start', {
|
|
132
|
+
imageId,
|
|
133
|
+
scheme: parsedImageId.scheme,
|
|
134
|
+
url: parsedImageId.url,
|
|
135
|
+
frameIndex,
|
|
136
|
+
});
|
|
137
|
+
let natural = metaData.get(NATURALIZED, imageId);
|
|
138
|
+
if (!natural) {
|
|
139
|
+
console.log('[dicomImageLoader/wadouri] loadImageFromNaturalizedMetadata: no NATURALIZED metadata, attempting to fetch and populate', { imageId });
|
|
140
|
+
if (!schemeLoader) {
|
|
141
|
+
throw new Error(`loadImageFromNaturalizedMetadata: no NATURALIZED cache and unknown scheme ${parsedImageId.scheme}`);
|
|
142
|
+
}
|
|
143
|
+
const result = (await schemeLoader(parsedImageId.url, imageId));
|
|
144
|
+
const arrayBuffer = result instanceof ArrayBuffer ? result : result.arrayBuffer;
|
|
145
|
+
const baseImageId = `${parsedImageId.scheme}:${parsedImageId.url}`;
|
|
146
|
+
await addDicomPart10Instance(baseImageId, arrayBuffer);
|
|
147
|
+
natural = metaData.get(NATURALIZED, imageId);
|
|
148
|
+
}
|
|
149
|
+
const loadEnd = Date.now();
|
|
150
|
+
const frameData = metaData.getTyped(MetadataEnums.MetadataModules.COMPRESSED_FRAME_DATA, imageId, { frameIndex });
|
|
151
|
+
if (!frameData) {
|
|
152
|
+
console.warn('[dicomImageLoader/wadouri] loadImageFromNaturalizedMetadata: no COMPRESSED_FRAME_DATA for imageId', { imageId, frameIndex });
|
|
153
|
+
throw new Error(`loadImageFromNaturalizedMetadata: no pixel data in NATURALIZED for imageId ${imageId}`);
|
|
154
|
+
}
|
|
155
|
+
const { pixelData, transferSyntaxUid } = frameData;
|
|
156
|
+
const concatenatedPixelData = concatPixelData(pixelData);
|
|
157
|
+
const image = await createImage(imageId, concatenatedPixelData, transferSyntaxUid, options);
|
|
158
|
+
const end = Date.now();
|
|
159
|
+
const out = image;
|
|
160
|
+
out.imageQualityStatus = ImageQualityStatus.FULL_RESOLUTION;
|
|
161
|
+
out.data = natural;
|
|
162
|
+
out.loadTimeInMS = loadEnd - start;
|
|
163
|
+
out.totalTimeInMS = end - start;
|
|
164
|
+
return out;
|
|
165
|
+
})();
|
|
166
|
+
return { promise };
|
|
167
|
+
}
|
|
168
|
+
const loadImage = (imageId, options = {}) => {
|
|
169
|
+
const parsedImageId = parseImageId(imageId);
|
|
170
|
+
const schemeLoader = getLoaderForScheme(parsedImageId.scheme);
|
|
171
|
+
if (!schemeLoader) {
|
|
172
|
+
throw new Error(`wadouri loadImage: no loader for scheme '${parsedImageId.scheme}'`);
|
|
103
173
|
}
|
|
174
|
+
const frameIndex = parsedImageId.pixelDataFrame !== undefined
|
|
175
|
+
? parsedImageId.pixelDataFrame
|
|
176
|
+
: 0;
|
|
177
|
+
const sharedCacheKey = parsedImageId.url;
|
|
104
178
|
const dataSetPromise = dataSetCacheManager.load(parsedImageId.url, schemeLoader, imageId);
|
|
105
|
-
return loadImageFromPromise(dataSetPromise, imageId,
|
|
106
|
-
}
|
|
107
|
-
export { loadImageFromPromise, getLoaderForScheme, loadImage };
|
|
179
|
+
return loadImageFromPromise(dataSetPromise, imageId, frameIndex, sharedCacheKey, options);
|
|
180
|
+
};
|
|
181
|
+
export { loadImageFromPromise, getLoaderForScheme, loadImage, loadImageFromNaturalizedMetadata, loadImageFromDataSet, };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as dicomParser from 'dicom-parser';
|
|
2
|
+
declare function inflater(byteArray: Uint8Array, position: number): Uint8Array;
|
|
3
|
+
export declare const parseDicomOptions: {
|
|
4
|
+
inflater: typeof inflater;
|
|
5
|
+
};
|
|
6
|
+
export declare function parseDicom(byteArray: Uint8Array, options?: dicomParser.ParseDicomOptions): dicomParser.DataSet;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as dicomParser from 'dicom-parser';
|
|
2
|
+
import pako from 'pako';
|
|
3
|
+
function inflater(byteArray, position) {
|
|
4
|
+
const deflated = byteArray.slice(position);
|
|
5
|
+
const inflated = pako.inflateRaw(deflated);
|
|
6
|
+
const fullByteArray = new Uint8Array(inflated.length + position);
|
|
7
|
+
fullByteArray.set(byteArray.slice(0, position), 0);
|
|
8
|
+
fullByteArray.set(inflated, position);
|
|
9
|
+
return fullByteArray;
|
|
10
|
+
}
|
|
11
|
+
export const parseDicomOptions = { inflater };
|
|
12
|
+
export function parseDicom(byteArray, options) {
|
|
13
|
+
return dicomParser.parseDicom(byteArray, {
|
|
14
|
+
...parseDicomOptions,
|
|
15
|
+
...options,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { metaData, registerImageLoader } from '@cornerstonejs/core';
|
|
2
|
-
import {
|
|
2
|
+
import { registerDefaultProviders } from '@cornerstonejs/metadata';
|
|
3
|
+
import { loadImage, loadImageFromNaturalizedMetadata } from './loadImage';
|
|
3
4
|
import { metaDataProvider } from './metaData/index';
|
|
4
|
-
export default function () {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export default function (options) {
|
|
6
|
+
if (options?.useLegacyMetadataProvider === true) {
|
|
7
|
+
console.warn('wadouri metaDataProvider is deprecated. Use registerMetadataProvider module from @cornerstonejs/metadata instead.');
|
|
8
|
+
registerImageLoader('dicomweb', loadImage);
|
|
9
|
+
registerImageLoader('wadouri', loadImage);
|
|
10
|
+
registerImageLoader('dicomfile', loadImage);
|
|
11
|
+
metaData.addProvider(metaDataProvider);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
registerImageLoader('dicomweb', loadImageFromNaturalizedMetadata);
|
|
15
|
+
registerImageLoader('wadouri', loadImageFromNaturalizedMetadata);
|
|
16
|
+
registerImageLoader('dicomfile', loadImageFromNaturalizedMetadata);
|
|
17
|
+
registerDefaultProviders();
|
|
9
18
|
}
|
|
19
|
+
export { loadImageFromNaturalizedMetadata as loadImage } from './loadImage';
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -53,7 +53,8 @@ declare const cornerstoneDICOMImageLoader: {
|
|
|
53
53
|
loadImageFromPromise: typeof import("./imageLoader/wadouri/loadImage").loadImageFromPromise;
|
|
54
54
|
getLoaderForScheme: typeof import("./imageLoader/wadouri/loadImage").getLoaderForScheme;
|
|
55
55
|
getPixelData: typeof import("./imageLoader/wadouri/getPixelData").default;
|
|
56
|
-
loadImage:
|
|
56
|
+
loadImage: (imageId: string, options?: Types.DICOMLoaderImageOptions) => import("packages/core/dist/esm/types").IImageLoadObject;
|
|
57
|
+
loadImageFromNaturalizedMetadata: typeof import("./imageLoader/wadouri/loadImage").loadImageFromNaturalizedMetadata;
|
|
57
58
|
parseImageId: typeof import("./imageLoader/wadouri/parseImageId").default;
|
|
58
59
|
unpackBinaryFrame: typeof import("./imageLoader/wadouri/unpackBinaryFrame").default;
|
|
59
60
|
register: typeof import("./imageLoader/wadouri/register").default;
|
package/dist/esm/init.js
CHANGED
|
@@ -7,7 +7,7 @@ const workerFn = () => {
|
|
|
7
7
|
};
|
|
8
8
|
function init(options = {}) {
|
|
9
9
|
setOptions(options);
|
|
10
|
-
registerLoaders();
|
|
10
|
+
registerLoaders(options);
|
|
11
11
|
const workerManager = getWebWorkerManager();
|
|
12
12
|
const maxWorkers = options?.maxWebWorkers || getReasonableWorkerCount();
|
|
13
13
|
workerManager.registerWorker('dicomImageLoader', workerFn, {
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "5.0.0
|
|
1
|
+
export declare const version = "5.0.0";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.0.0
|
|
1
|
+
export const version = '5.0.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/dicom-image-loader",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Cornerstone Image Loader for DICOM WADO-URI and WADO-RS and Local file",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"DICOM",
|
|
@@ -65,15 +65,16 @@
|
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
|
-
"build:loader": "
|
|
68
|
+
"build:loader": "pnpm run build:all && pnpm run copy-dts",
|
|
69
|
+
"build": "pnpm run build:esm",
|
|
69
70
|
"build:esm": "tsc --project ./tsconfig.json",
|
|
70
71
|
"build:esm:watch": "tsc --project ./tsconfig.json --watch",
|
|
71
72
|
"build:umd:dynamic": "cross-env NODE_ENV=production webpack --config .webpack/webpack-dynamic-import.js",
|
|
72
73
|
"build:umd:bundle": "cross-env NODE_ENV=production webpack --config .webpack/webpack-bundle.js",
|
|
73
|
-
"build:all": "
|
|
74
|
+
"build:all": "pnpm run build:esm",
|
|
74
75
|
"copy-dts": "echo 'not implemented yet'",
|
|
75
76
|
"clean": "shx rm -rf dist",
|
|
76
|
-
"clean:deep": "
|
|
77
|
+
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
|
77
78
|
"api-check": "api-extractor --debug run ",
|
|
78
79
|
"cm": "npx git-cz",
|
|
79
80
|
"clean:dist": "shx rm -rf dist",
|
|
@@ -98,7 +99,7 @@
|
|
|
98
99
|
"webpack:dynamic-import:watch": "webpack --progress --watch --config .webpack/webpack-dynamic-import",
|
|
99
100
|
"webpack:dynamic-import:debug": "webpack --progress --watch --config .webpack/webpack-dynamic-import-debug",
|
|
100
101
|
"webpack:watch": "webpack --progress --watch --config .webpack",
|
|
101
|
-
"prepublishOnly": "
|
|
102
|
+
"prepublishOnly": "pnpm run build:loader"
|
|
102
103
|
},
|
|
103
104
|
"dependencies": {
|
|
104
105
|
"@cornerstonejs/codec-charls": "1.2.3",
|
|
@@ -111,8 +112,13 @@
|
|
|
111
112
|
"pako": "2.1.0",
|
|
112
113
|
"uuid": "9.0.1"
|
|
113
114
|
},
|
|
115
|
+
"devDependencies": {
|
|
116
|
+
"@cornerstonejs/core": "5.0.0",
|
|
117
|
+
"@cornerstonejs/metadata": "5.0.0"
|
|
118
|
+
},
|
|
114
119
|
"peerDependencies": {
|
|
115
|
-
"@cornerstonejs/core": "5.0.0
|
|
120
|
+
"@cornerstonejs/core": "5.0.0",
|
|
121
|
+
"@cornerstonejs/metadata": "5.0.0",
|
|
116
122
|
"dicom-parser": "1.8.21"
|
|
117
123
|
},
|
|
118
124
|
"config": {
|
|
@@ -120,5 +126,5 @@
|
|
|
120
126
|
"path": "./node_modules/cz-conventional-changelog"
|
|
121
127
|
}
|
|
122
128
|
},
|
|
123
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "d6f3fba43abcbaaf7468ff534588f6a88720b875"
|
|
124
130
|
}
|