How to create volumes from local set of dcm files?

Describe Your Question

Hello. I am new to working with dicom.
I have been studying the topic and examples (Examples | Cornerstone.js) for several days.
So far I can only work with a set of local dcm files.

I use @cornerstonejs in React
(“@cornerstonejs/core”: “^1.82.7”)

At the moment I have managed to create a working component that accepts multiple files via input[file] and renders them as a stack.

But do I understand correctly that in order to use “crosshairs” (https://www.cornerstonejs.org/live-examples/crosshairs), I need to use volumes instead of stack? If so, please tell me how I can combine working with multiple local files and “volumes”?

import { type ChangeEvent, useEffect } from 'react';
import { RenderingEngine, type Types, Enums } from '@cornerstonejs/core';
import * as cornerstoneTools from '@cornerstonejs/tools';
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
import { initDemo } from '@shared/cornerstone3d/helpers';
import { convertMultiframeImageIds, prefetchMetadataInformation } from '@shared/cornerstone3d/helpers/convertMultiframeImageIds';

const { StackScrollMouseWheelTool, ToolGroupManager } = cornerstoneTools;

const { ViewportType } = Enums;
let element: HTMLDivElement;
let viewport: Types.IStackViewport;
const toolGroupId = 'myToolGroup';

function createContent() {
    const content = document.getElementById('content');
    element = document.createElement('div');
    element.id = 'cornerstone-element';
    element.style.width = '500px';
    element.style.height = '500px';
    content && content.appendChild(element);

    cornerstoneTools.addTool(StackScrollMouseWheelTool);
}

async function run() {
    await initDemo();

    const toolGroup = ToolGroupManager.createToolGroup(toolGroupId) as cornerstoneTools.Types.IToolGroup;

    toolGroup.addTool(StackScrollMouseWheelTool.toolName);

    toolGroup.setToolActive(StackScrollMouseWheelTool.toolName);

    const renderingEngineId = 'myRenderingEngine';
    const renderingEngine = new RenderingEngine(renderingEngineId);

    const viewportId = 'CT_STACK';
    const viewportInput: Types.PublicViewportInput = {
        viewportId,
        type: ViewportType.STACK,
        element,
        defaultOptions: {
            orientation: Enums.OrientationAxis.SAGITTAL,
            background: [0.2, 0, 0.2] as Types.Point3,
        },
    };

    renderingEngine.enableElement(viewportInput);

    // Get the stack viewport that was created
    viewport = renderingEngine.getViewport(viewportId) as Types.IStackViewport;

    toolGroup.addViewport(viewportId, renderingEngineId);
}

async function loadAndViewImage(imageId: Array<string>) {
    await prefetchMetadataInformation(imageId);
    const stack = convertMultiframeImageIds(imageId);
    // Set the stack on the viewport
    viewport.setStack(stack).then(() => {
        viewport.render();
    });

    /**
     * -------------------------------------
     * ??? How to use imageId from files to create volume instead of stack??
     * -------------------------------------

     */
}

export const DicomTestViewer4 = () => {
    const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
        const ids: Array<string> = [];
        if (e.target.files && e.target.files.length > 1) {
            Array.from(e.target.files).forEach((file) => {
                const imageId = cornerstoneDICOMImageLoader.wadouri.fileManager.add(file);
                ids.push(imageId);
            });
            loadAndViewImage(ids);
        }
    };

    useEffect(() => {
        createContent();
        run();
        return () => {
            cornerstoneTools.destroy();
        };
    }, []);

    return (
        <div>
            <div>
                Choose: <input type="file" id="selectFile" onChange={handleFileChange} multiple />
            </div>
            <p>DicomTestViewer4</p>
            <div id="content"></div>
        </div>
    );
};

Inside Cornerstone3D/core there is a volumeLoader.createLocalVolume