Capture the screen

I'm a newbie and i have a question:

Has jMonkey any function that allow me to capture the screen and export to a image file (jpg, png,…)?



Some one can help me? sorry for my english

Take a look at com.jme.app.BaseSimpleGame.java in the update() function for an example. It's something like display.getRenderer().takeScreenShot("blah");

thanks for your help. i will try

I am trying to get a screenShot but so far I get a tone of errors


Jun 20, 2008 9:00:43 PM com.jme.renderer.lwjgl.LWJGLRenderer takeScreenShot
INFO: Taking screenshot: temp.png
java.lang.NullPointerException
        at org.lwjgl.opengl.GL11.glReadPixels(GL11.java:2339)
        at com.jme.renderer.lwjgl.LWJGLRenderer.grabScreenContents(Unknown Source)
        at com.jme.renderer.lwjgl.LWJGLRenderer.takeScreenShot(Unknown Source)
        at Source.HelloWorld$22.actionPerformed(HelloWorld.java:1289)
        at javax.swing.JFileChooser.fireActionPerformed(JFileChooser.java:1718)
        at javax.swing.JFileChooser.approveSelection(JFileChooser.java:1628)
        at javax.swing.plaf.basic.BasicFileChooserUI$ApproveSelectionAction.actionPerformed(BasicFileChooserUI.java:913)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:272)
        at java.awt.Component.processMouseEvent(Component.java:6094)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
        at java.awt.Component.processEvent(Component.java:5859)
        at java.awt.Container.processEvent(Container.java:2058)
        at java.awt.Component.dispatchEventImpl(Component.java:4466)
        at java.awt.Container.dispatchEventImpl(Container.java:2116)
        at java.awt.Component.dispatchEvent(Component.java:4296)
        at com.jmex.awt.swingui.JMEDesktop.dispatchEvent(Unknown Source)
        at com.jmex.awt.swingui.JMEDesktop.sendAWTMouseEvent(Unknown Source)
        at com.jmex.awt.swingui.JMEDesktop.access$1000(Unknown Source)
        at com.jmex.awt.swingui.JMEDesktop$7.run(Unknown Source)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
null
error
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:284)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)



Here is the code in which I call the renderer :

private void createSaveAsDialog() {
        // <editor-fold defaultstate="collapsed" desc="Save As ... dialog">
        // MOVE dialog


        final JDesktopPane desktopPane = jmeDesktop.getJDesktop();
        //JFileChooser newProjectFileChooser = new JFileChooser();
        saveAsFileChooser.setCurrentDirectory(new File("projects"));
        saveAsFileChooser.addChoosableFileFilter(new HouseFilter(Utils.project));
        saveAsFileChooser.setAcceptAllFileFilterUsed(false);
        saveAsFileChooser.setApproveButtonText("Save");
        //Add custom icons for file types.
        saveAsFileChooser.setFileView(new HouseFileView());
        //Add the preview pane.
        saveAsFileChooser.setAccessory(new HousePreview(saveAsFileChooser));
        saveAsFileChooser.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent event){
                String projectName = null;
                String filePath = null;
                if(event.getSource().toString().contains("APPROVE_OPTION")){
                //    System.out.println("Open");
                    try{
                 //   System.out.println(newProjectFileChooser.getSelectedFile().toURL());
                    projectName = saveAsFileChooser.getSelectedFile().getName();
                    if(saveAsFileChooser.getSelectedFile().exists())
                        filePath = saveAsFileChooser.getSelectedFile().getPath();
                    else
                        filePath = "projects/" + projectName;
                    //int i = projectName.lastIndexOf('.');
                    //if(i > 0)
                    //    projectName = projectName.substring(0,i);
                   
                    int i = filePath.lastIndexOf('.');
                    if(i > 0)
                        filePath = filePath.substring(0,i);
                    System.out.println("file chooser project Name : " + projectName);
                   
                    saveScene(filePath + ".proj");
                    display.getRenderer().takeScreenShot("temp");
                   
                    } catch(Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                        System.out.println("error");
                    }
                } else {
                //    System.out.println("Cancel");
                }
               
                saveAsProjectDialog.setVisible(false);
                //file.
               
   
            }
        }) ;
        saveAsProjectDialog.getContentPane().add(saveAsFileChooser);
        saveAsProjectDialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        saveAsProjectDialog.pack();
        desktopPane.add(saveAsProjectDialog);
        //</editor-fold>
    }



You are working with a non-thread safe function outside of openGL.  (Its in an action listener, so will be called by the AWT/swing thread)



you need to inject the call into the openGL rendering thread like this



         ........
         ........
         ........
         System.out.println("file chooser project Name : " + projectName);
                   
         saveScene(filePath + ".proj");

         GameTaskQueueManager.getManager().update( new Callable<Object>() {

                    public Object call() throws Exception {
                       
                        // This is the non-thread safe call that is throwing the error
                        display.getRenderer().takeScreenShot("temp");

                        return null;
                    }
          } );


basixs said:

You are working with a non-thread safe function outside of openGL.  (Its in an action listener, so will be called by the AWT/swing thread)

