Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use java.awt.Robot and its createScreenCapture(Rectangle) method. The method reads pixels from a screen-coordinate rectangle and returns a BufferedImage; pass that image to ImageIO.write to create a PNG, JPEG, or another supported image file. The example below captures an 800×600 area, while later examples derive bounds from a display so they also work when resolution changes.

Minimal Java Robot screenshot (PNG)

This complete class captures the rectangle whose top-left corner is (0, 0) and writes it as screenshot.png in the process working directory.

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Screenshot {
    public static void main(String[] args) throws AWTException, IOException {
        Robot robot = new Robot();
        Rectangle area = new Rectangle(0, 0, 800, 600);
        BufferedImage image = robot.createScreenCapture(area);
        ImageIO.write(image, "png", new File("screenshot.png"));
    }
}

Compile and run it in a normal desktop session:

javac Screenshot.java
java Screenshot

ImageIO.write receives the image, a format name, and a destination. A successful run creates a PNG containing exactly the requested rectangle. The rectangle must have a positive width and height; zero or negative dimensions cause IllegalArgumentException.

Capture the entire primary display

Hard-coding 800×600 is useful for a test but not for a real utility. Ask the graphics environment for the primary display’s bounds and use a Robot associated with that device.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class FullPrimaryScreenshot {
    public static void main(String[] args) throws AWTException, IOException {
        GraphicsDevice device = GraphicsEnvironment
                .getLocalGraphicsEnvironment()
                .getDefaultScreenDevice();

        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        Robot robot = new Robot(device);
        BufferedImage image = robot.createScreenCapture(bounds);

        File output = new File("primary-screen.png");
        ImageIO.write(image, "png", output);
        System.out.println("Wrote " + output.getAbsolutePath());
    }
}

The bounds are screen coordinates, not coordinates relative to an application window. A display can therefore have a negative x or y origin when the operating system places it to the left or above another monitor. Using the selected device’s configuration preserves that origin instead of assuming that every screen starts at (0, 0).

Capture one monitor in a multi-monitor setup

Enumerate the graphics devices, choose the one you need, and construct the Robot with that device. This example prints each device and captures the device selected by its index.

import java.awt.AWTException;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class OneMonitorScreenshot {
    public static void main(String[] args) throws AWTException, IOException {
        GraphicsDevice[] devices = GraphicsEnvironment
                .getLocalGraphicsEnvironment()
                .getScreenDevices();

        for (int i = 0; i < devices.length; i++) {
            Rectangle r = devices[i].getDefaultConfiguration().getBounds();
            System.out.println(i + ": " + devices[i].getIDstring() + " " + r);
        }

        int selectedIndex = 0;
        if (selectedIndex < 0 || selectedIndex >= devices.length) {
            throw new IllegalArgumentException("No such display: " + selectedIndex);
        }

        GraphicsDevice device = devices[selectedIndex];
        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        Robot robot = new Robot(device);
        BufferedImage image = robot.createScreenCapture(bounds);
        ImageIO.write(image, "png", new File("monitor-" + selectedIndex + ".png"));
    }
}

Some systems expose all monitors in one virtual coordinate space; others expose coordinate systems independently. Always obtain the rectangle from the same GraphicsDevice used to construct the Robot. If you instead want a combined desktop image, calculate the union of the device bounds only when your platform presents a shared virtual desktop, and test the result with your actual monitor arrangement.

Capture an arbitrary screen rectangle

For a toolbar, dialog, or test region, supply the desired screen coordinates directly. The following helper validates the dimensions and creates parent directories before writing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public final class RegionCapture {
    private RegionCapture() { }

    public static File capture(Rectangle area, File destination)
            throws AWTException, IOException {
        if (area.width <= 0 || area.height <= 0) {
            throw new IllegalArgumentException("Width and height must be positive");
        }
        File parent = destination.getAbsoluteFile().getParentFile();
        if (parent != null && !parent.exists() && !parent.mkdirs()) {
            throw new IOException("Could not create " + parent);
        }

        BufferedImage image = new Robot().createScreenCapture(area);
        if (!ImageIO.write(image, "png", destination)) {
            throw new IOException("No PNG writer is available");
        }
        return destination;
    }

    public static void main(String[] args) throws Exception {
        File file = capture(new Rectangle(100, 100, 640, 480),
                new File("captures/region.png"));
        System.out.println(file.getCanonicalPath());
    }
}

