新增 dcm 等医疗数位影像预览
This commit is contained in:
159
server/src/main/resources/static/dcm/DICOMZero.js
Normal file
159
server/src/main/resources/static/dcm/DICOMZero.js
Normal file
@ -0,0 +1,159 @@
|
||||
class DICOMZero {
|
||||
constructor(options={}) {
|
||||
this.status = options.status || function() {};
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.mappingLog = [];
|
||||
this.dataTransfer = undefined;
|
||||
this.datasets = [];
|
||||
this.readers = [];
|
||||
this.arrayBuffers = [];
|
||||
this.files = [];
|
||||
this.fileIndex = 0;
|
||||
this.context = {patients: []};
|
||||
}
|
||||
|
||||
static datasetFromArrayBuffer(arrayBuffer) {
|
||||
let dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
|
||||
let dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
||||
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
|
||||
return(dataset);
|
||||
}
|
||||
|
||||
// return a function to use as the 'onload' callback for the file reader.
|
||||
// The function takes a progress event argument and it knows (from this class instance)
|
||||
// when all files have been read so it can invoke the doneCallback when all
|
||||
// have been read.
|
||||
getReadDICOMFunction(doneCallback, statusCallback) {
|
||||
statusCallback = statusCallback || console.log;
|
||||
return progressEvent => {
|
||||
let reader = progressEvent.target;
|
||||
let arrayBuffer = reader.result;
|
||||
this.arrayBuffers.push(arrayBuffer);
|
||||
|
||||
let dicomData;
|
||||
try {
|
||||
dicomData = dcmjs.data.DicomMessage.readFile(arrayBuffer);
|
||||
let dataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomData.dict);
|
||||
dataset._meta = dcmjs.data.DicomMetaDictionary.namifyDataset(dicomData.meta);
|
||||
this.datasets.push(dataset);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
statusCallback("skipping non-dicom file");
|
||||
}
|
||||
|
||||
let readerIndex = this.readers.indexOf(reader);
|
||||
if (readerIndex < 0) {
|
||||
reject("Logic error: Unexpected reader!");
|
||||
} else {
|
||||
this.readers.splice(readerIndex, 1); // remove the reader
|
||||
}
|
||||
|
||||
if (this.fileIndex === this.dataTransfer.files.length) {
|
||||
statusCallback(`Normalizing...`);
|
||||
try {
|
||||
this.multiframe = dcmjs.normalizers.Normalizer.normalizeToDataset(this.datasets);
|
||||
} catch (e) {
|
||||
console.error('Could not convert to multiframe');
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
if (this.multiframe.SOPClassUID == dcmjs.data.DicomMetaDictionary.sopClassUIDsByName['Segmentation']){
|
||||
statusCallback(`Creating segmentation...`);
|
||||
try {
|
||||
this.seg = new dcmjs.derivations.Segmentation([this.multiframe]);
|
||||
statusCallback(`Created ${this.multiframe.NumberOfFrames} frame multiframe object and segmentation.`);
|
||||
} catch (e) {
|
||||
console.error('Could not create segmentation');
|
||||
console.error(e);
|
||||
}
|
||||
} else if (this.multiframe.SOPClassUID == dcmjs.data.DicomMetaDictionary.sopClassUIDsByName['ParametricMapStorage']){
|
||||
statusCallback(`Creating parametric map...`);
|
||||
try {
|
||||
this.pm = new dcmjs.derivations.ParametricMap([this.multiframe]);
|
||||
statusCallback(`Created ${this.multiframe.NumberOfFrames} frame multiframe object and parametric map.`);
|
||||
} catch (e) {
|
||||
console.error('Could not create parametric map');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
doneCallback();
|
||||
} else {
|
||||
statusCallback(`Reading... (${this.fileIndex+1}).`);
|
||||
this.readOneFile(doneCallback, statusCallback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Used for file selection button or drop of file list
|
||||
readOneFile(doneCallback, statusCallback) {
|
||||
let file = this.dataTransfer.files[this.fileIndex];
|
||||
this.fileIndex++;
|
||||
|
||||
let reader = new FileReader();
|
||||
reader.onload = this.getReadDICOMFunction(doneCallback, statusCallback);
|
||||
reader.readAsArrayBuffer(file);
|
||||
|
||||
this.files.push(file);
|
||||
this.readers.push(reader);
|
||||
}
|
||||
|
||||
handleDataTransferFileAsDataset(file, options={}) {
|
||||
options.doneCallback = options.doneCallback || function(){};
|
||||
|
||||
let reader = new FileReader();
|
||||
reader.onload = (progressEvent) => {
|
||||
let dataset = DICOMZero.datasetFromArrayBuffer(reader.result);
|
||||
options.doneCallback(dataset);
|
||||
}
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
extractDatasetFromZipArrayBuffer(arrayBuffer) {
|
||||
this.status(`Extracting ${this.datasets.length} of ${this.expectedDICOMFileCount}...`);
|
||||
this.datasets.push(DICOMZero.datasetFromArrayBuffer(arrayBuffer));
|
||||
if (this.datasets.length == this.expectedDICOMFileCount) {
|
||||
this.status(`Finished extracting`);
|
||||
this.zipFinishCallback();
|
||||
}
|
||||
};
|
||||
|
||||
handleZip(zip) {
|
||||
this.zip = zip;
|
||||
this.expectedDICOMFileCount = 0;
|
||||
Object.keys(zip.files).forEach(fileKey => {
|
||||
this.status(`Considering ${fileKey}...`);
|
||||
if (fileKey.endsWith('.dcm')) {
|
||||
this.expectedDICOMFileCount += 1;
|
||||
zip.files[fileKey].async('arraybuffer').then(this.extractDatasetFromZipArrayBuffer.bind(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extractFromZipArrayBuffer(arrayBuffer, finishCallback=function(){}) {
|
||||
this.zipFinishCallback = finishCallback;
|
||||
this.status("Extracting from zip...");
|
||||
JSZip.loadAsync(arrayBuffer)
|
||||
.then(this.handleZip.bind(this));
|
||||
}
|
||||
|
||||
organizeDatasets() {
|
||||
this.datasets.forEach(dataset => {
|
||||
let patientName = dataset.PatientName;
|
||||
let studyTag = dataset.StudyDate + ": " + dataset.StudyDescription;
|
||||
let seriesTag = dataset.SeriesNumber + ": " + dataset.SeriesDescription;
|
||||
let patientNames = this.context.patients.map(patient => patient.name);
|
||||
let patientIndex = patientNames.indexOf(dataset.PatientName);
|
||||
if (patientIndex == -1) {
|
||||
this.context.patients.push({
|
||||
name: dataset.PatientName,
|
||||
id: this.context.patients.length,
|
||||
studies: {}
|
||||
});
|
||||
}
|
||||
let studyNames; // TODO - finish organizing
|
||||
});
|
||||
}
|
||||
}
|
||||
8547
server/src/main/resources/static/dcm/cornerstone.js
Normal file
8547
server/src/main/resources/static/dcm/cornerstone.js
Normal file
File diff suppressed because one or more lines are too long
2084
server/src/main/resources/static/dcm/cornerstoneMath.js
Normal file
2084
server/src/main/resources/static/dcm/cornerstoneMath.js
Normal file
File diff suppressed because it is too large
Load Diff
36430
server/src/main/resources/static/dcm/cornerstoneTools.js
Normal file
36430
server/src/main/resources/static/dcm/cornerstoneTools.js
Normal file
File diff suppressed because it is too large
Load Diff
2
server/src/main/resources/static/dcm/cornerstoneWADOImageLoader.bundle.min.js
vendored
Normal file
2
server/src/main/resources/static/dcm/cornerstoneWADOImageLoader.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3955
server/src/main/resources/static/dcm/dicomParser.js
Normal file
3955
server/src/main/resources/static/dcm/dicomParser.js
Normal file
File diff suppressed because it is too large
Load Diff
7
server/src/main/resources/static/dcm/hammer.min.js
vendored
Normal file
7
server/src/main/resources/static/dcm/hammer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7119
server/src/main/resources/static/dcm/index.umd.js
Normal file
7119
server/src/main/resources/static/dcm/index.umd.js
Normal file
File diff suppressed because it is too large
Load Diff
43
server/src/main/resources/static/dcm/initCornerstone.js
Normal file
43
server/src/main/resources/static/dcm/initCornerstone.js
Normal file
@ -0,0 +1,43 @@
|
||||
cornerstoneTools.external.cornerstone = cornerstone;
|
||||
cornerstoneTools.external.Hammer = Hammer;
|
||||
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
|
||||
|
||||
cornerstoneTools.init();
|
||||
|
||||
cornerstoneTools.addTool(cornerstoneTools.BidirectionalTool);
|
||||
cornerstoneTools.addTool(cornerstoneTools.ArrowAnnotateTool);
|
||||
cornerstoneTools.addTool(cornerstoneTools.EllipticalRoiTool);
|
||||
|
||||
function getBlobUrl(url) {
|
||||
const baseUrl = window.URL || window.webkitURL;
|
||||
const blob = new Blob([`importScripts('${url}')`], {
|
||||
type: "application/javascript"
|
||||
});
|
||||
|
||||
return baseUrl.createObjectURL(blob);
|
||||
}
|
||||
|
||||
const config = {
|
||||
maxWebWorkers: navigator.hardwareConcurrency || 1,
|
||||
startWebWorkersOnDemand: true,
|
||||
webWorkerPath: getBlobUrl(
|
||||
"https://unpkg.com/cornerstone-wado-image-loader/dist/cornerstoneWADOImageLoaderWebWorker.min.js"
|
||||
),
|
||||
webWorkerTaskPaths: [],
|
||||
taskConfiguration: {
|
||||
decodeTask: {
|
||||
loadCodecsOnStartup: true,
|
||||
initializeCodecsOnStartup: false,
|
||||
codecsPath: getBlobUrl(
|
||||
"https://unpkg.com/cornerstone-wado-image-loader/dist/cornerstoneWADOImageLoaderCodecs.min.js"
|
||||
),
|
||||
usePDFJS: false,
|
||||
strict: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||
|
||||
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
||||
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
|
||||
25147
server/src/main/resources/static/dcm/react-dom.development.js
Normal file
25147
server/src/main/resources/static/dcm/react-dom.development.js
Normal file
File diff suppressed because it is too large
Load Diff
3318
server/src/main/resources/static/dcm/react.development.js
Normal file
3318
server/src/main/resources/static/dcm/react.development.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user