printing frame content?

hi!
please help me…!!!
how can one print frame content to the printer (from opengl canvas)?

thanks!!

You can read the image data from graphics memory to main memory with glReadPixels, create a BufferedImage from this data and then print that image with the usual java printing APIs (one of the three sigh).

This thread has some info on creating the buffered image:
http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jogl;action=display;num=1091095319;start=2#2

It would be nice if JOGL included an utility method for these kinds of needs. It seems that this code is asked for once a week now :slight_smile: .

I agree. Could someone code up these routines (maybe screen capture and printing) as one or two helper classes in net.java.games.jogl.util? That would help a great deal.

I cannot remember another request for printing, but this is at least the third time I have answered a question about screenshots.

I think creating a screenshot as a buffered image and uploading a buffered image as texture are the most common requirements.

I have created a prototype utility.

The functions are pretty low level. They essentially enable the use of buffered images in the pixel transfer operations of opengl.

Any opinions?

public static BufferedImage readPixels(
GL gl, int x, int y, int width, int height);
public static void readPixels(
GL gl, int x, int y, int width, int height, BufferedImage target);
public static void drawPixels(
GL gl, BufferedImage image);
public static void texImage2D(
GL gl, BufferedImage image);

Complete Code:

package net.java.games.jogl.util;

import java.awt.image.;
import net.java.games.jogl.
;

public class ImageUtils {
public static BufferedImage readPixels(GL gl, int x, int y, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
readPixels(gl, x, y, width, height, image);
return image;
}

  public static void readPixels(GL gl, int x, int y, int width, int height, BufferedImage target) {
        int[] rawData = new int[width * height];
        
        gl.glPushClientAttrib(GL.GL_CLIENT_PIXEL_STORE_BIT);
        gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 4);
        gl.glReadPixels(x, y, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_INT_8_8_8_8, rawData);
        gl.glPopClientAttrib();
        
        convertGLToJava(width, height, rawData);
        target.setRGB(0, 0, width, height, rawData, 0, width);      
  }

  public static void drawPixels(GL gl, BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();

        int[] rawData = image.getRGB(0, 0, width, height, null, 0, width);
        convertJavaToGL(width, height, rawData);
        
        gl.glPushClientAttrib(GL.GL_CLIENT_PIXEL_STORE_BIT);
        gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4);
        gl.glDrawPixels(width, height, GL.GL_RGBA, GL.GL_UNSIGNED_INT_8_8_8_8, rawData);
        gl.glPopClientAttrib();
  }
  
  public static void texImage2D(GL gl, BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();

        int[] rawData = image.getRGB(0, 0, width, height, null, 0, width);
        convertJavaToGL(width, height, rawData);
        
        gl.glPushClientAttrib(GL.GL_CLIENT_PIXEL_STORE_BIT);
        gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 4);
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, 4, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_INT_8_8_8_8, rawData);
        gl.glPopClientAttrib();
  }
  
  /**
   * Convertes the image data from argb to rgba and flips the image vertically.
   */
  private static void convertJavaToGL(int width, int height, int[] rawData) {
        for (int y1 = 0, y2 = height - 1; y2 >= y1; y1++, y2--) {
              for (int x = 0; x < width; x++) {
                    int argb1 = rawData[y1 * width + x];
                    int argb2 = rawData[y2 * width + x];

                    int rgba1 = (argb1 << 8) | (argb1 >>> 24);
                    int rgba2 = (argb2 << 8) | (argb2 >>> 24);

                    rawData[y1 * width + x] = rgba2;
                    rawData[y2 * width + x] = rgba1;
              }
        }
  }

  /**
   * Convertes the image data from rgba to argb and flips the image vertically.
   */
  private static void convertGLToJava(int width, int height, int[] rawData) {
        for (int y1 = 0, y2 = height - 1; y2 >= y1; y1++, y2--) {
              for (int x = 0; x < width; x++) {
                    int rgba1 = rawData[y1 * width + x];
                    int rgba2 = rawData[y2 * width + x];

                    int argb1 = (rgba1 << 24) | (rgba1 >>> 8);
                    int argb2 = (rgba2 << 24) | (rgba2 >>> 8);

                    rawData[y1 * width + x] = argb2;
                    rawData[y2 * width + x] = argb1;
              }
        }
  }

}

