Question

So, I have hit something of a wall. I am trying to grab a JFrame's contents or the JFrame as a whole convert it to or draw it into a BufferedImage and then write that image to a jpeg file. I got the write to file bit to work all right. The trouble is I can't find a method that lets me get the content of the JFrame without some weird issues.

I tried using a Robot but that came with a load of issues like causing the program to hang and alpha layers not working right.

The method that I found which seemed to show the most promise isn't working any better. It doesn't cause my program to hang but unfortunately when I get the contents of the JFrame using this method the resulting image is the same size as the JFrame but contains nothing but a grey panel with a black boarder 25 pixels at the top and a 3 pixel on all other sides. this corresponds to the boarder size of the JFrame itself.

I am wondering if perhaps it is to do with the BufferStrategy. or maybe I am only getting the back pane of the JFrame in which case I need to know how to grab the front or the whole thing. But really I have no idea where to go with this and most of the result I get from searching are about putting an image into a JFrame rather than turning a JFrame into an image.

I have cut down the files I wrote as much as I can and will post there here.

This now works, with a few odd eccentricities lingering from it's numerous revisions

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Scanner;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;

public class Window extends JFrame {

    private static final long serialVersionUID = 1L;
    private BufferStrategy graphicBuffer;
    int frame = 0;

    public static void main(String[] cats) {
        new Window("Testing", 600, 400);
    }

    public Window(String title, int sizeX, int sizeY) {
        setTitle(title);
        setSize(sizeX, sizeY);

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setUndecorated(false);
        this.setVisible(true);

        System.out.print("New Input: ");
        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
        String input = scanner.nextLine();

        while (scanner.hasNext()) {
            input = scanner.next();
            if (input.equals("end")) {
                scanner.close();
                break;
            } else {
                System.out.println("Working " + input);
                render();
                System.out.print("New Input: ");
            }
        }
        System.out.println("End of Loop");
    }

    public void render(boolean toImg)
    {
        if( toImg ){
            renderToImage();
        } else {
            renderToScreen();
        }
    }

    public void render() {
        if (graphicBuffer == null) {
            createBufferStrategy(3);
            graphicBuffer = getBufferStrategy();
        }
        Graphics g = graphicBuffer.getDrawGraphics();
        Graphics2D g2 = (Graphics2D) g;

        Rectangle bounds = g2.getDeviceConfiguration().getBounds();
        int h = (int) bounds.getHeight();
        int w = (int) bounds.getWidth();

        Insets insets = this.getInsets();
        int t = insets.top;
        int l = insets.right;
        int r = insets.left;
        int b = insets.bottom;

        int areaW = w - (l + r);
        int areaH = h - (t + b);

        g2.setColor(new Color(100, 0, 0));
        g2.fillRect(0, 0, w, h);

        flicker(g2, l, t, areaW, areaH);

        g2.dispose();
        g.dispose();
        graphicBuffer.show();

        grabFrame();
    }

    public void renderToImage( ) 
    {
        frame++;
        if (graphicBuffer == null) {
            createBufferStrategy(3);
            graphicBuffer = getBufferStrategy();
        }

        Rectangle bounds = this.getBounds();
        int h = (int) bounds.getHeight();
        int w = (int) bounds.getWidth();

        BufferedImage image = new BufferedImage( this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB );
        Graphics g = image.getGraphics();
        Graphics2D g2 = (Graphics2D) g;

        Insets insets = this.getInsets();
        int t = insets.top;
        int l = insets.right;
        int r = insets.left;
        int b = insets.bottom;

        int areaW = w - (l + r);
        int areaH = h - (t + b);

        g2.setColor(new Color(100, 0, 0));
        g2.fillRect(0, 0, w, h);

        flicker(g2, l, t, areaW, areaH);

        g2.dispose();
        g.dispose();
        g = graphicBuffer.getDrawGraphics();
        g2 = (Graphics2D) g;
        g2.drawImage( image, 0, 0, null );
        g2.dispose();
        g.dispose();
        graphicBuffer.show();

        testPrintToJpeg( image, frame );
    }

    public void testPrintToJpeg(BufferedImage frame, int frNum) {
        try {
            String userHome = System.getProperty("user.home");
            File outputFile = new File(userHome + "/Desktop/JavaOutput/EOL" + frNum + ".jpg");

            if (outputFile.getParentFile().mkdirs()) {
                System.out.println("[FrameToFile] Missing Folders Probably Added");
            }

            IIOImage outputImage = new IIOImage(frame, null, null);

            ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
            writer.setOutput(new FileImageOutputStream(outputFile));
            ImageWriteParam writeParam = writer.getDefaultWriteParam();
            writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            writeParam.setCompressionQuality(1.0f);
            writer.write(null, outputImage, writeParam);

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Fail at Image Writer");
        }
    }
}
Was it helpful?

Solution

In grabFrame you're calling the paint method of the content pane component to ask it to paint itself into the image's graphics context. But there's nothing on the content pane, which is a separate component. Your render method ignores the content pane and paints to the frame directly.

The second problem is that, even if you called the frame's paint method instead, the paint method ignores the supplied graphics context and paints into the buffer strategy instead. The image neither knows nor cares that this has happened. The buffer strategy for the frame is unrelated to the image.

To draw to the image, you'll have to use the graphics context of the image instead of the one from the buffer strategy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top