Coordinates refer to the desktop, so a region starting at (100, 100) is not automatically relative to the currently focused window. The user can move a window or change display arrangement between runs; derive coordinates from your own UI or configuration when repeatability matters.

High-DPI and display scaling

On a scaled display, logical screen coordinates and native device pixels can differ. The ordinary createScreenCapture call returns one BufferedImage for the requested rectangle. Java also provides createMultiResolutionScreenCapture(Rectangle), which returns a MultiResolutionImage and can include a native-resolution variant.

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.awt.image.MultiResolutionImage;
import java.io.File;
import javax.imageio.ImageIO;

public class HiDpiScreenshot {
    public static void main(String[] args) throws Exception {
        GraphicsDevice device = GraphicsEnvironment
                .getLocalGraphicsEnvironment()
                .getDefaultScreenDevice();
        Rectangle bounds = device.getDefaultConfiguration().getBounds();
        Robot robot = new Robot(device);

        MultiResolutionImage captured =
                robot.createMultiResolutionScreenCapture(bounds);

        BufferedImage largest = null;
        for (Image variant : captured.getResolutionVariants()) {
            if (variant instanceof BufferedImage) {
                BufferedImage candidate = (BufferedImage) variant;
                if (largest == null ||
                        (long) candidate.getWidth() * candidate.getHeight() >
                        (long) largest.getWidth() * largest.getHeight()) {
                    largest = candidate;
                }
            }
        }
        if (largest == null) {
            throw new IllegalStateException("No BufferedImage variant returned");
        }
        ImageIO.write(largest, "png", new File("primary-native-resolution.png"));
    }
}

Choose the multi-resolution method when downstream work needs the native-resolution pixels, such as visual comparison or OCR on a high-density display. Use the simpler method when one predictable image size is more important than retaining alternate variants.

Do not block Swing’s event-dispatch thread

Screen capture can take a noticeable amount of time, especially when the operating system must ask for capture permission. Oracle’s Robot documentation advises against calling capture on the AWT Event Dispatch Thread. Run the operation on a worker instead:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;

public class BackgroundCapture {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Thread worker = new Thread(() -> {
                try {
                    BufferedImage image = new Robot()
                            .createScreenCapture(new Rectangle(0, 0, 800, 600));
                    ImageIO.write(image, "png", new File("background.png"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, "screen-capture");
            worker.start();
        });
    }
}

Update Swing controls back on the EDT after the worker finishes. For repeated captures, reuse a Robot where practical and choose a capture interval that your application can handle; the API documentation does not promise a fixed capture speed.

Permissions, headless systems, and failure handling

Desktop session is required

Constructing Robot can throw AWTException when the platform disallows low-level input control, and it always fails in a headless environment. A container, SSH session without a graphical display, or CI runner without a desktop session cannot provide normal screen pixels. Use a real logged-in graphical session or a platform-supported virtual display.

Screen-capture permission

Some operating systems require explicit screen-recording or accessibility permission. A denied permission can cause SecurityException; if permission is not granted, the returned image contents may be undefined. Catch the exception, tell the user which operating-system permission is missing, and request access through the normal system settings rather than silently saving the result.

Validate before writing

Check the rectangle before calling the API, use an absolute output path while diagnosing problems, and check the boolean returned by ImageIO.write. A false return means no writer was found for the requested format. Also handle IOException for an unwritable directory, locked file, or full disk.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
try {
    Robot robot = new Robot();
    Rectangle area = new Rectangle(x, y, width, height);
    if (area.width <= 0 || area.height <= 0) {
        throw new IllegalArgumentException("Capture dimensions must be positive");
    }
    BufferedImage image = robot.createScreenCapture(area);
    boolean written = ImageIO.write(image, "png", outputFile);
    if (!written) {
        throw new IOException("No writer for png");
    }
} catch (java.awt.AWTException e) {
    throw new IllegalStateException("A graphical desktop is unavailable", e);
} catch (SecurityException e) {
    throw new IllegalStateException("Screen-capture permission was denied", e);
} catch (java.io.IOException e) {
    throw new IllegalStateException("Could not save the screenshot", e);
}

Choosing PNG, JPEG, or another output

The format argument is independent of the capture call. For lossless UI text and transparency-sensitive work, use png. For a smaller photographic file, try jpg, understanding that JPEG introduces lossy compression. The destination filename extension does not select the encoder; the second argument to ImageIO.write does. Keep the extension and format name consistent so other programs interpret the file correctly.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your real requirement is a rendered website rather than the pixels visible on a developer’s desktop, a screenshot API avoids managing a graphical Java session. ScreenshotNeo accepts one GET request and returns PNG, JPEG, WebP, or a PDF. Its cleanup step accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing result.

cURL

See the ScreenshotNeo API documentation for parameters and authentication. Replace YOUR_API_KEY with your key:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Browser-rendering options

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets plus arbitrary viewports, retina scale, PDF paper size/margins/landscape/page ranges, HTML/CSS-to-image, custom CSS and JavaScript, pre-capture clicks, hidden selectors, waits for a selector, delay, or network idle, ad/tracker/request/resource blocking, custom headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, image resizing, configurable-TTL caching, signed links for public <img> tags, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Plans

Every feature is included on every plan. Yearly billing provides two months free.

Plan Included shots Price
Free 1,000 per month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Use the free tier to try a browser-rendered workflow without a payment card. Create a free ScreenshotNeo account for 1,000 screenshots a month.

Troubleshooting checklist

Symptom Likely cause Fix
AWTException while constructing Robot No permitted graphical desktop, or the platform blocks low-level control. Run inside a logged-in desktop session or supported virtual display and grant the required OS permission.
SecurityException or black/undefined pixels Screen-recording permission was denied. Enable the Java runtime or packaged application in the operating system’s screen-capture settings, then restart if required.
IllegalArgumentException Width or height is zero/negative. Print the rectangle and validate both dimensions before capture.
Image has the wrong monitor or offset The rectangle was assumed to start at (0, 0), or the wrong device was selected. Read bounds from the intended GraphicsDevice and construct Robot(device).
Output file is missing Relative path points somewhere unexpected, parent directory does not exist, or writing failed. Log getAbsolutePath(), create parents, and handle IOException.
Capture freezes the UI Capture was invoked on Swing’s EDT. Move the operation to a worker thread and publish only the finished result on the EDT.
High-DPI image is not native resolution The single-resolution method was used. Use createMultiResolutionScreenCapture and select the appropriate resolution variant.

FAQ

Where does a relative screenshot filename go?

It is resolved against the Java process’s current working directory, which may differ from the directory containing your source file or JAR. Print new File(name).getAbsolutePath() or use an absolute Path when the destination must be predictable.

Can the same code capture a web page without opening it on the desktop?

Robot captures physical screen pixels, so a browser window and graphical session are required. For server-side website rendering, use the ScreenshotNeo request in the previous section instead of arranging a desktop browser.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Where does a relative screenshot filename go?

It is resolved against the Java process’s current working directory. Print the file’s absolute path or provide an absolute destination when the location must be deterministic.

Can Robot capture a website on a server with no display?

No. Robot reads desktop pixels and requires a graphical session; a headless server needs a supported virtual display or a browser-rendering API such as ScreenshotNeo.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.