Convert a Webpage to a JPEG in Java with Selenium
Capture a rendered webpage with Selenium in Java, convert it to JPEG with ImageIO, and handle viewport limits, transparency, quality, and errors.
Direct answer: use Selenium’s Java TakesScreenshot.getScreenshotAs to capture the current browser view, decode the screenshot into a BufferedImage, then write it as JPEG with ImageIO.write(image, "jpg", outputFile). Selenium’s standard screenshot is for the current browsing context; it does not guarantee a capture of the entire scrollable page. JPEG is lossy, so PNG is often better when crisp text and UI edges matter.
1. Capture a webpage and write a JPEG
This example uses Maven, ChromeDriver, and Java’s built-in ImageIO. It writes page.jpg to the current working directory, checks for a decodable image and a JPEG writer, and always closes the browser.
Maven dependency
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.19.0</version>
</dependency>
The version above is an example dependency version, not a recommendation to use it for every project. Choose a Selenium version compatible with your Java runtime and browser setup, and keep Selenium components aligned.
Complete Java program
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class WebpageToJpeg {
public static void main(String[] args) throws IOException {
WebDriver driver = new ChromeDriver();
try {
driver.get("https://example.com");
// Selenium returns the current browsing context screenshot.
File temporaryScreenshot = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
BufferedImage captured = ImageIO.read(temporaryScreenshot);
if (captured == null) {
throw new IOException("Could not decode the browser screenshot");
}
// JPEG has no alpha channel. Composite onto white before encoding.
BufferedImage rgb = new BufferedImage(
captured.getWidth(), captured.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = rgb.createGraphics();
try {
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, rgb.getWidth(), rgb.getHeight());
graphics.drawImage(captured, 0, 0, null);
} finally {
graphics.dispose();
}
File output = new File("page.jpg");
boolean hasJpegWriter = ImageIO.write(rgb, "jpg", output);
if (!hasJpegWriter) {
throw new IOException("No JPEG ImageIO writer is available");
}
System.out.println("Wrote " + output.getAbsolutePath());
} finally {
driver.quit();
}
}
}
Selenium’s screenshot API supports OutputType.FILE, BYTES, and BASE64. A FILE result is temporary, so process or copy it promptly rather than treating its path as durable storage. The ImageIO.write format name selects the encoder; its boolean result is false if no suitable writer is available, and writing can throw IOException. See the Selenium TakesScreenshot API and Java ImageIO API.
2. Wait for the page state you need
driver.get waits according to the browser’s page-load strategy, but a page can continue changing afterward: client-side rendering, animations, delayed content, and lazy images may still be in progress. Selenium’s basic screenshot call does not itself promise that those elements have settled or that below-the-fold lazy images have loaded.
For an element that signals readiness, use an explicit wait before capture. For example, add these imports and wait for a known page element:
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
new WebDriverWait(driver, Duration.ofSeconds(15))
.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("main")));
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
Replace main with a selector that appears only when the content you need is ready. For a fixed delay, JavaScript can pause execution, but an explicit condition is usually more reliable than guessing a delay. If the target depends on scrolling to trigger lazy loading, scroll the page in steps and wait for the required images or content before capturing; this does not turn a normal WebDriver screenshot into a guaranteed full-page capture.
3. Viewport screenshots versus full-page screenshots
The ordinary TakesScreenshot call captures the current browsing context as supported by the driver. Treat it as a viewport capture unless your browser-specific API explicitly documents otherwise. If the viewport dimensions matter, set them before navigating or capture:
import org.openqa.selenium.Dimension;
driver.manage().window().setSize(new Dimension(1440, 1000));
This requests a browser window size; browser chrome and headless behavior can affect the exact content viewport. When reproducibility matters, record the browser, driver, viewport, device scale, and page state alongside the output.
For a browser-specific full-page route, Selenium documents FirefoxDriver.getFullPageScreenshotAs(OutputType<X>) through its HasFullPageScreenshot interface. This is a Firefox-specific API, not a cross-browser guarantee. Check the FirefoxDriver API and verify the Selenium and Firefox versions you deploy. Selenium DevTools bindings also expose protocol screenshot features for particular browser protocol versions; those APIs are version-dependent and should be checked against your actual Selenium and browser versions. The versioned Selenium DevTools Page API documents JPEG as a screenshot format for that binding.
Do not assume that stitching separate viewport screenshots is seamless: sticky headers may repeat, animations can shift between captures, and content can change while scrolling. For a full document, prefer a documented full-page API supported by your exact browser combination, then inspect the result.
4. JPEG format, fidelity, and transparency
ImageIO’s "jpg" format writes JPEG. JPEG is lossy, which can soften small text, sharp edges, and flat-color UI. Oracle’s Java image-format tutorial advises against JPEG for screenshots where the original must be preserved exactly; PNG is lossless and supports translucency. Use JPEG when a downstream system requires it or the file-size tradeoff is useful, and use PNG when pixel fidelity or transparency matters. See Oracle’s image conversion tutorial.
JPEG does not preserve transparency. The Java example composites onto white before encoding. Change Color.WHITE to the desired opaque background when a different background is appropriate. If you do not composite explicitly, transparent areas may be rendered with an unintended background by later processing.
The simple ImageIO.write convenience method uses the available writer’s default settings. To control compression quality, obtain an ImageWriter, set explicit compression parameters, and dispose of the writer afterward. Quality values and compression behavior depend on the writer; compare representative outputs rather than assuming a universal quality-to-size ratio.
5. Alternative screenshot output types
Use the output type that matches your pipeline:
OutputType.FILE: convenient for ImageIO and filesystem output; Selenium describes this as a temporary file.OutputType.BYTES: useful when you want to decode from memory or send bytes to another service without an intermediate input file.OutputType.BASE64: useful when an API specifically expects a Base64 string; decode it before ImageIO processing.
Regardless of the input form, the JPEG encoding step needs an image representation. If you choose BYTES, wrap them in a ByteArrayInputStream and call ImageIO.read; if you choose BASE64, decode with Java’s Base64 decoder first.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ClassCastException when casting to TakesScreenshot |
The selected driver does not implement the screenshot interface as expected. | Use a supported browser WebDriver and check the driver’s Selenium API documentation. |
| Screenshot is blank or missing content | Capture happened before client-side content rendered, or the page showed a challenge/error state. | Wait for a meaningful element or application-ready condition; inspect the page before encoding. |
| Only the visible area appears | Standard WebDriver capture is not a portable full-page operation. | Use a documented browser-specific full-page method, such as Firefox’s API where compatible, and verify behavior for your exact versions. |
ImageIO.read returns null |
The file did not contain an image format recognized by an ImageIO reader, or the screenshot file was unavailable or invalid. | Check that capture completed, that the temporary file still exists, and that it contains screenshot bytes before decoding. |
ImageIO.write returns false |
No writer was found for the requested format name. | Check the format spelling (jpg) and available ImageIO providers; fail explicitly rather than reporting success. |
| JPEG has a dark or unexpected transparent background | JPEG has no alpha channel. | Composite the screenshot onto an explicit opaque color before encoding. |
| Text looks fuzzy or has halos | JPEG compression is lossy and can affect high-contrast edges. | Use PNG when fidelity matters, or compare a higher-quality JPEG setting with the receiving system’s size limit. |
| Driver startup fails | Browser/driver mismatch, missing browser installation, or environment configuration problem. | Align browser and Selenium setup, confirm the browser is installed in the runtime environment, and review the driver startup exception. |
7. Performance, reliability, and cost
Local Selenium capture requires a browser process, driver, page navigation, and image decoding/encoding. Reuse a driver for a controlled batch instead of launching one browser per URL, but isolate sessions when pages must not share cookies or state. Always call quit() in a finally block. Bound navigation and explicit waits to avoid jobs hanging indefinitely, and write output to a managed path with enough disk space.
Capture cost is primarily the compute and runtime you allocate for browser execution; this workflow has no per-shot API charge, but you operate the browser infrastructure and handle driver compatibility, timeouts, and retries. Retry transient navigation failures selectively, and avoid retry loops for deterministic errors such as invalid URLs or selectors. Store capture metadata such as URL, timestamp, viewport, browser version, and result status to diagnose inconsistent outputs.
8. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server: send one GET request with a URL and receive an image or PDF. Its API accepts options for output format, full-page capture, viewport/device presets, waiting, selectors, and other capture controls; see the ScreenshotNeo documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.jpg
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com", "format": "jpeg"},
timeout=90,
)
r.raise_for_status()
open("shot.jpg", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
format: 'jpeg'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.jpg', bytes));
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up free for 1,000 screenshots a month, no card required.
9. Frequently asked questions
Can Selenium save directly to JPEG?
The standard screenshot API returns screenshot data, not a promise of JPEG encoding. Decode the returned image and write it with Java ImageIO using the jpg format name.
Should I use jpg or jpeg in ImageIO?
jpg is the common ImageIO format name shown in Java examples. Check the writer availability and the boolean result from ImageIO.write.
Will Selenium capture a full page automatically?
Do not rely on that. The normal call captures the current browsing context; full-page methods are browser-specific, so consult the API for your chosen driver.
Why choose PNG if the required output is JPEG?
PNG is a better intermediate when you need exact screenshot edges or transparency. Convert to JPEG only at the boundary that requires it, with an explicit background for transparent pixels.


