Hi there,
I am trying to load a VTI image file in my React/NextJS/VTK.js app, but I am struggling to display a simple slice of the image.
I have added an actor to display the outline of the image that works well.
This the code of my component:
'use client';
import { useRef, useEffect } from 'react';
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
import vtkGenericRenderWindow from '@kitware/vtk.js/Rendering/Misc/GenericRenderWindow';
import vtkImageMapper from '@kitware/vtk.js/Rendering/Core/ImageMapper';
import vtkImageSlice from '@kitware/vtk.js/Rendering/Core/ImageSlice';
import vtkXMLImageDataReader from '@kitware/vtk.js/IO/XML/XMLImageDataReader';
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkOutlineFilter from '@kitware/vtk.js/Filters/General/OutlineFilter';
import { SlicingMode } from '@kitware/vtk.js/Rendering/Core/ImageMapper/Constants';
export default function ImageComponent() {
const vtkContainerRef = useRef(null);
const context = useRef(null);
const loadScene = async () => {
if (context.current) {
return;
}
const genericRenderWindow = vtkGenericRenderWindow.newInstance();
genericRenderWindow.setContainer(vtkContainerRef.current);
genericRenderWindow.resize();
const renderer = genericRenderWindow.getRenderer();
const renderWindow = genericRenderWindow.getRenderWindow();
renderer.setBackground(0.5, 0.5, 0.5);
renderWindow.render();
const response = await fetch("/vase.vti");
const content = await response.arrayBuffer();
const reader = vtkXMLImageDataReader.newInstance();
reader.parseAsArrayBuffer(content);
const data = reader.getOutputData(0);
// IMAGE
const mapper = vtkImageMapper.newInstance();
const actor = vtkImageSlice.newInstance();
actor.setMapper(mapper);
mapper.setInputData(data);
mapper.setSlicingMode(SlicingMode.Z);
mapper.setSlice(0);
actor.getProperty().setColorWindow(255);
actor.getProperty().setColorLevel(127.5);
renderer.addActor(actor);
// OUTLINE
const outline = vtkOutlineFilter.newInstance();
outline.setInputData(data);
const outlineMapper = vtkMapper.newInstance();
outlineMapper.setInputConnection(outline.getOutputPort());
const outlineActor = vtkActor.newInstance();
outlineActor.setMapper(outlineMapper);
outlineActor.getProperty().setColor(1, 1, 0);
outlineActor.getProperty().setLineWidth(2);
renderer.addActor(outlineActor);
renderer.resetCamera();
renderer.resetCameraClippingRange();
renderWindow.render();
context.current = {
genericRenderWindow,
actor,
outlineActor
};
};
useEffect(() => {
loadScene()
return () => {
if (context.current) {
const { genericRenderWindow, actor, outlineActor } = context.current;
actor?.getMapper().delete();
actor?.delete();
outlineActor?.getMapper().delete();
outlineActor?.delete();
genericRenderWindow.delete();
if (vtkContainerRef.current) {
vtkContainerRef.current.innerHTML = '';
}
context.current = null;
}
};
}, [vtkContainerRef]);
return (
<div ref={vtkContainerRef} className="h-[calc(100vh-64px)]" />
)
}
This is the result:
The image comes from the vtk examples:
https://gitlab.kitware.com/vtk/vtk-examples/-/blob/master/src/Testing/Data/vase.vti
Does anyone have any clue on what I might be doing wrong ?
Thanks a lot,
Clément