ohif-viewer/extensions/default/src/init.ts

145 lines
4.5 KiB
TypeScript

import { DicomMetadataStore, classes } from '@ohif/core';
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv';
import getPTImageIdInstanceMetadata from './getPTImageIdInstanceMetadata';
import { registerHangingProtocolAttributes } from './hangingprotocols';
import { HotkeysManager } from '@ohif/core'
const metadataProvider = classes.MetadataProvider;
/**
*
* @param {Object} servicesManager
* @param {Object} configuration
*/
export default function init({ servicesManager, commandsManager, hotkeysManager }: withAppTypes): void {
const { toolbarService, cineService, viewportGridService } = servicesManager.services;
toolbarService.registerEventForToolbarUpdate(cineService, [
cineService.EVENTS.CINE_STATE_CHANGED,
]);
toolbarService.registerEventForToolbarUpdate(hotkeysManager, [
HotkeysManager.EVENTS.HOTKEY_PRESSED,
]);
// Add
DicomMetadataStore.subscribe(DicomMetadataStore.EVENTS.INSTANCES_ADDED, handleScalingModules);
// If the metadata for PET has changed by the user (e.g. manually changing the PatientWeight)
// we need to recalculate the SUV Scaling Factors
DicomMetadataStore.subscribe(DicomMetadataStore.EVENTS.SERIES_UPDATED, handleScalingModules);
// Adds extra custom attributes for use by hanging protocols
registerHangingProtocolAttributes({ servicesManager });
// Function to process and subscribe to events for a given set of commands and listeners
const subscribeToEvents = listeners => {
Object.entries(listeners).forEach(([event, commands]) => {
const supportedEvents = [
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
viewportGridService.EVENTS.VIEWPORTS_READY,
];
if (supportedEvents.includes(event)) {
viewportGridService.subscribe(event, eventData => {
const viewportId = eventData?.viewportId ?? viewportGridService.getActiveViewportId();
commandsManager.run(commands, { viewportId });
});
}
});
};
toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, state => {
const { buttons } = state;
for (const [id, button] of Object.entries(buttons)) {
const { buttonSection, items, listeners } = button.props || {};
// Handle group items' listeners
if (buttonSection && items) {
items.forEach(item => {
if (item.listeners) {
subscribeToEvents(item.listeners);
}
});
}
// Handle button listeners
if (listeners) {
subscribeToEvents(listeners);
}
}
});
}
const handleScalingModules = ({ SeriesInstanceUID, StudyInstanceUID }) => {
const { instances } = DicomMetadataStore.getSeries(StudyInstanceUID, SeriesInstanceUID);
if (!instances?.length) {
return;
}
const modality = instances[0].Modality;
const allowedModality = ['PT', 'RTDOSE'];
if (!allowedModality.includes(modality)) {
return;
}
const imageIds = instances.map(instance => instance.imageId);
const instanceMetadataArray = [];
if (modality === 'RTDOSE') {
const DoseGridScaling = instances[0].DoseGridScaling;
const DoseSummation = instances[0].DoseSummation;
const DoseType = instances[0].DoseType;
const DoseUnit = instances[0].DoseUnit;
const NumberOfFrames = instances[0].NumberOfFrames;
const imageId = imageIds[0];
// add scaling module to the metadata
// since RTDOSE is always a multiframe we should add the scaling module to each frame
for (let i = 0; i < NumberOfFrames; i++) {
const frameIndex = i + 1;
// Todo: we should support other things like wadouri, local etc
const newImageId = `${imageId.replace(/\/frames\/\d+$/, '')}/frames/${frameIndex}`;
metadataProvider.addCustomMetadata(newImageId, 'scalingModule', {
DoseGridScaling,
DoseSummation,
DoseType,
DoseUnit,
});
}
return;
}
// try except block to prevent errors when the metadata is not correct
try {
imageIds.forEach(imageId => {
const instanceMetadata = getPTImageIdInstanceMetadata(imageId);
if (instanceMetadata) {
instanceMetadataArray.push(instanceMetadata);
}
});
if (!instanceMetadataArray.length) {
return;
}
const suvScalingFactors = calculateSUVScalingFactors(instanceMetadataArray);
instanceMetadataArray.forEach((instanceMetadata, index) => {
metadataProvider.addCustomMetadata(
imageIds[index],
'scalingModule',
suvScalingFactors[index]
);
});
} catch (error) {
console.log(error);
}
};