Render to BufferedImage

I want to render direct in to a BufferedImage and I have no Idea how to accomplish this  :frowning:

Can someone help me please?

use texture renderer to render the scene into a texture, then go from there.

Rendering to a texture won’t help, it only copies the data to a texture handle on the GPU. If you want to copy the data back to CPU you need to use glReadPixels. In my context system, it is possible to render to a JmePixelBuffer context and then seamlessly copy the data to a jME Image object, you can then convert that to a BufferedImage or anything else. Another option is to use the grabPixels method in DisplaySystem, but that requires having an active window…

i think u can get the texture data in a bytebuffer, then use the buffer to create an buffered image.



and to be more specific on that,


ByteBuffer buffer = texture.getData();
byte[] data = new byte[buffer.capacity()];
DataBuffer dataBuffer = new DataBufferInt(data, width, height);
ColorModel colorModel = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff);
int[] masks = new int[] {...};
WritableRaster raster = Raster.createPackedRaster(dataBuffer, width, height, width, masks, null);
BufferedImage image = new BufferedImage(colorModel, raster, false, null);

Thank you for your suggestions. I have made my own solution based on tipps from a German Java forum.

But it does not run as it should :frowning:

The Landscape is shown correctly on the screen but the exported .jpg file is black. I have absolutely no idea why.




import com.jme.app.SimpleGame;
import com.jme.renderer.ColorRGBA;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import com.jme.math.Vector3f;
import com.jme.bounding.BoundingBox;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.image.Texture;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.*;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

public class Engine extends SimpleGame  {


    public static void main(String[] args) {
        Engine app = new Engine();
       
        app.start();
      
       
    }
 
 
  

 
   
   
    protected void simpleInitGame() {

        cam.setParallelProjection(true);
        float aspect = (float) display.getWidth() / display.getHeight();
        cam.setFrustum( -100, 1000, -50 * aspect, 50 * aspect, -50, 50 );
        cam.setLocation(new Vector3f(0, 0,0));
        cam.setDirection(new Vector3f(-1, -1, -1));
        cam.update();
 
        display.getRenderer().setBackgroundColor(ColorRGBA.white);
        complexTerrain();
       
        cam.update();
     
       
       
       
        //System.exit(0);
           
       
       
   
}
   
    public void saveImageFile()
            {
       
        int width = 1024; int height = 768;
      
       
        IntBuffer pixelBuf = ByteBuffer.allocateDirect((width*height)<<2).order(ByteOrder.nativeOrder()).asIntBuffer();
        GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, pixelBuf);


        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
        img.setRGB (x, y, pixelBuf.get((height - y - 1) * width + x));
            }
        }
  
       
       
        
        System.out.println(img.toString());
             String filename = "map//MapPattern_Test.jpg";

    try
             {
                System.out.println("Schreibe Pattern Datei: "+filename);
                OutputStream out = new BufferedOutputStream(new FileOutputStream(filename));
      ImageIO.write(img, "jpeg", out);
             }
    catch(IOException e)
       {
      System.out.println("Fehler beim schreiben der Pattern-Datei: "+filename);
       }
    }

    /**
     *
     * L

Could it be because you do not seem to have light added to the scene?

Hm i don't know. On the screen everything is fine and the background is set to white. So at least the saved picture should be white.

How do I add light?

rootNode.attachChild(tb);
       
        saveImageFile(); 

??
No surprise there. Attaching your terrain to the root node won't render it, so obviously anything you copy from the screen is going to be black. You need to draw the terrain first, flush the render queue, (maybe swap buffers?), then call glReadPixels.
E.g:


display.getRenderer().draw(rootNode);
display.getRenderer().renderQueue();
saveImageFile();

wow thank you! and sorry for the stupid question but I’m completely new to jme.

But there is another bug in the code the picture is somehow inverted:

This is how the screen looks:

www.TristanZindler.de/Bild4.png

This is how the jpg is looking after your correction:

www.TristanZindler.de/MapPattern_Test.jpg


Hi,



I don't know what you mean exactly by inverted, for me it simply seems that the terrain isn't textured, and I think it's because you should call updateRenderState on your object before rendering/saving it.



Hope it helps

have a look at LWJGLRenderer.takeScreenShot() and LWJGLRenderer.grabScreenContents()