【问题标题】:Painting to both a JFrame and a jpeg using java使用 java 绘制到 JFrame 和 jpeg
【发布时间】:2014-02-02 00:54:43
【问题描述】:

所以,我碰了壁。我正在尝试获取 JFrame 的内容或整个 JFrame 将其转换为或绘制到 BufferedImage 中,然后将该图像写入 jpeg 文件。我让写入文件位工作正常。问题是我找不到一种方法可以让我在没有一些奇怪问题的情况下获取 JFrame 的内容。

我尝试使用机器人,但这带来了很多问题,例如导致程序挂起和 alpha 层无法正常工作。

我发现似乎最有希望的方法并没有更好地工作。它不会导致我的程序挂起,但不幸的是,当我使用此方法获取 JFrame 的内容时,生成的图像与 JFrame 大小相同,但只包含一个灰色面板,顶部有一个 25 像素的黑色边框和一个其他所有侧面 3 像素。这对应于 JFrame 本身的边界大小。

我想知道这是否与 BufferStrategy 有关。或者也许我只得到 JFrame 的后面板,在这种情况下,我需要知道如何抓住前面或整个东西。但实际上我不知道该去哪里,而且我从搜索中得到的大部分结果都是关于将图像放入 JFrame 而不是将 JFrame 转换为图像。

我已经尽可能地减少了我写的文件,并将在此处发布。

现在可以了,但多次修改后仍有一些奇怪的怪癖

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");
        }
    }
}

【问题讨论】:

  • 如果我能弄清楚这个问题与什么有关,我会弄清楚这个问题的最佳标题是什么。但是现在我所知道的是,无论 JFrame 的内容如何,​​JFrame.paint(BufferedImage.getGraphics()) 都会导致灰色图像。以及无穷无尽的乐趣!我快速而肮脏的解决方法中的某些内容可能会导致无限循环。

标签: java jframe bufferedimage


【解决方案1】:

在grabFrame 中,您调用内容窗格组件的paint 方法,要求它将自身绘制到图像的图形上下文中。但是内容窗格上没有任何内容,它是一个单独的组件。您的渲染方法会忽略内容窗格并直接绘制到框架。

第二个问题是,即使您改为调用框架的paint 方法,paint 方法也会忽略提供的图形上下文并改为绘制到缓冲区策略中。图像既不知道也不关心这已经发生了。帧的缓冲策略与图像无关。

要绘制到图像,您必须使用图像的图形上下文而不是缓冲区策略中的上下文。

【讨论】:

  • 谢谢。很高兴知道。有什么推荐的读物吗?如果不是它被绘制到的框架,我不知道图像的上下文是什么,所以我需要一个关于从哪里开始寻找的提示。
  • 抱歉,在图形上下文中,我只是指Graphics 对象。图像的图形对象绘制到图像上。缓冲区策略中的图形对象绘制到帧上。要在图像上绘图,您必须使用在您的渲染方法中调用image.getGraphics() 返回的图形对象。您需要做的就是将 render() 中的绘画代码移动到某个将图形对象作为参数的方法中。然后,您可以根据需要使用缓冲区策略中的图形对象或图像的图形对象调用该方法。
  • 哦?我要赶紧去试一试!谢谢!
  • 啊!这将导致渲染不得不运行两次不会它。一次用于 JFrame,一次用于 jpeg。我想我可以放弃 BufferStrategy 并绘制到 BufferedImage 中,然后将其推送到框架上,然后再将其传递给 jpeg 保护程序。我希望有一种方法可以在将成品涂入框架后抓住它以节省工作量。
  • 是的,再次研究你的代码,我不确定我是否给了你最好的建议。我对您的哪种方法应该相互调用感到非常困惑。调用层次结构几乎是循环的。您的主要目的是将这些帧存储为 JPEG,还是将帧渲染到屏幕上,还是您总是对每一帧都进行这两种操作?
猜你喜欢
  • 1970-01-01
  • 2014-10-21
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
  • 2018-03-19
  • 2018-12-04
相关资源
最近更新 更多