[quote]Complete Code:
[/quote]
Excellent. Thanks. Could you provide a copyright notice for the header? At least your name so we can have proper attribution in the source base? Feel free to email me at kbr@dev.java.net.

thanks for the util functions.
Could you run through a quick example of how to use them??

Thanks in advance.

I do not claim any copyright for this code and place it into the public domain.

My real name is “Stefan Tannenbaum” and I would be happy to be mentioned as author in the code base.

Here is a usage example showing textures and screenshots.

import java.awt.;
import java.awt.event.
;
import java.awt.image.*;

import javax.swing.*;

import net.java.games.jogl.;
import net.java.games.jogl.util.
;

public class ImageUtilsDemo implements Runnable, GLEventListener, ActionListener {
JFrame frame;
GLCanvas canvas;
boolean makeScreenshot;

  public void init(GLDrawable drawable) {
        GL gl = drawable.getGL();
        
        // create the texture image (load an image with ImageIO.read() in real applications)
        BufferedImage image = createDemoImage();            
        
        // create a texture object from the image
        gl.glEnable(GL.GL_TEXTURE_2D);
        gl.glBindTexture(GL.GL_TEXTURE_2D, 1);  
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
        ImageUtils.texImage2D(gl, image);
  }

  public void display(GLDrawable drawable) {
        GL gl = drawable.getGL();
  
        // draw the texture on a fullscreen quad
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(0, 0);
        gl.glVertex2f(-1, -1);
        gl.glTexCoord2f(0, 1);
        gl.glVertex2f(-1, 1);
        gl.glTexCoord2f(1, 1);
        gl.glVertex2f(1, 1);
        gl.glTexCoord2f(1, 0);
        gl.glVertex2f(1, -1);
        gl.glEnd();
        
        // if screenshot was requested since last draw
        if (makeScreenshot) {
              makeScreenshot = false;
              
              // read pixels from canvas
              int width = drawable.getSize().width;
              int height = drawable.getSize().height;
              BufferedImage screenshot = ImageUtils.readPixels(gl, 0, 0, width, height);
              
              // show screenshot (or save with ImageIO.write())
              showImage(screenshot);
        }
  }

  void scheduleScreeenshot() {
        // screenshot must be taken within display loop
        // set a boolean tag and rerun display loop
        makeScreenshot = true;
        canvas.repaint();
  }

  public void run() {
        canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
        canvas.addGLEventListener(this);

        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        p.setPreferredSize(new Dimension(256, 256));
        p.add(canvas);

        JButton b = new JButton("Screenshot");
        b.addActionListener(this);

        frame = new JFrame("ImageUtilsDemo");
        frame.getContentPane().add(p);
        frame.getContentPane().add(b, BorderLayout.SOUTH);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.show();
  }
  
  BufferedImage createDemoImage() {
        BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 256, 256);
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.setFont(new Font("Verdana", Font.PLAIN, 50));
        g.setColor(Color.YELLOW);
        g.drawString("Hello", 40, 90);
        g.dispose();
        return image;
  }
  
  void showImage(BufferedImage image) {
        JFrame f = new JFrame("Screenshot");
        f.getContentPane().add(new JLabel(new ImageIcon(image)));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.show();
  }
  
  public void reshape(GLDrawable drawable, int x, int y, int width, int height) {
  }
  
  public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {
  }
  
  public void actionPerformed(ActionEvent e) {
        scheduleScreeenshot();
  }
  
  public static void main(String[] arguments) {
        SwingUtilities.invokeLater(new ImageUtilsDemo());
  }

}