<div dir="ltr">You might run into a concurrency issue.<div>VTK is not thread safe, and the way Glassfish is handling servlet may result in concurrency.</div><div>You did not notice it before because the rendering was faster in surface mode. But for volume rendering, the server side might already be in a Render() call when a new one occurs.</div><div><br></div><div>On a side note, why don't you use VTK Web or ParaViewWeb?</div><div><br></div><div>Seb</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 20, 2015 at 10:43 PM, Emptystack <span dir="ltr"><<a href="mailto:wulihouxiaoshuai@163.com" target="_blank">wulihouxiaoshuai@163.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">My Java servlet code is as following:<br>
<br>
package com.hou.service;<br>
<br>
import java.awt.image.BufferedImage;<br>
import java.io.File;<br>
import java.io.FileInputStream;<br>
import java.io.FileNotFoundException;<br>
import java.io.FileOutputStream;<br>
import java.io.IOException;<br>
<br>
import javax.imageio.ImageIO;<br>
import javax.servlet.ServletException;<br>
import javax.servlet.ServletOutputStream;<br>
import javax.servlet.http.HttpServlet;<br>
import javax.servlet.http.HttpServletRequest;<br>
import javax.servlet.http.HttpServletResponse;<br>
import javax.servlet.http.HttpSession;<br>
<br>
import com.hou.core.RenderContext;<br>
import com.sun.image.codec.jpeg.JPEGCodec;<br>
import com.sun.image.codec.jpeg.JPEGImageEncoder;<br>
<br>
import vtk.vtkActor;<br>
import vtk.vtkConeSource;<br>
import vtk.vtkJPEGWriter;<br>
import vtk.vtkNativeLibrary;<br>
import vtk.vtkPolyDataMapper;<br>
import vtk.vtkRenderWindow;<br>
import vtk.vtkRenderWindowInteractor;<br>
import vtk.vtkRenderer;<br>
import vtk.vtkUnsignedCharArray;<br>
import vtk.vtkWindowToImageFilter;<br>
<br>
public class Image extends HttpServlet {<br>
<br>
/**<br>
*<br>
*/<br>
private static final long serialVersionUID = 1L;<br>
<br>
// private RenderContext renderContext;<br>
<br>
// Load VTK library and print which library was not properly loaded<br>
static {<br>
if (!vtkNativeLibrary.LoadAllNativeLibraries()) {<br>
for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {<br>
if (!lib.IsLoaded()) {<br>
System.out.println(lib.GetLibraryName() + " not loaded");<br>
} else {<br>
System.out.println(lib.GetLibraryName() + " loaded");<br>
}<br>
}<br>
} else {<br>
System.out.println("All Libraries are loaded");<br>
}<br>
vtkNativeLibrary.DisableOutputWindow(null);<br>
}<br>
<br>
@Override<br>
protected void doGet(HttpServletRequest req, HttpServletResponse resp)<br>
throws ServletException, IOException {<br>
// TODO Auto-generated method stub<br>
// super.doGet(req, resp);<br>
<br>
HttpSession session = req.getSession(false);<br>
<br>
int count;<br>
<br>
vtkConeSource cone;<br>
vtkPolyDataMapper mapper;<br>
vtkActor actor;<br>
vtkRenderer renderer;<br>
vtkRenderWindow renderWindow;<br>
vtkRenderWindowInteractor interactor;<br>
<br>
String countKey = "count";<br>
<br>
String coneKey = "cone";<br>
String mapperKey = "mapper";<br>
String actorKey = "actor";<br>
String rendererKey = "renderer";<br>
String renderWindowKey = "renderWindow";<br>
String interactorKey = "interactor";<br>
<br>
if (session == null) {<br>
session = req.getSession(true);<br>
<br>
count = 0;<br>
session.setAttribute(countKey, count);<br>
<br>
cone = new vtkConeSource();<br>
cone.SetHeight(3.0);<br>
cone.SetRadius(1.0);<br>
cone.SetResolution(10);<br>
session.setAttribute(coneKey, cone);<br>
<br>
mapper = new vtkPolyDataMapper();<br>
mapper.SetInputConnection(cone.GetOutputPort());<br>
session.setAttribute(mapperKey, mapper);<br>
<br>
actor = new vtkActor();<br>
actor.SetMapper(mapper);<br>
session.setAttribute(actorKey, actor);<br>
<br>
renderer = new vtkRenderer();<br>
renderer.AddActor(actor);<br>
session.setAttribute(rendererKey, renderer);<br>
<br>
renderWindow = new vtkRenderWindow();<br>
renderWindow.SetSize(300, 300);<br>
renderWindow.SetOffScreenRendering(1);<br>
renderWindow.AddRenderer(renderer);<br>
session.setAttribute(renderWindowKey, renderWindow);<br>
<br>
interactor = new vtkRenderWindowInteractor();<br>
interactor.SetRenderWindow(renderWindow);<br>
session.setAttribute(interactorKey, interactor);<br>
<br>
interactor.Initialize();<br>
interactor.Render();<br>
} else {<br>
interactor =<br>
(vtkRenderWindowInteractor)session.getAttribute(interactorKey);<br>
renderWindow = (vtkRenderWindow)session.getAttribute(renderWindowKey);<br>
<br>
count = (int)session.getAttribute(countKey);<br>
count++;<br>
if (count == 1) {<br>
interactor.SetEventPosition(100, 100);<br>
interactor.SetLastEventPosition(100, 100);<br>
interactor.LeftButtonPressEvent();<br>
}<br>
else {<br>
interactor.LeftButtonPressEvent();<br>
interactor.SetEventPosition(110, 110);<br>
interactor.SetLastEventPosition(100, 100);<br>
interactor.MouseMoveEvent();<br>
}<br>
session.setAttribute(countKey, count);<br>
}<br>
<br>
int[] size = renderWindow.GetSize();<br>
<br>
vtkUnsignedCharArray pixelDataArray = new vtkUnsignedCharArray();<br>
<br>
renderWindow.GetPixelData(0, 0, size[0] - 1, size[1] - 1,<br>
1-renderWindow.GetDoubleBuffer(), pixelDataArray);<br>
<br>
// convert unsigned char to byte,note the range of each primitive type<br>
byte[] bytePixelData = pixelDataArray.GetJavaArray();<br>
<br>
int[] RGBPixelData = new int[bytePixelData.length];<br>
<br>
// convert byte to unsigned and stored in RGBPixelData array<br>
for (int i = 0; i < RGBPixelData.length; i++) {<br>
RGBPixelData[i] = bytePixelData[i] & 0xff;<br>
}<br>
int[] pixelData = new int[size[0] * size[1]];<br>
<br>
int index = 0;<br>
int r, g, b;<br>
<br>
// The sequence of pixels is from left to right and from bottom to top,<br>
// so we need flip the RGB pixel<br>
// no A channel to avoid image distortion<br>
for (int row = size[1] - 1; row >= 0; row--) {<br>
for (int column = 0; column < size[0]; column++) {<br>
r = RGBPixelData[3 * (size[1] * row + column)];<br>
g = RGBPixelData[3 * (size[1] * row + column) + 1];<br>
b = RGBPixelData[3 * (size[1] * row + column) + 2];<br>
<br>
if (r > 255) {<br>
r = 255;<br>
}<br>
if (r < 0) {<br>
r = 0;<br>
}<br>
if (g > 255) {<br>
g = 255;<br>
}<br>
if (g < 0) {<br>
g = 0;<br>
}<br>
if (b > 255) {<br>
b = 255;<br>
}<br>
if (b < 0) {<br>
b = 0;<br>
}<br>
<br>
pixelData[index] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b &<br>
0xff));<br>
index++;<br>
}<br>
<br>
}<br>
BufferedImage bi = new BufferedImage(size[0], size[1],<br>
BufferedImage.TYPE_INT_RGB);<br>
bi.getRaster().setDataElements(0, 0, size[0], size[1], pixelData);<br>
<br>
// get a ServletOutputStream for writing binary data<br>
ServletOutputStream so = resp.getOutputStream();<br>
// This creates an instance of a JPEGImageEncoder<br>
// that can be used to encode image data as JPEG Data streams.<br>
JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(so);<br>
// Encode a BufferedImage as a JPEG data stream<br>
jie.encode(bi);<br>
<br>
so.flush();<br>
}<br>
}<br>
<br>
I used a simple cone to test the rotation. And after several requests the<br>
cone can be rotated. So I replaced the code with the following volume<br>
rendering code :<br>
<br>
package com.hou.service;<br>
<br>
import java.awt.image.BufferedImage;<br>
import java.io.File;<br>
import java.io.FileInputStream;<br>
import java.io.FileNotFoundException;<br>
import java.io.FileOutputStream;<br>
import java.io.IOException;<br>
<br>
import javax.imageio.ImageIO;<br>
import javax.servlet.ServletException;<br>
import javax.servlet.ServletOutputStream;<br>
import javax.servlet.http.HttpServlet;<br>
import javax.servlet.http.HttpServletRequest;<br>
import javax.servlet.http.HttpServletResponse;<br>
import javax.servlet.http.HttpSession;<br>
<br>
import com.hou.auxiliary.VolumeMapperType;<br>
import com.hou.convertor.DicomImageImport;<br>
import com.hou.core.RenderContext;<br>
import com.hou.prop.ViewProp;<br>
import com.sun.image.codec.jpeg.JPEGCodec;<br>
import com.sun.image.codec.jpeg.JPEGImageEncoder;<br>
<br>
import vtk.vtkActor;<br>
import vtk.vtkColorTransferFunction;<br>
import vtk.vtkConeSource;<br>
import vtk.vtkDICOMImageReader;<br>
import vtk.vtkGPUVolumeRayCastMapper;<br>
import vtk.vtkImageData;<br>
import vtk.vtkImageShiftScale;<br>
import vtk.vtkJPEGWriter;<br>
import vtk.vtkNativeLibrary;<br>
import vtk.vtkPiecewiseFunction;<br>
import vtk.vtkPlaneSource;<br>
import vtk.vtkPolyDataMapper;<br>
import vtk.vtkRenderWindow;<br>
import vtk.vtkRenderWindowInteractor;<br>
import vtk.vtkRenderer;<br>
import vtk.vtkSmartVolumeMapper;<br>
import vtk.vtkUnsignedCharArray;<br>
import vtk.vtkVolume;<br>
import vtk.vtkVolumeMapper;<br>
import vtk.vtkVolumeProperty;<br>
import vtk.vtkVolumeRayCastMIPFunction;<br>
import vtk.vtkVolumeRayCastMapper;<br>
import vtk.vtkWindowToImageFilter;<br>
<br>
public class Image extends HttpServlet {<br>
<br>
/**<br>
*<br>
*/<br>
private static final long serialVersionUID = 1L;<br>
<br>
// private RenderContext renderContext;<br>
<br>
// Load VTK library and print which library was not properly loaded<br>
static {<br>
if (!vtkNativeLibrary.LoadAllNativeLibraries()) {<br>
for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {<br>
if (!lib.IsLoaded()) {<br>
System.out.println(lib.GetLibraryName() + " not loaded");<br>
} else {<br>
System.out.println(lib.GetLibraryName() + " loaded");<br>
}<br>
}<br>
} else {<br>
System.out.println("All Libraries are loaded");<br>
}<br>
vtkNativeLibrary.DisableOutputWindow(null);<br>
}<br>
<br>
@Override<br>
protected void doGet(HttpServletRequest req, HttpServletResponse resp)<br>
throws ServletException, IOException {<br>
// TODO Auto-generated method stub<br>
// super.doGet(req, resp);<br>
<br>
HttpSession session = req.getSession(false);<br>
<br>
int count;<br>
<br>
vtkDICOMImageReader reader;<br>
vtkGPUVolumeRayCastMapper mapper;<br>
vtkColorTransferFunction colorTransferFunction;<br>
vtkPiecewiseFunction opacityFunction;<br>
vtkVolumeProperty volumeProperty;<br>
vtkVolume volume;<br>
vtkRenderer renderer;<br>
vtkRenderWindow renderWindow;<br>
vtkRenderWindowInteractor interactor;<br>
<br>
String countKey = "count";<br>
<br>
String readerKey = "reader";<br>
String colorTFKey = "colorTF";<br>
String opacityTFKey = "opacityTF";<br>
String mapperKey = "mapper";<br>
String volumePropertyKey = "volumeProperty";<br>
String volumeKey = "volume";<br>
String rendererKey = "renderer";<br>
String renderWindowKey = "renderWindow";<br>
String interactorKey = "interactor";<br>
<br>
if (session == null) {<br>
session = req.getSession(true);<br>
<br>
reader = new vtkDICOMImageReader();<br>
reader.SetDirectoryName("/home/garnett/image/CT");<br>
reader.Update();<br>
session.setAttribute(readerKey, reader);<br>
<br>
<br>
colorTransferFunction = new vtkColorTransferFunction();<br>
colorTransferFunction.AddRGBPoint(-3024, 0.0, 0.0, 0.0);<br>
colorTransferFunction.AddRGBPoint(42.9, 0.55, 0.25, 0.15);<br>
colorTransferFunction.AddRGBPoint(184.4, 0.92, 0.64, 0.06);<br>
colorTransferFunction.AddRGBPoint(277.64, 1.0, 0.88, 0.62);<br>
colorTransferFunction.AddRGBPoint(1430, 1.0, 0.99, 0.95);<br>
session.setAttribute(colorTFKey, colorTransferFunction);<br>
<br>
opacityFunction = new vtkPiecewiseFunction();<br>
opacityFunction.AddPoint(-3024, 0.0);<br>
opacityFunction.AddPoint(42.9, 0.0);<br>
opacityFunction.AddPoint(163.5, 0.429);<br>
opacityFunction.AddPoint(277.64, 0.777);<br>
opacityFunction.AddPoint(1430, 0.758);<br>
session.setAttribute(opacityTFKey, opacityFunction);<br>
<br>
volumeProperty = new vtkVolumeProperty();<br>
volumeProperty.SetColor(colorTransferFunction);<br>
volumeProperty.SetScalarOpacity(opacityFunction);<br>
volumeProperty.SetInterpolationTypeToLinear();<br>
volumeProperty.ShadeOn();<br>
volumeProperty.SetAmbient(0.1);<br>
volumeProperty.SetDiffuse(0.9);<br>
volumeProperty.SetSpecular(0.2);<br>
volumeProperty.SetSpecularPower(10.0);<br>
volumeProperty.SetScalarOpacityUnitDistance(0.8919);<br>
session.setAttribute(volumePropertyKey, volumeProperty);<br>
<br>
mapper = new vtkGPUVolumeRayCastMapper();<br>
mapper.SetBlendModeToComposite();<br>
mapper.SetInput(reader.GetOutput());<br>
mapper.Update();<br>
session.setAttribute(mapperKey, mapper);<br>
<br>
volume = new vtkVolume();<br>
volume.SetMapper(mapper);<br>
volume.SetProperty(volumeProperty);<br>
session.setAttribute(volumeKey, volume);<br>
<br>
count = 0;<br>
session.setAttribute(countKey, count);<br>
<br>
renderer = new vtkRenderer();<br>
renderer.AddVolume(volume);<br>
session.setAttribute(rendererKey, renderer);<br>
<br>
renderWindow = new vtkRenderWindow();<br>
renderWindow.SetSize(300, 300);<br>
renderWindow.SetOffScreenRendering(1);<br>
renderWindow.AddRenderer(renderer);<br>
session.setAttribute(renderWindowKey, renderWindow);<br>
<br>
interactor = new vtkRenderWindowInteractor();<br>
interactor.SetRenderWindow(renderWindow);<br>
session.setAttribute(interactorKey, interactor);<br>
<br>
interactor.Initialize();<br>
interactor.Render();<br>
} else {<br>
interactor =<br>
(vtkRenderWindowInteractor)session.getAttribute(interactorKey);<br>
renderWindow = (vtkRenderWindow)session.getAttribute(renderWindowKey);<br>
<br>
count = (int)session.getAttribute(countKey);<br>
count++;<br>
if (count == 1) {<br>
interactor.SetEventPosition(100, 100);<br>
interactor.SetLastEventPosition(100, 100);<br>
interactor.LeftButtonPressEvent();<br>
interactor.LeftButtonReleaseEvent();<br>
}<br>
else {<br>
interactor.LeftButtonPressEvent();<br>
interactor.SetEventPosition(110, 110);<br>
interactor.SetLastEventPosition(100, 100);<br>
interactor.MouseMoveEvent();<br>
interactor.LeftButtonReleaseEvent();<br>
}<br>
session.setAttribute(countKey, count);<br>
}<br>
<br>
int[] size = renderWindow.GetSize();<br>
<br>
vtkUnsignedCharArray pixelDataArray = new vtkUnsignedCharArray();<br>
<br>
renderWindow.GetPixelData(0, 0, size[0] - 1, size[1] - 1,<br>
1-renderWindow.GetDoubleBuffer(), pixelDataArray);<br>
<br>
// convert unsigned char to byte,note the range of each primitive type<br>
byte[] bytePixelData = pixelDataArray.GetJavaArray();<br>
<br>
int[] RGBPixelData = new int[bytePixelData.length];<br>
<br>
// convert byte to unsigned and stored in RGBPixelData array<br>
for (int i = 0; i < RGBPixelData.length; i++) {<br>
RGBPixelData[i] = bytePixelData[i] & 0xff;<br>
}<br>
int[] pixelData = new int[size[0] * size[1]];<br>
<br>
int index = 0;<br>
int r, g, b;<br>
<br>
// The sequence of pixels is from left to right and from bottom to top,<br>
// so we need flip the RGB pixel<br>
// no A channel to avoid image distortion<br>
for (int row = size[1] - 1; row >= 0; row--) {<br>
for (int column = 0; column < size[0]; column++) {<br>
r = RGBPixelData[3 * (size[1] * row + column)];<br>
g = RGBPixelData[3 * (size[1] * row + column) + 1];<br>
b = RGBPixelData[3 * (size[1] * row + column) + 2];<br>
<br>
if (r > 255) {<br>
r = 255;<br>
}<br>
if (r < 0) {<br>
r = 0;<br>
}<br>
if (g > 255) {<br>
g = 255;<br>
}<br>
if (g < 0) {<br>
g = 0;<br>
}<br>
if (b > 255) {<br>
b = 255;<br>
}<br>
if (b < 0) {<br>
b = 0;<br>
}<br>
<br>
pixelData[index] = ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b &<br>
0xff));<br>
index++;<br>
}<br>
<br>
}<br>
BufferedImage bi = new BufferedImage(size[0], size[1],<br>
BufferedImage.TYPE_INT_RGB);<br>
bi.getRaster().setDataElements(0, 0, size[0], size[1], pixelData);<br>
<br>
// get a ServletOutputStream for writing binary data<br>
ServletOutputStream so = resp.getOutputStream();<br>
// This creates an instance of a JPEGImageEncoder<br>
// that can be used to encode image data as JPEG Data streams.<br>
JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(so);<br>
// Encode a BufferedImage as a JPEG data stream<br>
jie.encode(bi);<br>
<br>
so.flush();<br>
}<br>
<br>
<br>
}<br>
<br>
The first request still can get the image, but the second request failed.<br>
After some debugging works, I hav found that the problem happeneded at the<br>
interactor.MouseMoveEvent() method which invokes the<br>
vtkRenderWindowInteractor::Render() method. I don't know why it crashed at<br>
this place. Is there something wrong with my java servlet code? I have been<br>
confused with this problem for several months.<br>
Looking forward to your reply!<br>
Best fishes!<br>
<br>
<br>
<br>
<br>
--<br>
View this message in context: <a href="http://vtk.1045678.n5.nabble.com/Java-servlet-Glassfish-volume-rendering-applications-problem-tp5730017p5730190.html" target="_blank">http://vtk.1045678.n5.nabble.com/Java-servlet-Glassfish-volume-rendering-applications-problem-tp5730017p5730190.html</a><br>
<div class="HOEnZb"><div class="h5">Sent from the VTK - Users mailing list archive at Nabble.com.<br>
_______________________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
<br>
Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
<br>
Please keep messages on-topic and check the VTK FAQ at: <a href="http://www.vtk.org/Wiki/VTK_FAQ" target="_blank">http://www.vtk.org/Wiki/VTK_FAQ</a><br>
<br>
Search the list archives at: <a href="http://markmail.org/search/?q=vtkusers" target="_blank">http://markmail.org/search/?q=vtkusers</a><br>
<br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://public.kitware.com/mailman/listinfo/vtkusers" target="_blank">http://public.kitware.com/mailman/listinfo/vtkusers</a><br>
</div></div></blockquote></div><br></div>