Write scene from Vtk PolyData to PNG File

Hi,

I have VTK PolyData XML files which are generated by a .NET Core Webservice. I’m building now an other .NET Service which will generate PDF reports. Part of this reports are a few images from the 3D model. I need to read a PolyData file, setup the camera and create then a PNG file from the scene. As this code will be running in a Webservice I can’t have any (visible) Windows Forms or other UI controls.
What’s the easiest solution to achieve this?

I can read the PolyData file. But save the scene to a png file doesn’t work. Seems like the vtkAlgorithmOutput which I set using the SetInputConnection method of the vtkPNGWriter, is not useable with the vtkPNGWriter.

I used the code from this two examples:
https://lorensen.github.io/VTKExamples/site/CSharp/IO/WritePNG/
https://lorensen.github.io/VTKExamples/site/CSharp/IO/ReadPolyData/

Thanks!
Best Regards,
Florian

I think you will need to compile VTK with one of the headless rendering modes: OSMESA (headless software rendering) or EGL (only if you have nvidia graphics card)

Dan

Hi Dan,

thanks for your reply. That doesn’t sound like an easy solution. I will spend some more time on this tomorrow.

I have now a solution which is working (see code below). It just works when compiling as x86. But that’s okay.

But I have now problems setting up the camera and set the viewport when rendering the png (or crop the image).

Can I get the bounds for all actors in the render window for the current camera position?
What I need is a PNG which shows the whole model in isometric perspective and has a margin of 10px on all sides. But I can’t find a way to achive this :frowning:

Thanks!

Here my current solution:

// read all the data from the file
vtkXMLPolyDataReader reader = vtkXMLPolyDataReader.New();
string fullFilePath = Path.GetFullPath(filePath);
reader.SetFileName(fullFilePath);
reader.Update();

vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInput(reader.GetOutput(0));

vtkActor polyDataActor = vtkActor.New();
polyDataActor.SetMapper(mapper);
polyDataActor.GetProperty().SetEdgeVisibility(1);
polyDataActor.GetProperty().SetLineWidth(2f);
double[] actorBounds = polyDataActor.GetBounds();

vtkRenderer renderer = vtkRenderer.New();
renderer.SetBackground(0.2, 0.3, 0.4);
renderer.AddActor(polyDataActor);
renderer.ResetCamera();

// setup the render window
vtkRenderWindow renderWindow = vtkRenderWindow.New();
renderWindow.SetBorders(0);     // no borders --> then the window is created with the correct size
renderWindow.SetLineSmoothing(1);
renderWindow.SetMultiSamples(8);
renderWindow.OffScreenRenderingOn();
int scale = 1;

double modelWidth = actorBounds[0] < 0 ? Math.Abs(actorBounds[0]) + actorBounds[1] : actorBounds[1] - actorBounds[0];
double modelHeight = actorBounds[2] < 0 ? Math.Abs(actorBounds[2]) + actorBounds[3] : actorBounds[3] - actorBounds[2];
double modelDepth = actorBounds[4] < 0 ? Math.Abs(actorBounds[4]) + actorBounds[5] : actorBounds[5] - actorBounds[4];
double maxWH = Math.Max(modelWidth, modelHeight);

renderWindow.SetSize(Convert.ToInt32(Math.Floor(maxWH * scale)) + 1, Convert.ToInt32(Math.Floor(maxWH * scale)) + 1);    // use maxWH for width+heigt that the ResetCamera() method does work correct
renderWindow.AddRenderer(renderer);

// setup the camera
vtkCamera camera = renderer.GetActiveCamera();
renderer.ResetCamera();
camera.Azimuth(-60);
camera.Elevation(20);

renderer.ResetCamera();
renderer.ResetCameraClippingRange();

renderWindow.Render();

// write content of render window to png
vtkPNGWriter writer = vtkPNGWriter.New();
writer.SetFileName(destinationFile);

vtkWindowToImageFilter imgFilter = vtkWindowToImageFilter.New();
imgFilter.SetInput(renderWindow);
imgFilter.SetMagnification(1);
imgFilter.SetInputBufferTypeToRGB();
imgFilter.Update();

writer.SetFileName(fullFilePath);
writer.SetInputConnection(imgFilter.GetOutputPort());
writer.Write();

How can I filter the pieces?

In my PolyData vtp files 3 pieces are definied. Per defualt I want to show only the first piece. How can I do that?

I tried to SetPiece(0) on the vtkPolyDataMapper and also get output with index 0 from the vtkXMLPolyDataReader:

        vtkXMLPolyDataReader reader = vtkXMLPolyDataReader.New();
        reader.SetFileName(fullFilePath);
        reader.Update();

        vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
        var nbOfPiecesForOutput0 = reader.GetOutput(0).GetNumberOfPieces(); // returns 1 ???
        var nbOfPieces = reader.GetOutput().GetNumberOfPieces();            // returns 1 ???
        
        mapper.SetInput(reader.GetOutput(0));
        mapper.SetPiece(0);

Also the GetNumberOfPices methods returns one. Although there are three pieces in the file!
Setting the piece index on the mapper has no effect. Allways are all three pieces are rendered!