takeScreenShot in JME3

Hi!



I tried to make a Screenshot with content of the openGL Window, but i did not found a function similar to jme2: DisplaySystem.takeScreenShot(String file)



So i added into the current LwjglRenderer the function of jme2.



see:

http://soundmodul.heimat.eu/starcom/LwjglRenderer.java

The changes are some imports (line 77), and from line 761 to 830.



Is there an other way to make a Screenshot?

This should definitely not be in the LwjglRenderer.

Someone posted a helper class to render a screen shot to a texture. Maybe you could extend what he did an make a helper class that save this texture to a file.



http://hub.jmonkeyengine.org/groups/contribution-depot-jme3/snippets/single/15/

Sorry, i did not get it working!

After setup:

new ScreenCaptureHelper(mainCamera, rootNode, renderManager)

the Texture2d.Image:

texture.getImage().getData(0)

returns always null.



What can i do in this case?

Usage of ScreenCaptureHelper:

  1. setup it.

    [java]

    ScreenCaptureHelper helper = new ScreenCaptureHelper(mainCamera, rootNode, renderManager)

    helper.getTexture(); // returned texture contains no data now.

    [/java]
  2. perform screen capture

    [java]

    helper.captureScreen(); // if texture was attached to a mesh, you can see screen contents on the model.

    [/java]

There was actually a ScreenshotAppState added recently, it creates a screenshot of the screen and saves it into a PNG file in the working directory when you press “Print Screen”.

1 Like

Its been stored here: http://hub.jmonkeyengine.org/groups/contribution-depot-jme3/snippets/

I used the ScreenshotAppState, but the output picture is vertical and horizontal mirrored!

Is it a bug? Otherwise it works great. Hope someone can give me a solution

I dont think its a bug, AWT and OpenGL use different coordinates. Just flip the image, its easy to do using AWT image manipulation.

Thats strange, I thought I fixed that issue already. Make sure you test with the latest revision :slight_smile:

Ok, I will. (I did, but I will check again ;))

What about the “Nigthly Builds”? I like them more, that the SVN.

DarkPhoenixX said:
What about the "Nigthly Builds"? I like them more, that the SVN.

What about them?

Works fine with ScreenshotAppState!

Thanks for all your replies.

Hey guys,



first thank you for having a possibility to generate screenshots in this simple way. I played a little bit with the ScreenshotAppState and always have a single line in the resulting image. Any ideas?



Can you try taking screenshots inside of jME3 tests or other applications to see if this happens?

I think it might be a graphics card driver issue of some sort, try to install latest drivers and see if that helps.

Hi,



my graphics card driver is latest (NVidia GeForce 425M). But you were right. If i use the ScreenshotAppState for example in the TestNormalMapping the resulting screen has no line in its center.



My current implementation:



[java]private void saveAsImage(final String pFile) {

LOG.info(“Saving screenshot to “” + pFile + “”.”);



screenState.setCurrentFile(new File(pFile));

cityApp.addAppState(screenState);

cityApp.flush(false);

try {

synchronized (this) {

wait();

}

} catch (InterruptedException e) {

e.printStackTrace();

}

cityApp.getStateManager().detach(screenState);

}[/java]



I copied the ScreenshotAppState and added a method to take a file. That’s the only thing i’ve changed.



Regards

Moe

Hi!



I did the same, but it works for me!



The code of my ScreenShotAppState:

[java]

package starcom.jme3d.render;



/** Kopie von com.jme3.app.state.ScreenshotAppState; Modifiziert **/



import com.jme3.app.state.AbstractAppState;

import com.jme3.app.state.AppStateManager;

import com.jme3.app.Application;

import com.jme3.input.InputManager;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.post.SceneProcessor;

import com.jme3.renderer.RenderManager;

import com.jme3.renderer.Renderer;

import com.jme3.renderer.ViewPort;

import com.jme3.renderer.queue.RenderQueue;

