Recommended Free Tools
Pass - as wkhtmltopdf’s output target, read the child process’s standard output through Process.getInputStream(), and copy those bytes to your Java OutputStream. Keep diagnostics on stderr, wait for the process, and reject non-zero exit codes. This streams the PDF without creating an output PDF file.
Direct solution: send the PDF to stdout
wkhtmltopdf treats a single hyphen as a special output path. The command wkhtmltopdf input.html - writes PDF bytes to stdout instead of a named file. Java’s ProcessBuilder leaves that stdout available from Process.getInputStream(), so your application can copy it directly to a file stream, servlet response, cloud-storage stream, or ByteArrayOutputStream.
Reusable exporter
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
public final class WkhtmltopdfExporter {
private WkhtmltopdfExporter() {
}
public static void export(String executable,
String input,
OutputStream destination)
throws IOException, InterruptedException {
Process process = new ProcessBuilder(List.of(executable, input, "-"))
// Keep stderr away from the PDF byte stream.
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
try (InputStream pdf = process.getInputStream()) {
pdf.transferTo(destination);
}
int exit = process.waitFor();
if (exit != 0) {
throw new IOException("wkhtmltopdf exited with code " + exit);
}
}
}
The destination belongs to the caller. This method closes only the process stdout stream; it does not close your OutputStream. That matters when the destination is an HTTP response stream or a larger pipeline that still has work to do.
Compile and run
- Install a wkhtmltopdf build on the host running Java and verify that the executable is runnable by the same user as the application.
- Use
wkhtmltopdf --versionfrom that account, or configure an absolute executable path such as/usr/local/bin/wkhtmltopdf. - Call
WkhtmltopdfExporter.export("wkhtmltopdf", "input.html", destination). Replace the first argument with the absolute path when the service environment has a restrictedPATH.
Collecting the PDF in memory
A ByteArrayOutputStream is convenient when another API requires a byte array, but memory use grows with the complete PDF size.
#1 Best Overall
- Perfect Adobe Acrobat Pro alternative – lifetime license for Windows 10 and 11.
- EDIT text, images, pages, hyperlinks, designs in PDF documents. ORGANIZE PDFs.
- READ and Comment on PDFs – Intuitive reading modes & document commenting and mark up tools!
- CREATE, COMBINE, SCAN and COMPRESS PDFs.
- FILL forms & Digitally Sign PDFs. Work with Digital certificates
import java.io.ByteArrayOutputStream;
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
WkhtmltopdfExporter.export("wkhtmltopdf", "input.html", bytes);
byte[] pdfBytes = bytes.toByteArray();
For large or user-controlled documents, stream onward instead of accumulating the entire result. A temporary output file is also reasonable when a downstream component requires a seekable path or operations staff expect files.
Streaming to an HTTP response
Set the response content type before starting the conversion and pass the response’s output stream as the destination. Do not merge stderr into stdout: warning text would make the PDF invalid.
// Example inside a servlet handler
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=report.pdf");
try {
WkhtmltopdfExporter.export("/usr/local/bin/wkhtmltopdf",
"/srv/templates/report.html",
response.getOutputStream());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("PDF conversion interrupted", e);
}
If your framework requires a Content-Length header, you must render to memory or a temporary file first, because stdout streaming does not provide the final length in advance. Otherwise, use chunked transfer according to the framework’s normal response handling.
Handling stderr without deadlocks
Process.getInputStream() is the child’s stdout and getErrorStream() is its stderr. The example inherits stderr, allowing the operating system’s error stream to receive diagnostics while stdout remains pure PDF data. This is a good default for a server whose process logs are captured.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Rank #2
- ULTIMATE IMAGE PROCESSNG - GIMP is one of the best known programs for graphic design and image editing
- MAXIMUM FUNCTIONALITY - GIMP has all the functions you need to maniplulate your photos or create original artwork
- MAXIMUM COMPATIBILITY - it's compatible with all the major image editors such as Adobe PhotoShop Elements / Lightroom / CS 5 / CS 6 / PaintShop
- MORE THAN GIMP 2.8 - in addition to the software this package includes ✔ an additional 20,000 clip art images ✔ 10,000 additional photo frames ✔ 900-page PDF manual in English ✔ free e-mail support
- Compatible with Windows PC (11 / 10 / 8.1 / 8 / 7 / Vista and XP) and Mac
If you need to inspect stderr in Java, continuously drain it while copying stdout. A noisy conversion can fill the stderr pipe; if nobody reads it, wkhtmltopdf may block and your stdout copy will appear to hang. Java also offers redirectErrorStream(true), but do not use that setting when stdout is the PDF destination because it combines text diagnostics with binary PDF bytes.
Exit status, partial output, and cancellation
- Copying bytes is not proof of success. Wait for
process.waitFor()and reject every non-zero exit code. - If the caller disconnects, close or stop writing to the destination and terminate the child process according to your server’s cancellation policy.
- For bounded request time, wait with a timeout, then destroy the process and (when necessary) its descendants. A timeout should be reported as a conversion failure, not returned as a PDF.
- Do not publish a partially written stream as a successful document. When possible, write to a temporary buffer or transactional destination and commit only after a zero exit code.
Input forms and wkhtmltopdf options
The normal command-line synopsis accepts an HTML file or URL followed by an output path. For a local file:
wkhtmltopdf input.html -
For a URL:
wkhtmltopdf https://example.com/report -
Build arguments as a list, not one shell-escaped string, so spaces and special characters are passed safely:
List<String> command = List.of(
"/usr/local/bin/wkhtmltopdf",
"--print-media-type",
"--javascript-delay", "500",
"https://example.com/report",
"-"
);
Process process = new ProcessBuilder(command)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();
Switches for JavaScript, cookies, headers, local-file access, page size, margins, orientation, and other rendering behavior are deployment decisions. Add only the switches your installed build supports, and validate untrusted URLs and local-file access before exposing this capability to users.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Rank #3
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- 1 Year License for 1 Windows & 2 Mobile (Android and/or iOS) devices.
When HTML is a string
wkhtmltopdf’s documented command form is file- and URL-oriented. If your input is an HTML string, write it to a controlled temporary file, render that file, and delete it in a finally block. This avoids shell interpolation and gives the converter a concrete input path.
Path html = Files.createTempFile("wkhtmltopdf-", ".html");
try {
Files.writeString(html, htmlContent, StandardCharsets.UTF_8);
WkhtmltopdfExporter.export("wkhtmltopdf", html.toString(), destination);
} finally {
Files.deleteIfExists(html);
}
Set the document’s character encoding explicitly when your content is not UTF-8, and ensure referenced stylesheets, images, and fonts are reachable from the conversion process.
Common failures and fixes
“Cannot run program” or executable not found
The Java process cannot find or execute wkhtmltopdf. Install it in the runtime image, make it executable, or pass its absolute path. A shell account’s PATH is not necessarily the same as the service account’s environment.
The returned file is not a readable PDF
Check that stderr was not merged into stdout. Use redirectError(ProcessBuilder.Redirect.INHERIT) or drain getErrorStream() separately. Also verify that the process exited with code zero.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #4
The method hangs
Unread stderr can block a chatty process. Drain it or inherit it. Network pages, JavaScript, unreachable resources, and waits for external content can also prolong conversion; apply an application timeout and terminate the child on expiry.
Output is blank or missing images
Inspect the source URL from the converter host, resource permissions, relative URL resolution, JavaScript timing, and local-file restrictions. Add a deliberate JavaScript delay only when the page needs it; delays increase latency for every request.
HTTP response has the wrong length
Do not guess a content length for a live stdout stream. Buffer to memory or a temporary file when the framework requires a known length, or allow its chunked streaming mode.
Non-zero exit after some bytes were copied
Treat the result as failed. Preserve stderr in logs, discard the partial destination where possible, and return an error to the caller rather than a corrupt document.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
- Complete Audio/Visual Lessons
- PDF instruction manual (303 pages)
- Introductory through advanced material for version 2022
- Over 7.5 hours of video lessons (190 individual lessons)
- Quiz, Optional Final Exam, Certificate of Completion
OutputStream streaming versus a wrapper
A direct ProcessBuilder integration keeps executable discovery, argument construction, stdout, stderr, exit status, timeouts, and destination ownership visible in your code. The wkhtmltopdf-java project provides a Java wrapper and still requires wkhtmltopdf to be installed. Choose it when its option model and lifecycle fit your application; choose direct process control when observability and precise stream handling matter most.
When to choose a native Java converter
A library such as PDFreactor documents Java APIs that write directly to an OutputStream, which can remove the external executable dependency. Evaluate alternatives on the properties that affect your deployment:
| Decision factor | Question to answer |
|---|---|
| Stream API | Can it write directly to your destination without a temporary file? |
| Rendering | Does its HTML, CSS, and JavaScript behavior match your documents? |
| Deployment | Does it require an executable, native libraries, fonts, or a display service? |
| Licensing | Are its license and per-server or per-developer costs acceptable? |
| Observability | Can you capture structured errors, warnings, and timing? |
| Maintenance | Is the project’s support and release cadence suitable for your risk profile? |
Or skip the browser setup
If your real task is obtaining a clean image or PDF of a web page rather than controlling a local wkhtmltopdf process, ScreenshotNeo provides a single-call screenshot API and an MCP server for AI agents. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing status.
For a screenshot, call the API directly:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Other supported clients:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Its options include full-page and element capture, device and retina settings, PDF paper and margin controls, custom CSS and JavaScript, waits, request blocking, headers, cookies, geolocation, caching, signed links, asynchronous webhooks, bulk capture, and an OpenAPI specification. The MCP tools are take_screenshot, get_page_info, and capture_pdf. One thousand screenshots per month are free with no card; paid plans start at $5 for 3,000. See the ScreenshotNeo documentation, then create a free account.
Practical checklist
- Use
-as the wkhtmltopdf output argument. - Copy
process.getInputStream()to the caller’sOutputStream. - Keep stderr separate and continuously drained or inherited.
- Wait for and validate the exit code.
- Use an absolute executable path in managed deployments.
- Apply timeouts, resource limits, and URL/local-file security controls.
- Buffer only when a byte array or known content length is required.
Frequently Asked Questions
Can wkhtmltopdf write directly to Java’s OutputStream?
wkhtmltopdf writes to stdout when its output argument is -; Java reads that stdout stream and copies it to any destination OutputStream.
Should I close the destination stream in the exporter?
No. The caller owns the destination. Close only the process input stream used to read stdout.
Is a wkhtmltopdf Java wrapper self-contained?
No. The wrapper still requires an installed, executable wkhtmltopdf binary.
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.

