Apakah ada cara untuk mengambil tangkapan layar menggunakan Java dan menyimpannya ke semacam gambar?

128

Sesederhana seperti judulnya: Dapatkah Anda menggunakan hanya perintah Java untuk mengambil tangkapan layar dan menyimpannya? Atau, apakah saya perlu menggunakan program khusus OS untuk mengambil tangkapan layar dan kemudian mengambilnya dari clipboard?

jjnguy
sumber
Saya tidak pernah tahu itu akan sesederhana itu.
jjnguy
2
Berkat pertanyaan ini, saya menulis tutorial untuk pemula absolut di blog saya: thepcwizard.in/2012/12/java-screen-capturing-tutorial.html
ThePCWizard

Jawaban:

187

Percaya atau tidak, Anda benar-benar dapat menggunakan java.awt.Robotuntuk "membuat gambar yang mengandung piksel dibaca dari layar." Anda kemudian dapat menulis gambar itu ke file di disk.

Saya baru saja mencobanya, dan semuanya berakhir seperti:

Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capture = new Robot().createScreenCapture(screenRect);
ImageIO.write(capture, "bmp", new File(args[0]));

CATATAN: Ini hanya akan menangkap monitor utama. Lihat GraphicsConfiguration untuk dukungan multi-monitor.

David Citron
sumber
1
Saya ingin tahu apakah ini yang digunakan oleh aplikasi berbagi layar seperti Elluminate ( elluminate.com ).
Chris Wagner
@java_enthu sebenarnya ya, itu akan berfungsi tanpa konsol jika Anda akan jalur hardcode untuk screenshot di aplikasi Anda.
Dmitry Zagorulkin
2
Robot tidak menyertakan mouse dalam tangkapan layar. Apakah ada fungsi serupa yang melakukan hal yang persis sama, tetapi TIDAK termasuk mouse?
null Pengguna
3
apakah ada cara untuk menangkap kursor mouse juga ?!
Mehdi Karamosly
23

Saya tidak pernah suka menggunakan Robot, jadi saya membuat metode sederhana saya sendiri untuk membuat tangkapan layar objek JFrame:

public static final void makeScreenshot(JFrame argFrame) {
    Rectangle rec = argFrame.getBounds();
    BufferedImage bufferedImage = new BufferedImage(rec.width, rec.height, BufferedImage.TYPE_INT_ARGB);
    argFrame.paint(bufferedImage.getGraphics());

    try {
        // Create temp file
        File temp = File.createTempFile("screenshot", ".png");

        // Use the ImageIO API to write the bufferedImage to a temporary file
        ImageIO.write(bufferedImage, "png", temp);

        // Delete temp file when program exits
        temp.deleteOnExit();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
}
DejanLekic
sumber
17
Ada alasan mengapa Anda tidak menyukai Robot?
Simon Forsberg
2
Anggap saja sebagai masalah selera.
DejanLekic
3
Sepertinya ini seharusnya memiliki keuntungan bekerja bahkan jika jendela target dikaburkan sebelum tangkapan layar diambil.
Brad Mace
7
Di sisi lain, ini hanya mendapatkan isi dari jendela, sedangkan dengan RobotAnda juga bisa mendapatkan bingkai jendela dan bilah judul.
Brad Mace
1
Untuk tampilan HiDPI (Mac retina) ini membuat tangkapan layar dengan resolusi setengah. Untuk memperbaiki skala bufferedImage.getGraphics (). (2, 2) sebelum argFrame.paint (bufferedImage.getGraphics ()) panggil dan gunakan BufferedImage baru (rec.width * 2, rec.height * 2, BufferedImage.TYPE_INT_ARGB) untuk buat BufferedImage
nyholku
18

Jika Anda ingin menangkap semua monitor, Anda dapat menggunakan kode berikut:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] screens = ge.getScreenDevices();

Rectangle allScreenBounds = new Rectangle();
for (GraphicsDevice screen : screens) {
    Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();

    allScreenBounds.width += screenBounds.width;
    allScreenBounds.height = Math.max(allScreenBounds.height, screenBounds.height);
}

Robot robot = new Robot();
BufferedImage screenShot = robot.createScreenCapture(allScreenBounds);
11101101b
sumber
4
akan lebih baik untuk menghitungnya dengan cara ini
Brad Mace
10
public void captureScreen(String fileName) throws Exception {
   Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
   Rectangle screenRectangle = new Rectangle(screenSize);
   Robot robot = new Robot();
   BufferedImage image = robot.createScreenCapture(screenRectangle);
   ImageIO.write(image, "png", new File(fileName));
}
pengguna2503881
sumber
3
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File; 
import javax.imageio.ImageIO;
import javax.swing.*;  

