kkfileView/server/target/classes/static/dcm/DICOMZero.js

160 lines
5.5 KiB
JavaScript
Raw Normal View History

2024-05-15 12:24:32 +08:00
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
});
}
}