* feat: Add state sync and use it to remember viewport grid info fix: Version updates Fixes for toggling MPR mode Fix the display when the interleaved load module fails Fix the memory of the state to restore correctly PR fixes for the state sync service PR fixes PR fixes PR fixes Added a hack warning to remove volumeDeactivate Fixes for TMTV colormap setting Fix the casing Missed renames fix: tests not running due to variance in ordering Reverting some fixes to change case PR changes - mostly comments and minor improvements fix: All display sets were being updated on drag and drop PR fixes - mostly renames PR fixes Test support for OHIF, for HP branch test: Add at least a minimal set of automated tests for hanging protocols Docs PR fixes Merge fixes DOCS updates Add an example of the mn hanging protocol PR fixes PR fixes PR fixes * Fix the drag and drop PR fixes * PR changes - update default keys for next/previous stage * fix: Was storing the custom viewport grid too aggressively Caused by a PR change misspelling a variable
213 lines
7.8 KiB
JavaScript
213 lines
7.8 KiB
JavaScript
import { isImage } from '@ohif/core/src/utils/isImage';
|
|
import sopClassDictionary from '@ohif/core/src/utils/sopClassDictionary';
|
|
import ImageSet from '@ohif/core/src/classes/ImageSet';
|
|
import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable';
|
|
import { id } from './id';
|
|
|
|
const sopClassHandlerName = 'stack';
|
|
|
|
const isMultiFrame = instance => {
|
|
return instance.NumberOfFrames > 1;
|
|
};
|
|
|
|
const makeDisplaySet = instances => {
|
|
const instance = instances[0];
|
|
const imageSet = new ImageSet(instances);
|
|
|
|
const displayReconstructableInfo = isDisplaySetReconstructable(instances);
|
|
|
|
// set appropriate attributes to image set...
|
|
imageSet.setAttributes({
|
|
displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID
|
|
SeriesDate: instance.SeriesDate,
|
|
SeriesTime: instance.SeriesTime,
|
|
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
StudyInstanceUID: instance.StudyInstanceUID,
|
|
SeriesNumber: instance.SeriesNumber || 0,
|
|
FrameRate: instance.FrameTime,
|
|
SOPClassUID: instance.SOPClassUID,
|
|
SeriesDescription: instance.SeriesDescription || '',
|
|
Modality: instance.Modality,
|
|
isMultiFrame: isMultiFrame(instance),
|
|
countIcon: displayReconstructableInfo.value ? 'icon-mpr' : undefined,
|
|
numImageFrames: instances.length,
|
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
isReconstructable: displayReconstructableInfo.value,
|
|
});
|
|
|
|
// Sort the images in this series if needed
|
|
const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder');
|
|
if (shallSort) {
|
|
imageSet.sortBy((a, b) => {
|
|
// Sort by InstanceNumber (0020,0013)
|
|
return (
|
|
(parseInt(a.InstanceNumber) || 0) - (parseInt(b.InstanceNumber) || 0)
|
|
);
|
|
});
|
|
}
|
|
|
|
// Include the first image instance number (after sorted)
|
|
/*imageSet.setAttribute(
|
|
'instanceNumber',
|
|
imageSet.getImage(0).InstanceNumber
|
|
);*/
|
|
|
|
/*const isReconstructable = isDisplaySetReconstructable(series, instances);
|
|
|
|
imageSet.isReconstructable = isReconstructable.value;
|
|
|
|
if (isReconstructable.missingFrames) {
|
|
// TODO -> This is currently unused, but may be used for reconstructing
|
|
// Volumes with gaps later on.
|
|
imageSet.missingFrames = isReconstructable.missingFrames;
|
|
}*/
|
|
|
|
return imageSet;
|
|
};
|
|
|
|
const isSingleImageModality = modality => {
|
|
return modality === 'CR' || modality === 'MG' || modality === 'DX';
|
|
};
|
|
|
|
function getSopClassUids(instances) {
|
|
const uniqueSopClassUidsInSeries = new Set();
|
|
instances.forEach(instance => {
|
|
uniqueSopClassUidsInSeries.add(instance.SOPClassUID);
|
|
});
|
|
const sopClassUids = Array.from(uniqueSopClassUidsInSeries);
|
|
|
|
return sopClassUids;
|
|
}
|
|
|
|
/**
|
|
* Basic SOPClassHandler:
|
|
* - For all Image types that are stackable, create
|
|
* a displaySet with a stack of images
|
|
*
|
|
* @param {Array} sopClassHandlerModules List of SOP Class Modules
|
|
* @param {SeriesMetadata} series The series metadata object from which the display sets will be created
|
|
* @returns {Array} The list of display sets created for the given series object
|
|
*/
|
|
function getDisplaySetsFromSeries(instances) {
|
|
// If the series has no instances, stop here
|
|
if (!instances || !instances.length) {
|
|
throw new Error('No instances were provided');
|
|
}
|
|
|
|
const displaySets = [];
|
|
const sopClassUids = getSopClassUids(instances);
|
|
|
|
// Search through the instances (InstanceMetadata object) of this series
|
|
// Split Multi-frame instances and Single-image modalities
|
|
// into their own specific display sets. Place the rest of each
|
|
// series into another display set.
|
|
const stackableInstances = [];
|
|
instances.forEach(instance => {
|
|
// All imaging modalities must have a valid value for sopClassUid (x00080016) or rows (x00280010)
|
|
if (!isImage(instance.SOPClassUID) && !instance.Rows) {
|
|
return;
|
|
}
|
|
|
|
let displaySet;
|
|
|
|
if (isMultiFrame(instance)) {
|
|
displaySet = makeDisplaySet([instance]);
|
|
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
isClip: true,
|
|
numImageFrames: instance.NumberOfFrames,
|
|
instanceNumber: instance.InstanceNumber,
|
|
acquisitionDatetime: instance.AcquisitionDateTime,
|
|
});
|
|
displaySets.push(displaySet);
|
|
} else if (isSingleImageModality(instance.Modality)) {
|
|
displaySet = makeDisplaySet([instance]);
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
instanceNumber: instance.InstanceNumber,
|
|
acquisitionDatetime: instance.AcquisitionDateTime,
|
|
});
|
|
displaySets.push(displaySet);
|
|
} else {
|
|
stackableInstances.push(instance);
|
|
}
|
|
});
|
|
|
|
if (stackableInstances.length) {
|
|
const displaySet = makeDisplaySet(stackableInstances);
|
|
displaySet.setAttribute('studyInstanceUid', instances[0].StudyInstanceUID);
|
|
displaySet.setAttributes({
|
|
sopClassUids,
|
|
});
|
|
displaySets.push(displaySet);
|
|
}
|
|
|
|
return displaySets;
|
|
}
|
|
|
|
const sopClassUids = [
|
|
sopClassDictionary.ComputedRadiographyImageStorage,
|
|
sopClassDictionary.DigitalXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalXRayImageStorageForProcessing,
|
|
sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing,
|
|
sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation,
|
|
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing,
|
|
sopClassDictionary.CTImageStorage,
|
|
sopClassDictionary.EnhancedCTImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage,
|
|
sopClassDictionary.UltrasoundMultiframeImageStorage,
|
|
sopClassDictionary.MRImageStorage,
|
|
sopClassDictionary.EnhancedMRImageStorage,
|
|
sopClassDictionary.EnhancedMRColorImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedMRImageStorage,
|
|
sopClassDictionary.UltrasoundImageStorage,
|
|
sopClassDictionary.UltrasoundImageStorageRET,
|
|
sopClassDictionary.SecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage,
|
|
sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage,
|
|
sopClassDictionary.XRayAngiographicImageStorage,
|
|
sopClassDictionary.EnhancedXAImageStorage,
|
|
sopClassDictionary.XRayRadiofluoroscopicImageStorage,
|
|
sopClassDictionary.EnhancedXRFImageStorage,
|
|
sopClassDictionary.XRay3DAngiographicImageStorage,
|
|
sopClassDictionary.XRay3DCraniofacialImageStorage,
|
|
sopClassDictionary.BreastTomosynthesisImageStorage,
|
|
sopClassDictionary.BreastProjectionXRayImageStorageForPresentation,
|
|
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing,
|
|
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation,
|
|
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing,
|
|
sopClassDictionary.NuclearMedicineImageStorage,
|
|
sopClassDictionary.VLEndoscopicImageStorage,
|
|
sopClassDictionary.VideoEndoscopicImageStorage,
|
|
sopClassDictionary.VLMicroscopicImageStorage,
|
|
sopClassDictionary.VideoMicroscopicImageStorage,
|
|
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage,
|
|
sopClassDictionary.VLPhotographicImageStorage,
|
|
sopClassDictionary.VideoPhotographicImageStorage,
|
|
sopClassDictionary.OphthalmicPhotography8BitImageStorage,
|
|
sopClassDictionary.OphthalmicPhotography16BitImageStorage,
|
|
sopClassDictionary.OphthalmicTomographyImageStorage,
|
|
sopClassDictionary.VLWholeSlideMicroscopyImageStorage,
|
|
sopClassDictionary.PositronEmissionTomographyImageStorage,
|
|
sopClassDictionary.EnhancedPETImageStorage,
|
|
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage,
|
|
sopClassDictionary.RTImageStorage,
|
|
sopClassDictionary.EnhancedUSVolumeStorage,
|
|
];
|
|
|
|
function getSopClassHandlerModule() {
|
|
return [
|
|
{
|
|
name: sopClassHandlerName,
|
|
sopClassUids,
|
|
getDisplaySetsFromSeries,
|
|
},
|
|
];
|
|
}
|
|
|
|
export default getSopClassHandlerModule;
|