import com.jme3.texture.FrameBuffer;

import com.jme3.util.BufferUtils;

import com.jme3.util.Screenshots;

import java.awt.image.BufferedImage;

import java.awt.Image;

import java.io.File;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.util.List;

import java.util.logging.Level;

import java.util.logging.Logger;

import javax.imageio.ImageIO;

import java.awt.event.ActionListener;



public class ScreenshotAppState extends AbstractAppState implements SceneProcessor {



private static final Logger logger = Logger.getLogger(ScreenshotAppState.class.getName());

private boolean capture = false;

private Renderer renderer;

private ByteBuffer outBuf;

private String screenShotFile;

private int shotIndex = 0;

private BufferedImage awtImage;

ActionListener readyAction;



@Override

public void initialize(AppStateManager stateManager, Application app) {

super.initialize(stateManager, app);

List<ViewPort> vps = app.getRenderManager().getPostViews();

ViewPort last = vps.get(vps.size()-1);

last.addProcessor(this);



}



public void takeScreenShot() { takeScreenShot(null); }

public void takeScreenShot(String screenShotFile)

{

this.screenShotFile = screenShotFile;

capture = true;

}



public void setActionListener(ActionListener readyAction) {this.readyAction = readyAction;}



public Image getLastScreenShot()

{

if (awtImage==null) {return null;}

return awtImage.getScaledInstance(awtImage.getWidth(),awtImage.getHeight(),Image.SCALE_FAST);

}



public void initialize(RenderManager rm, ViewPort vp) {

renderer = rm.getRenderer();

reshape(vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());

}



@Override

public boolean isInitialized() {

return super.isInitialized() && renderer != null;

}



public void reshape(ViewPort vp, int w, int h) {

outBuf = BufferUtils.createByteBuffer(wh4);

awtImage = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);

}



public void preFrame(float tpf) {}



public void postQueue(RenderQueue rq) {}



public void postFrame(FrameBuffer out)

{

if (capture)

{

capture = false;

shotIndex++;



renderer.readFrameBuffer(out, outBuf);

Screenshots.convertScreenShot(outBuf, awtImage);



if (screenShotFile!=null)

{

try

{

ImageIO.write(awtImage, "png", new File(screenShotFile));

} catch (IOException ex){ logger.log(Level.SEVERE, "Error while saving screenshot", ex); }

}

if (readyAction!=null)

{

javax.swing.SwingUtilities.invokeLater(new Runnable()

{

@Override

public void run()

{

readyAction.actionPerformed(null);

}

});

}

}

}

}

[/java]



With takeScreenShot(String file) i can store the file correctly.

Make sure that all framebuffer reading operations occur in the render thread under the postFrame call, using the method in any other places could lead to an unexpected result.

Hey guys,



thanks for the replies. After testing a little bit i found out that resizing my parent frame makes the line disappear. Maybe it could be a round problem in ScreenShots. I think i fixed it:



The following lines in Screenshots.java



[java]for (int y = 0; y < height / 2; y++){

for (int x = 0; x < width; x++){



}

}[/java]



could be replaced with:



[java]int halfHeight = (int) (height / 2f + 0.5);

for (int y = 0; y < halfHeight; y++){

for (int x = 0; x < width; x++){



}

}[/java]



Regards

Moe

Hello,



I followed all the suggestions in this topic, and I used the provided class ScreenCaptureHelper to take my screenshot.



However, once I get the Texture2D, (maybe assign it to a Picture object), how do I convert it to a BufferedImage or any other java format that allows me to save it to a jpg/png file?



Thank you for your help in advance.



Regards

Lorenzo

(Not sure why this class doesn’t appear in the javadocs.)



The code in ScreenshotAppState should work:

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/desktop/com/jme3/app/state/ScreenshotAppState.java



If not, I do have a working version that I use in Mythruna so can fix it if it’s broken. Otherwise, it should be what you are looking for on “how to do it” even if you can’t use it directly for some reason.