web-dev-qa-db-ja.com

Swing:JFrameの画像を取得

JFrameのJava.awt.Imageを取得するにはどうすればよいですか?

JFrameのスクリーンショットを取得したい(アプリケーション内で後で使用するため)。現在、これはロボットを使用して達成され、関連するJFrameの座標と寸法を指定するスクリーンショットを撮ります。

ただし、より良い方法があると考えています。Swingコンポーネントは、デフォルトで、画面にペイントする前に、イメージとしてダブルバッファーにレンダリングされます。

コンポーネントからこれらの画像を取得する方法はありますか?

62
bguiz

ComponentImageCapture.Java

import Java.awt.BorderLayout;
import Java.awt.Component;
import Java.awt.Image;
import Java.awt.Graphics;

import Java.awt.image.BufferedImage;

import Java.awt.event.ActionListener;
import Java.awt.event.ActionEvent;
import Java.awt.event.KeyEvent;
import Java.awt.event.InputEvent;

import javax.swing.*;

import javax.swing.border.TitledBorder;

import javax.imageio.ImageIO;

import Java.io.File;

/**
Create a screenshot of a component.
@author Andrew Thompson
*/
class ComponentImageCapture {

  static final String HELP =
    "Type Ctrl-0 to get a screenshot of the current GUI.\n" +
    "The screenshot will be saved to the current " +
    "directory as 'screenshot.png'.";

  public static BufferedImage getScreenShot(
    Component component) {

    BufferedImage image = new BufferedImage(
      component.getWidth(),
      component.getHeight(),
      BufferedImage.TYPE_INT_RGB
      );
    // call the Component's Paint method, using
    // the Graphics object of the image.
    component.Paint( image.getGraphics() ); // alternately use .printAll(..)
    return image;
  }

  public static void main(String[] args) {
    Runnable r = new Runnable() {
      public void run() {
        final JFrame f = new JFrame("Test Screenshot");

        JMenuItem screenshot =
          new JMenuItem("Screenshot");
        screenshot.setAccelerator(
          KeyStroke.getKeyStroke(
            KeyEvent.VK_0,
            InputEvent.CTRL_DOWN_MASK
          ));
        screenshot.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent ae) {
              BufferedImage img = getScreenShot(
                f.getContentPane() );
              JOptionPane.showMessageDialog(
                null,
                new JLabel(
                  new ImageIcon(
                    img.getScaledInstance(
                      img.getWidth(null)/2,
                      img.getHeight(null)/2,
                      Image.SCALE_SMOOTH )
                    )));
              try {
                // write the image as a PNG
                ImageIO.write(
                  img,
                  "png",
                  new File("screenshot.png"));
              } catch(Exception e) {
                e.printStackTrace();
              }
            }
          } );
        JMenu menu = new JMenu("Other");
        menu.add(screenshot);
        JMenuBar mb = new JMenuBar();
        mb.add(menu);
        f.setJMenuBar(mb);

        JPanel p = new JPanel( new BorderLayout(5,5) );
        p.setBorder( new TitledBorder("Main GUI") );
        p.add( new JScrollPane(new JTree()),
          BorderLayout.WEST );
        p.add( new JScrollPane( new JTextArea(HELP,10,30) ),
          BorderLayout.CENTER );

        f.setContentPane( p );
        f.pack();
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
      }
    };
    SwingUtilities.invokeLater(r);
  }
} 

スクリーンショット

GUI with captured image

こちらもご覧ください

上記のコードは、レンダリング前にコンポーネントが画面上で実現されていることを前提としています。

Rob Camickは、未実現のコンポーネントを Screen Image クラスでペイントする方法を示しています。

関連性のある別のスレッドは、 最初の表示なしでJLabelをレンダリング です。特に、ダリル・バークによる「1行修正」です。

LabelRenderTest.Java

次に、2番目のリンクに示されているコードの更新版を示します。

import Java.awt.*;
import Java.awt.image.BufferedImage;
import javax.swing.*;

public class LabelRenderTest {

    public static void main(String[] args) {
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {

            String title = "<html><body style='width: 200px; padding: 5px;'>"
                + "<h1>Do U C Me?</h1>"
                + "Here is a long string that will wrap.  "
                + "The effect we want is a multi-line label.";

                JFrame f = new JFrame("Label Render Test");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                BufferedImage image = new BufferedImage(
                    400,
                    300,
                    BufferedImage.TYPE_INT_RGB);
                Graphics2D imageGraphics = image.createGraphics();
                GradientPaint gp = new GradientPaint(
                    20f,
                    20f,
                    Color.red,
                    380f,
                    280f,
                    Color.orange);
                imageGraphics.setPaint(gp);
                imageGraphics.fillRect(0, 0, 400, 300);

                JLabel textLabel = new JLabel(title);
                textLabel.setSize(textLabel.getPreferredSize());

                Dimension d = textLabel.getPreferredSize();
                BufferedImage bi = new BufferedImage(
                    d.width,
                    d.height,
                    BufferedImage.TYPE_INT_ARGB);
                Graphics g = bi.createGraphics();
                g.setColor(new Color(255, 255, 255, 128));
                g.fillRoundRect(
                    0,
                    0,
                    bi.getWidth(f),
                    bi.getHeight(f),
                    15,
                    10);
                g.setColor(Color.black);
                textLabel.Paint(g);
                Graphics g2 = image.getGraphics();
                g2.drawImage(bi, 20, 20, f);

                ImageIcon ii = new ImageIcon(image);
                JLabel imageLabel = new JLabel(ii);

                f.getContentPane().add(imageLabel);
                f.pack();
                f.setLocationByPlatform(true);

                f.setVisible(true);
            }
        });
    }
}

スクリーンショット

Label rendered on image

71
Andrew Thompson