improve export schema
This commit is contained in:
+114
-121
@@ -1073,134 +1073,127 @@ function App() {
|
||||
}
|
||||
useEffect(() => {
|
||||
// Export the current viewer state as JSON
|
||||
window.exportViewerState = () => {
|
||||
const numActive = viewportGrid.rows * viewportGrid.cols;
|
||||
const activeViewportModes = viewportModes.slice(0, numActive);
|
||||
const activeSelectedStackIdx = selectedStackIdx.slice(0, numActive);
|
||||
const activeAvailableStacks = availableStacks;
|
||||
const activeViewportImageIds = viewportImageIds.slice(0, numActive);
|
||||
window.exportViewerState = () => {
|
||||
const numActive = viewportGrid.rows * viewportGrid.cols;
|
||||
const modes = viewportModes.slice(0, numActive);
|
||||
const stackIdx = selectedStackIdx.slice(0, numActive);
|
||||
const stacks = availableStacks.map(s => ({
|
||||
i: s.imageIds, // imageIds
|
||||
u: s.studyInstanceUID // studyInstanceUID
|
||||
}));
|
||||
|
||||
// Collect viewport properties, stack positions, and camera for active viewports
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
const viewportProperties: any[] = [];
|
||||
const stackPositions: number[] = [];
|
||||
const cameraProperties: any[] = [];
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
let props = null;
|
||||
let stackPos = null;
|
||||
let camera = null;
|
||||
if (renderingEngine) {
|
||||
const viewportId = `CT_${i}`;
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
if (viewport) {
|
||||
if (typeof viewport.getProperties === "function") {
|
||||
props = viewport.getProperties();
|
||||
}
|
||||
if (typeof viewport.getCurrentImageIdIndex === "function") {
|
||||
stackPos = viewport.getCurrentImageIdIndex();
|
||||
}
|
||||
if (typeof viewport.getCamera === "function") {
|
||||
camera = viewport.getCamera();
|
||||
}
|
||||
// Only keep minimal properties
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
const props: any[] = [];
|
||||
const stackPos: number[] = [];
|
||||
const cam: any[] = [];
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
let p = null, s = null, c = null;
|
||||
if (renderingEngine) {
|
||||
const viewportId = `CT_${i}`;
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
if (viewport) {
|
||||
if (typeof viewport.getProperties === "function") {
|
||||
const { voiRange, invert, interpolationType, VOILUTFunction, colormap } = viewport.getProperties();
|
||||
p = { voiRange, invert, interpolationType, VOILUTFunction, colormap };
|
||||
}
|
||||
if (typeof viewport.getCurrentImageIdIndex === "function") {
|
||||
s = viewport.getCurrentImageIdIndex();
|
||||
}
|
||||
if (typeof viewport.getCamera === "function") {
|
||||
c = viewport.getCamera();
|
||||
}
|
||||
}
|
||||
viewportProperties.push(props);
|
||||
stackPositions.push(stackPos);
|
||||
cameraProperties.push(camera);
|
||||
}
|
||||
props.push(p);
|
||||
stackPos.push(s);
|
||||
cam.push(c);
|
||||
}
|
||||
|
||||
// Use short keys for compactness
|
||||
const state = {
|
||||
grid: viewportGrid,
|
||||
modes,
|
||||
stacks,
|
||||
stackIdx,
|
||||
stackPos,
|
||||
props,
|
||||
cam,
|
||||
};
|
||||
return JSON.stringify(state);
|
||||
};
|
||||
|
||||
// Import and restore a viewer state from JSON (using stack indices)
|
||||
window.importViewerState = (json: string) => {
|
||||
try {
|
||||
restoringStateRef.current = true;
|
||||
const state = typeof json === "string" ? JSON.parse(json) : json;
|
||||
if (state.grid) setViewportGrid(state.grid);
|
||||
if (state.modes) setViewportModes(state.modes);
|
||||
if (state.stacks) setAvailableStacks(state.stacks.map((s: any) => ({
|
||||
imageIds: s.i,
|
||||
studyInstanceUID: s.u,
|
||||
})));
|
||||
if (state.stackIdx && state.stacks) {
|
||||
const reconstructed = state.stackIdx.map(
|
||||
(idx: number) => state.stacks[idx]?.i || []
|
||||
);
|
||||
setViewportImageIds(reconstructed);
|
||||
setSelectedStackIdx(state.stackIdx);
|
||||
}
|
||||
|
||||
const state = {
|
||||
viewportGrid,
|
||||
viewportModes: activeViewportModes,
|
||||
selectedStackIdx: activeSelectedStackIdx,
|
||||
availableStacks: activeAvailableStacks,
|
||||
viewportImageIds: activeViewportImageIds,
|
||||
viewportProperties,
|
||||
stackPositions,
|
||||
cameraProperties,
|
||||
};
|
||||
return JSON.stringify(state, null, 2);
|
||||
};
|
||||
|
||||
window.importViewerState = (json: string) => {
|
||||
try {
|
||||
console.log("Importing viewer state:", json);
|
||||
restoringStateRef.current = true;
|
||||
|
||||
const state = typeof json === "string" ? JSON.parse(json) : json;
|
||||
if (state.viewportGrid) setViewportGrid(state.viewportGrid);
|
||||
if (state.viewportModes) setViewportModes(state.viewportModes);
|
||||
if (state.selectedStackIdx) setSelectedStackIdx(state.selectedStackIdx);
|
||||
if (state.availableStacks) setAvailableStacks(state.availableStacks);
|
||||
if (state.viewportImageIds) setViewportImageIds(state.viewportImageIds);
|
||||
|
||||
setTimeout(() => {
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) {
|
||||
restoringStateRef.current = false;
|
||||
return;
|
||||
}
|
||||
const numActive = state.viewportGrid?.rows * state.viewportGrid?.cols || 1;
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
const viewportId = `CT_${i}`;
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
if (!viewport) continue;
|
||||
|
||||
// Restore stack position (scroll)
|
||||
if (
|
||||
state.stackPositions &&
|
||||
typeof state.stackPositions[i] === "number" &&
|
||||
typeof viewport.setImageIdIndex === "function"
|
||||
) {
|
||||
if (csUtilities && csUtilities.jumpToSlice) {
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: state.stackPositions[i] });
|
||||
} else {
|
||||
viewport.setImageIdIndex(state.stackPositions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore viewport properties (VOI, invert, etc.)
|
||||
if (
|
||||
state.viewportProperties &&
|
||||
state.viewportProperties[i] &&
|
||||
typeof viewport.setProperties === "function"
|
||||
) {
|
||||
const props = state.viewportProperties[i];
|
||||
const { voiRange, invert, interpolationType, VOILUTFunction, colormap } = props;
|
||||
const propsToRestore: any = {};
|
||||
if (voiRange && voiRange.lower !== undefined && voiRange.upper !== undefined) propsToRestore.voiRange = voiRange;
|
||||
if (invert !== undefined) propsToRestore.invert = invert;
|
||||
if (interpolationType !== undefined) propsToRestore.interpolationType = interpolationType;
|
||||
if (VOILUTFunction) propsToRestore.VOILUTFunction = VOILUTFunction;
|
||||
if (
|
||||
colormap !== undefined &&
|
||||
colormap !== null &&
|
||||
(typeof colormap === "string" || (typeof colormap === "object" && !("actor" in colormap)))
|
||||
) {
|
||||
propsToRestore.colormap = colormap;
|
||||
}
|
||||
viewport.setProperties(propsToRestore);
|
||||
viewport.render();
|
||||
}
|
||||
|
||||
// Restore camera properties (zoom, pan, orientation)
|
||||
if (
|
||||
state.cameraProperties &&
|
||||
state.cameraProperties[i] &&
|
||||
typeof viewport.setCamera === "function"
|
||||
) {
|
||||
viewport.setCamera(state.cameraProperties[i]);
|
||||
viewport.render();
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) {
|
||||
restoringStateRef.current = false;
|
||||
console.log("Viewer state restored successfully");
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
const numActive = state.grid?.rows * state.grid?.cols || 1;
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
const viewportId = `CT_${i}`;
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
if (!viewport) continue;
|
||||
|
||||
// Restore stack position
|
||||
if (
|
||||
state.stackPos &&
|
||||
typeof state.stackPos[i] === "number" &&
|
||||
typeof viewport.setImageIdIndex === "function"
|
||||
) {
|
||||
if (csUtilities && csUtilities.jumpToSlice) {
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: state.stackPos[i] });
|
||||
} else {
|
||||
viewport.setImageIdIndex(state.stackPos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore properties
|
||||
if (
|
||||
state.props &&
|
||||
state.props[i] &&
|
||||
typeof viewport.setProperties === "function"
|
||||
) {
|
||||
viewport.setProperties(state.props[i]);
|
||||
viewport.render();
|
||||
}
|
||||
|
||||
// Restore camera
|
||||
if (
|
||||
state.cam &&
|
||||
state.cam[i] &&
|
||||
typeof viewport.setCamera === "function"
|
||||
) {
|
||||
viewport.setCamera(state.cam[i]);
|
||||
viewport.render();
|
||||
}
|
||||
}
|
||||
restoringStateRef.current = false;
|
||||
alert("Failed to import viewer state: " + e);
|
||||
}
|
||||
};
|
||||
}, 300);
|
||||
} catch (e) {
|
||||
restoringStateRef.current = false;
|
||||
alert("Failed to import viewer state: " + e);
|
||||
}
|
||||
};
|
||||
|
||||
// Export all annotations using cornerstoneTools.annotation.state.getAllAnnotations()
|
||||
window.exportAnnotations = () => {
|
||||
|
||||
Reference in New Issue
Block a user