public class HelloWorldFrame extends JFrame implements ActionListener {

JButton b;
public HelloWorldFrame() {
    this.setVisible(true);
    this.setLayout(null);
    b = new JButton("Click Here");
    b.setBounds(380, 290, 120, 60);
    b.setBackground(Color.red);
    b.setVisible(true);
    b.addActionListener(this);
    add(b);
    setSize(1000, 700);
}
public void actionPerformed(ActionEvent e)
{
    if (e.getSource() == b) 
    {
        this.dispose();
        try {
            Thread.sleep(1000);
            Toolkit tk = Toolkit.getDefaultToolkit(); 
            Dimension d = tk.getScreenSize();
            Rectangle rec = new Rectangle(0, 0, d.width, d.height);  
            Robot ro = new Robot();
            BufferedImage img = ro.createScreenCapture(rec);
            File f = new File("myimage.jpg");//set appropriate path
            ImageIO.write(img, "jpg", f);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }
}

public static void main(String[] args) {
    HelloWorldFrame obj = new HelloWorldFrame();
}
}
Nilesh Jadav
sumber
Saya melakukan benchmark dan ini yang paling lambat, juga memiliki kerugian terbesar dan ukuran file terbesar. Maaf,
Liam Larsen
3
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();  
GraphicsDevice[] screens = ge.getScreenDevices();       
Rectangle allScreenBounds = new Rectangle();  
for (GraphicsDevice screen : screens) {  
       Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();        
       allScreenBounds.width += screenBounds.width;  
       allScreenBounds.height = Math.max(allScreenBounds.height, screenBounds.height);
       allScreenBounds.x=Math.min(allScreenBounds.x, screenBounds.x);
       allScreenBounds.y=Math.min(allScreenBounds.y, screenBounds.y);
      } 
Robot robot = new Robot();
BufferedImage bufferedImage = robot.createScreenCapture(allScreenBounds);
File file = new File("C:\\Users\\Joe\\Desktop\\scr.png");
if(!file.exists())
    file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
ImageIO.write( bufferedImage, "png", fos );

bufferedImage akan berisi tangkapan layar penuh, ini diuji dengan tiga monitor

pelet joe
sumber
0

Anda dapat menggunakan java.awt.Robotuntuk mencapai tugas ini.

di bawah ini adalah kode server, yang menyimpan tangkapan layar yang diambil sebagai gambar di Direktori Anda.

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.imageio.ImageIO;

public class ServerApp extends Thread
{
       private ServerSocket serverSocket=null;
       private static Socket server = null;
       private Date date = null;
       private static final String DIR_NAME = "screenshots";

   public ServerApp() throws IOException, ClassNotFoundException, Exception{
       serverSocket = new ServerSocket(61000);
       serverSocket.setSoTimeout(180000);
   }

public void run()
   {
       while(true)
      {
           try
           {
              server = serverSocket.accept();
              date = new Date();
                  DateFormat dateFormat = new SimpleDateFormat("_yyMMdd_HHmmss");
              String fileName = server.getInetAddress().getHostName().replace(".", "-");
              System.out.println(fileName);
              BufferedImage img=ImageIO.read(ImageIO.createImageInputStream(server.getInputStream()));
              ImageIO.write(img, "png", new File("D:\\screenshots\\"+fileName+dateFormat.format(date)+".png"));
              System.out.println("Image received!!!!");
              //lblimg.setIcon(img);
          }
         catch(SocketTimeoutException st)
         {
               System.out.println("Socket timed out!"+st.toString());
 //createLogFile("[stocktimeoutexception]"+stExp.getMessage());
                  break;
             }
             catch(IOException e)
             {
                  e.printStackTrace();
                  break;
         }
         catch(Exception ex)
        {
              System.out.println(ex);
        }
      }
   }

   public static void main(String [] args) throws IOException, SQLException, ClassNotFoundException, Exception{
          ServerApp serverApp = new ServerApp();
          serverApp.createDirectory(DIR_NAME);
          Thread thread = new Thread(serverApp);
            thread.start();
   }

private void createDirectory(String dirName) {
    File newDir = new File("D:\\"+dirName);
    if(!newDir.exists()){
        boolean isCreated = newDir.mkdir();
    }
 }
} 

Dan ini adalah kode Klien yang berjalan pada utas dan setelah beberapa menit ia menangkap tangkapan layar layar pengguna.

package com.viremp.client;

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.Socket;
import java.util.Random;

import javax.imageio.ImageIO;

public class ClientApp implements Runnable {
    private static long nextTime = 0;
    private static ClientApp clientApp = null;
    private String serverName = "192.168.100.18"; //loop back ip
    private int portNo = 61000;
    //private Socket serverSocket = null;

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        clientApp = new ClientApp();
        clientApp.getNextFreq();
        Thread thread = new Thread(clientApp);
        thread.start();
    }

    private void getNextFreq() {
        long currentTime = System.currentTimeMillis();
        Random random = new Random();
        long value = random.nextInt(180000); //1800000
        nextTime = currentTime + value;
        //return currentTime+value;
    }

    @Override
    public void run() {
        while(true){
            if(nextTime < System.currentTimeMillis()){
                System.out.println(" get screen shot ");
                try {
                    clientApp.sendScreen();
                    clientApp.getNextFreq();
                } catch (AWTException e) {
                    // TODO Auto-generated catch block
                    System.out.println(" err"+e);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch(Exception e){
                    e.printStackTrace();
                }

            }
            //System.out.println(" statrted ....");
        }

    }

    private void sendScreen()throws AWTException, IOException {
           Socket serverSocket = new Socket(serverName, portNo);
             Toolkit toolkit = Toolkit.getDefaultToolkit();
             Dimension dimensions = toolkit.getScreenSize();
                 Robot robot = new Robot();  // Robot class 
                 BufferedImage screenshot = robot.createScreenCapture(new Rectangle(dimensions));
                 ImageIO.write(screenshot,"png",serverSocket.getOutputStream());
                 serverSocket.close();
    }
}
Muhammad Yawar
sumber
0

Toolkit mengembalikan piksel berdasarkan PPI, akibatnya, tangkapan layar tidak dibuat untuk seluruh layar saat menggunakan PPI> 100% di Windows. Saya mengusulkan untuk melakukan ini:

DisplayMode displayMode = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getDisplayMode();
Rectangle screenRectangle = new Rectangle(displayMode.getWidth(), displayMode.getHeight());
BufferedImage screenShot = new Robot().createScreenCapture(screenRectangle);
MisterParser
sumber