you need to inject the call into the openGL rendering thread like this


         ........
         ........
         ........
         System.out.println("file chooser project Name : " + projectName);
                   
         saveScene(filePath + ".proj");

         GameTaskQueueManager.getManager().update( new Callable<Object>() {

                    public Object call() throws Exception {
                       
                        // This is the non-thread safe call that is throwing the error
                        display.getRenderer().takeScreenShot("temp");

                        return null;
                    }
          } );





What you said worked beautifully and I thank you, but now I see I've got another problem :D. Like you see in the picture below, it saves the jFileChooser window too. :P.


final JDesktopPane desktopPane = jmeDesktop.getJDesktop();
        //JFileChooser newProjectFileChooser = new JFileChooser();
        saveAsFileChooser.setCurrentDirectory(new File("projects"));
        saveAsFileChooser.addChoosableFileFilter(new HouseFilter(Utils.project));
        saveAsFileChooser.setAcceptAllFileFilterUsed(false);
        saveAsFileChooser.setApproveButtonText("Save");
        //Add custom icons for file types.
        saveAsFileChooser.setFileView(new HouseFileView());
        //Add the preview pane.
        saveAsFileChooser.setAccessory(new HousePreview(saveAsFileChooser));
        saveAsFileChooser.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent event){
                String projectName = null;
                //String filePath = null;
                if(event.getSource().toString().contains("APPROVE_OPTION")){
                //    System.out.println("Open");
                    try{
                 //   System.out.println(newProjectFileChooser.getSelectedFile().toURL());
                    projectName = saveAsFileChooser.getSelectedFile().getName();
                    if(saveAsFileChooser.getSelectedFile().exists())
                        filePath = saveAsFileChooser.getSelectedFile().getPath();
                    else
                        filePath = "projects/" + projectName;
                    //int i = projectName.lastIndexOf('.');
                    //if(i > 0)
                    //    projectName = projectName.substring(0,i);
                   
                    int i = filePath.lastIndexOf('.');
                    if(i > 0)
                        filePath = filePath.substring(0,i);
                    System.out.println("file chooser project Name : " + projectName);
                   
                    saveScene(filePath + ".proj");
                   
                    GameTaskQueueManager.getManager().update( new Callable<Object>() {
                        public Object call() throws Exception {
                            // This is the non-thread safe call that is throwing the error
                            display.getRenderer().takeScreenShot(filePath);

                            return null;
                        }
                    } );
                   
                    } catch(Exception e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                        System.out.println("error");
                    }
                } else {
                //    System.out.println("Cancel");
                }
               
                saveAsProjectDialog.setVisible(false);
               
               
            }
        }) ;
        saveAsProjectDialog.getContentPane().add(saveAsFileChooser);
        saveAsProjectDialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        saveAsProjectDialog.pack();
        desktopPane.add(saveAsProjectDialog);



I call the takeScreenShot method when the user clicks on the Save button, but I need to delay it a bit, just until the window is closed.

I think it's better if you take the screenshot the moment the "take screenshot" button is clicked, and then ask the user where to save it, rather than taking it after the save dialog.

Is there any way to do this with jmonkey3?

i cannot find the takeScreenShot method.



I’m trying to take a screen shot on a simple android application i built using the jmonkey tutorials.



Thanks

https://wiki.jmonkeyengine.org/legacy/doku.php/?do=search&id=screenshot

Thanks,

But the only things i found (And i did do a search before hand) was a way to allow the user to take a screen shot.

I want to be able to take a screen shot from code like in the example above only for jme3.

you could try using the ScreenshotAppState and calling [java]screenshotAppState.onAction("",true,0);[/java] to take a screen shot.



or if you’re feeling brave you could rip the guts out of the ScreenshotAppState.

Why are some people too dumb to search the forum or just look into the documentation???

I just clicked Documentation->Tutorials&Docs->Screenshots…

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:screenshots

@Dodikles said:
Why are some people too dumb to search the forum of just look into the documentation?????

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:screenshots


... he did search ...

@lehmannds said:
But the only things i found (And i did do a search before hand) was a way to allow the user to take a screen shot.
I want to be able to take a screen shot from code like in the example above only for jme3.


True a forum search may have been useful, but he does have a reasonable question. Using onAction is a bit of a hack, and it's not using the AppState how it was designed (and documented).

Ahh, allright. Sry :slight_smile: You should basically need to implement what ScreenshotAppState does in the postFrame() method i.e. read the framebuffer and write it to disk…

1 Like

@thetoucher: thanks for the point in the right direction.

@Dodikles: I’m sorry for having trouble with the documentation but i am not used to gmaing/3d/android/java so i’m having a little trouble here.



I’ve tried taking the ScreenshotAppState class and tweaking it for my needs.

I have run in to 2 problems:


  1. FrameBuffer param comes in as null in the postFrame function.
  2. It seems that BufferedImage and ImageIO are not supported on android so i need a different method of saving the image.



    Any ideas about how to solve these problems?



    Thanks

You probably return null in preFrame

I copied it from ScreenshotAppState and it is void:



[java]public void preFrame(float tpf) {

}[/java]



and that is the signature in SceneProcessor:

[java]public void preFrame(float tpf);[/java]



should it be different?

Right, its a processor you’re having…