Use java.awt.Robot to read pixels from a screen rectangle, then write the returned BufferedImage with ImageIO.write. The smallest working program creates a Robot, captures a positive-width and positive-height Rectangle, and saves a PNG. A desktop session and permitted screen access are required; a headless server cannot create a Robot.
Minimal Java Robot screenshot
This complete example captures the screen area from (0, 0) through 799 by 599 and writes screenshot.png in the process’s current 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"));
}
}
createScreenCapture(Rectangle) returns a BufferedImage containing the pixels in screen coordinates. The rectangle must have positive width and height; otherwise Java throws IllegalArgumentException. ImageIO.write chooses an image writer for the format name and destination file.
Choose the output path and format
A relative path is resolved against the JVM’s current working directory, not necessarily the folder containing your source file. Use an absolute File when another directory is required:
File output = new File(System.getProperty("user.home"), "Desktop/robot-shot.png");
boolean written = ImageIO.write(image, "png", output);
if (!written) {
throw new IOException("No ImageIO writer for PNG");
}
PNG is lossless and usually best for interface screenshots. JPEG is useful for photographic content but introduces compression artifacts. The boolean result matters: it is false when no writer is available for the requested format.
Capture a complete display instead of a fixed rectangle
Hard-coding 800 by 600 misses pixels on other resolutions. Ask the selected GraphicsDevice for its configuration bounds and associate the Robot with that device:
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 FullDisplayScreenshot {
public static void main(String[] args) throws AWTException, IOException {
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = environment.getDefaultScreenDevice();
Rectangle bounds = device.getDefaultConfiguration().getBounds();
Robot robot = new Robot(device);
BufferedImage image = robot.createScreenCapture(bounds);
File output = new File("full-display.png");
if (!ImageIO.write(image, "png", output)) {
throw new IOException("No PNG writer available");
}
System.out.println("Saved " + output.getAbsolutePath());
}
}
The default screen device is normally the primary monitor. Its bounds can have a negative x or y when the operating system places that monitor beside another display, so use the returned rectangle rather than replacing it with an origin of zero.
Capture one monitor or a selected region
One chosen monitor
Enumerate devices and select the one you need. Each device supplies its own bounds and configuration:
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] devices = ge.getScreenDevices();
if (devices.length < 2) {
throw new IllegalStateException("A second monitor is not available");
}
GraphicsDevice target = devices[1];
Rectangle monitor = target.getDefaultConfiguration().getBounds();
BufferedImage image = new Robot(target).createScreenCapture(monitor);
ImageIO.write(image, "png", new File("monitor-2.png"));
For multiple monitors, Java can expose a shared virtual coordinate system or independent coordinate systems, depending on the platform. Capturing each device separately with a Robot tied to that device avoids guessing how the desktop is arranged. If you deliberately build one union rectangle, verify the coordinates on the target operating system first; gaps or negative origins are legitimate in a multi-monitor layout.
Rank #2
A selected screen rectangle
Supply any screen-coordinate rectangle with positive dimensions. For example, this captures an 800 by 600 region beginning 100 pixels from the top-left of the virtual desktop:
Rectangle selection = new Rectangle(100, 100, 800, 600);
BufferedImage image = new Robot().createScreenCapture(selection);
ImageIO.write(image, "png", new File("selection.png"));
The coordinates are not window coordinates or component coordinates. If a window moves, the same rectangle captures whatever is currently underneath it.
High-DPI and scaled displays
On a display with user-space-to-device-space scaling, createScreenCapture returns one BufferedImage for the requested rectangle. Java also provides createMultiResolutionScreenCapture(Rectangle), which returns a MultiResolutionImage that can contain a native-resolution variant. Use it when you need the device-resolution image rather than only the logical-size result.
Free tools Windows power users keep installed
One-click scans. No signup required.
import java.awt.Graphics2D;
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;
Rectangle area = new Rectangle(0, 0, 800, 600);
Robot robot = new Robot();
MultiResolutionImage multi = robot.createMultiResolutionScreenCapture(area);
Image variant = multi.getResolutionVariant(area.width * 2.0, area.height * 2.0);
BufferedImage nativeImage = new BufferedImage(
variant.getWidth(null), variant.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = nativeImage.createGraphics();
graphics.drawImage(variant, 0, 0, null);
graphics.dispose();
ImageIO.write(nativeImage, "png", new File("high-dpi.png"));
The requested dimensions passed to getResolutionVariant express the size you want; the returned image may have a different pixel size appropriate for the device. If ordinary logical-resolution output is sufficient, the simpler BufferedImage method avoids that extra conversion.
Run capture away from Swing’s event thread
Screen capture can take noticeable time, especially when the operating system must ask for permission. Do not invoke it on Swing’s AWT Event Dispatch Thread, or the interface can stop repainting while the call completes. Start a worker thread or an executor task and update Swing components afterward on the event thread:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
BufferedImage image = new Robot().createScreenCapture(area);
ImageIO.write(image, "png", output);
SwingUtilities.invokeLater(() -> statusLabel.setText("Saved"));
} catch (AWTException | IOException | SecurityException ex) {
SwingUtilities.invokeLater(() -> statusLabel.setText(ex.getMessage()));
}
});
Shut down the executor when the application closes. Keep the image-writing operation in the worker as well; large PNGs can require additional time and memory.
Prerequisites and permission behavior
- Desktop session: Constructing
RobotthrowsAWTExceptionwhen the platform does not permit low-level input control and always does so in a headless environment. A GUI login session is required. - Screen-capture permission: Some environments require explicit permission. A denied permission can cause
SecurityException, and the API warns that image contents may be undefined when access is not granted. - Valid geometry: Width and height must both be greater than zero. Check user-supplied coordinates before calling the method.
- Coordinate consistency: Use the bounds from the same
GraphicsDeviceassociated with theRobot, particularly on multi-monitor systems.
On a server, container, or CI runner without a graphical session, use a browser screenshot service or provide a virtual display; Robot itself does not create one.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesA robust reusable method
This helper validates the rectangle, reports common failures, and verifies that an ImageIO writer actually produced the file:
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 RobotCapture {
private RobotCapture() {}
public static File capture(Rectangle area, File output)
throws AWTException, IOException {
if (area == null || area.width <= 0 || area.height <= 0) {
throw new IllegalArgumentException("Capture width and height must be positive");
}
if (output == null) {
throw new NullPointerException("output");
}
BufferedImage image = new Robot().createScreenCapture(area);
if (!ImageIO.write(image, "png", output)) {
throw new IOException("No PNG ImageIO writer is installed");
}
return output;
}
}
Troubleshooting
java.awt.AWTException: headless environment
The JVM has no usable desktop session. Run the program inside a logged-in graphical session, or switch to a service designed to render web pages without a local display.
SecurityException or a blank/undefined image
Grant the operating system’s screen-recording or screen-capture permission to the Java runtime or launcher, then restart the process if the platform requires it. Permission must be granted before trusting the pixels.
Rank #4
IllegalArgumentException from createScreenCapture
Log the rectangle’s x, y, width, and height. A zero or negative dimension is invalid. Clamp a user selection to the selected device’s bounds before capturing.
The wrong monitor or an offset image
Print getDefaultConfiguration().getBounds() for every device and compare those values with the operating system’s layout. Use new Robot(targetDevice) and that device’s bounds instead of assuming every monitor starts at (0, 0).
The file is missing or empty
Print output.getAbsolutePath() to find the actual destination and check the boolean returned by ImageIO.write. Ensure the parent directory exists and the process has write permission.
The Swing interface freezes
Move both capture and encoding to a worker thread. Publish only the final status or image model back to the Event Dispatch Thread.
Performance, reliability, and format choices
- Capture only what you need: A small rectangle uses less memory and produces a smaller file than a full desktop image.
- Do not assume a fixed pixel count: Read device bounds at runtime so the same program works across resolutions, scaling settings, and monitor arrangements.
- Handle transient permission prompts: Treat the first capture as potentially slow and keep it out of latency-sensitive UI code.
- Keep files deterministic: Use an absolute destination, check the ImageIO result, and include a timestamp or sequence number when repeated captures must not overwrite each other.
- Choose high-DPI deliberately: The multi-resolution method can provide a native-resolution variant, but it also increases image dimensions and memory use.
Or skip the browser setup:
If what you really need is a screenshot of a web page rather than the pixels currently displayed on a desktop, ScreenshotNeo takes the capture through one HTTP request. Its clean-shot pipeline accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
Recommended Free Tools
Use the API documentation at https://screenshotneo.com/docs/ for all capture options. A cURL request is:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same endpoint is available from 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)
And from 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(`${res.status} ${res.statusText}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its 63 options include full-page lazy-image loading, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, clicks before capture, selector waits, delay or network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to get started.
FAQ
Can ImageIO write WebP in every Java installation?
No. The format is available only when a matching ImageIO writer is installed. Check the boolean return value or enumerate available writers before relying on a format beyond the standard writers.
Can I capture while the desktop is locked?
Robot reads the pixels exposed by the active graphical session. If the operating system withholds the desktop or screen-capture permission, the call can fail or the returned contents may not be usable; test the target environment rather than assuming locked-session behavior.
Frequently Asked Questions
Can ImageIO write WebP in every Java installation?
No. WebP output requires an installed ImageIO writer for that format; check the boolean result or available writers before depending on it.
Can I capture while the desktop is locked?
Robot depends on pixels exposed by the active graphical session. A locked or permission-restricted desktop may reject the capture or return unusable contents, so verify behavior on the target operating system.
Quick Recap
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.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →




