1

How to capture a Screenshot in native screen resolution?

The machine used to run the program is a macbook pro retina 15 with a resolution of 2880 x 1800 px. However, the output of createScreenCapture() from the Robot class only output half of that.

The dimensions screenSize below only returns 1440 x 900 px.

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

I'm currently running JRE 9 and the latest version of Eclipse.

Ratton
  • 11
  • 2
  • `Robot` probably doesn't care about the native resolution and just uses the resolution currently in use. You might have to look for a more native approach. – Kayaman Jan 07 '18 at 19:53
  • Would there be a way to make the java.awt dpi aware based on what you need? – Ratton Jan 07 '18 at 19:57
  • If you search for Java retina, you can notice that it hasn't been an easy path together for them. – Kayaman Jan 07 '18 at 20:06
  • Yea well, I might be confused , but i saw it should have hdpi support in java 8 and 9. Here is a [link](https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6) from Oracle JDK 9 release. Look for "retina". – Ratton Jan 07 '18 at 20:17
  • It being supported doesn't mean that your resolution *isn't* 1440x900. The method `getScreenSize()` doesn't mention anything about the **native** resolution of the screen. You might want to toy around with `GraphicsDevice` and othere related classes to see what kind of info you can get from your current environment. – Kayaman Jan 07 '18 at 20:23
  • There is a difference between physical and virtual resolutions on Macs and iOS. What tends to happen is the output is scaled from a higher resolution to fit the physical pixel resolution - it's all smoke a mirrors :P – MadProgrammer Jan 07 '18 at 20:54

3 Answers3

2

Robot do not will do this work, it fail at high resolution !

If you use Windows try this, otherwise tell me which operating system you use may I help you

Using Java 12 and JNA 5.4.0

import com.sun.jna.platform.win32.GDI32Util;
import com.sun.jna.platform.win32.WinDef.HWND;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

public class Main {

    public static void main(String[] args) {
        try {
            //Get JNA User32 Instace
            com.sun.jna.platform.win32.User32 user32 = com.sun.jna.platform.win32.User32.INSTANCE;
            //Get desktop windows handler
            HWND hwnd = user32.GetDesktopWindow();
            //Create a BufferedImage
            BufferedImage bi;
            //Function that take screenshot and set to BufferedImage bi
            bi = GDI32Util.getScreenshot(hwnd);
            //Save screenshot to a file
            ImageIO.write(bi, "png", new java.io.File("screenshot.png"));
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
Community
  • 1
  • 1
1

This contains Java version of MrPowerGamerBR's answer. I use MacbookPro 16 with bootcamp, and I used another question's answer to convert Image to BufferedImage.

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MultiResolutionImage;
import java.io.File;
import javax.imageio.ImageIO;

public class Screenshot {
    public static final long serialVersionUID = 1L;

    /**
     * Converts a given Image into a BufferedImage
     * from https://stackoverflow.com/a/13605411
     *
     * @param img The Image to be converted
     * @return The converted BufferedImage
     */
    public static BufferedImage toBufferedImage(Image img) {
        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }

        // Create a buffered image with transparency
        BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

        // Draw the image on to the buffered image
        Graphics2D bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        // Return the buffered image
        return bimage;
    }

    public static void main(String[] args) {
        try {
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            Robot robot = new Robot();
            MultiResolutionImage multiResolutionImage = robot.createMultiResolutionScreenCapture(
                    new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()));
            Image image = multiResolutionImage.getResolutionVariant(3072.0, 1920.0);
            // it was found that image is actually BufferedImage, but if not, use toBufferedImage().
            BufferedImage bufferedImage = toBufferedImage(image);

            String path = "Shot.jpg";
            ImageIO.write(bufferedImage, "jpg", new File(path));
            System.out.println("Screenshot saved");

        } catch (Exception ex) {
            System.out.println(ex);
        }
   }
}
Brian Hong
  • 930
  • 11
  • 15
  • 1
    Rather than using hard coded numbers for screen resolution, I just pick the biggest image among `multiResolutionImage.getResolutionVariants()` – Brian Hong Apr 19 '23 at 13:23
0

Here's a solution that doesn't require JNA. This is in Kotlin, but it is easy to reimplement it in Java.

The 2560x1440 provided in the getResolutionVariant is my monitor's resolution.

val screenSize = Toolkit.getDefaultToolkit().screenSize

val screenCapture = robot.createMultiResolutionScreenCapture(Rectangle(screenSize.width, screenSize.height))

val image = screenCapture.getResolutionVariant(2560.0, 1440.0)
MrPowerGamerBR
  • 514
  • 1
  • 6
  • 14