Recommended Free Tools
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
With iText pdfHTML, put the CSS text inside a <style> element in the HTML string, then pass that string and an output stream to HtmlConverter.convertToPdf. If the HTML refers to files by relative URL—such as a stylesheet, image, or font—also configure a base URI so the converter can find them. This works for CSS you build at runtime; it does not make pdfHTML a full browser, so check its supported CSS features when a layout depends on browser-specific behavior.
Embed the CSS string in the HTML string
For a self-contained document, assemble the HTML with a <style> element in the document head. The official pdfHTML tutorial demonstrates conversion from an HTML String, and the HtmlConverter API documents an overload that writes HTML supplied as a string to an OutputStream. No temporary CSS file is needed.
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class HtmlStringToPdf {
public static void main(String[] args) throws Exception {
String css = "body { font-family: sans-serif; color: #222; }"
+ ".invoice { width: 100%; }";
String html = "<!doctype html>"
+ "<html><head><meta charset="UTF-8">"
+ "<style>" + css + "</style></head>"
+ "<body><div class="invoice">Invoice</div>"
+ "</body></html>";
try (OutputStream out = Files.newOutputStream(Paths.get("out.pdf"))) {
HtmlConverter.convertToPdf(html, out);
}
}
}
The example writes out.pdf in the process’s working directory. The try-with-resources block closes the stream even if conversion throws an exception. In a web application, write to the response’s output stream or an application-managed stream instead, following that framework’s rules for response headers and stream ownership.
Keep generated CSS syntactically safe
Concatenating fixed CSS literals is simple, but if a declaration includes user-provided data, validate or escape it for the specific CSS context before inserting it. HTML escaping and CSS escaping are not interchangeable. Do not let untrusted input inject arbitrary markup or style rules into the generated document. For larger templates, use a template mechanism or a well-defined stylesheet builder rather than assembling many fragments without checking the final output.
Use a configured converter when needed
The two-argument overload is convenient when the HTML and all its resources are self-contained or use absolute URLs. The configured overload accepts ConverterProperties; set a base URI there when the document contains relative references.
Resolve relative stylesheets, images, and fonts
A relative URL such as images/logo.png is meaningful only relative to some location. A string passed to the converter does not tell it which directory your template came from. The iText tutorial explicitly calls out this issue and shows setting a base URI with ConverterProperties.setBaseUri.
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
String html = "<html><head>"
+ "<link rel="stylesheet" href="css/invoice.css">"
+ "</head><body>"
+ "<img src="images/logo.png" alt="Company">"
+ "<p>Invoice</p></body></html>";
String baseUri = Path.of("/srv/app/templates").toUri().toString();
ConverterProperties properties = new ConverterProperties()
.setBaseUri(baseUri);
try (OutputStream out = Files.newOutputStream(Path.of("out.pdf"))) {
HtmlConverter.convertToPdf(html, out, properties);
}
With this base URI, the relative references are resolved against the template directory: the stylesheet points to /srv/app/templates/css/invoice.css and the image to /srv/app/templates/images/logo.png. Choose a base URI that matches where the referenced resources actually live. A filesystem URI is appropriate for local assets; if resources are hosted elsewhere, use an appropriate resolvable URL instead. Keep resource access restricted to locations your application is intended to read.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC 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
Inline CSS and linked CSS can coexist
Use the embedded <style> approach for dynamically generated rules or a small, self-contained document. A linked stylesheet can be easier to maintain when templates share a substantial set of styles. You can also include both: a linked stylesheet for common rules and an inline style block for document-specific rules. The base URI is still needed for relative links and other relative resources.
Choose the rendering approach for the HTML you have
Embedding CSS solves how the converter receives stylesheet text; it does not guarantee that every browser layout will render the same way in a PDF. pdfHTML has a documented HTML and CSS feature subset. Its feature matrix lists supported paged-media rules and common HTML elements, and also marks some browser-oriented features as unsupported or partial, including scripts, animations and transitions, CSS custom properties, and several modern layout features. Check the matrix for the particular properties and selectors your template uses rather than assuming browser parity.
- For controlled reports and invoices: keep the markup well-formed, use straightforward layout rules, and test representative long and short documents.
- For print-oriented documents: review the supported paged-media rules in the feature matrix and verify page breaks, margins, and repeated content in the generated PDF.
- For JavaScript-driven pages or browser-specific layout: do not assume those behaviors will execute or match a browser in pdfHTML; simplify the template or choose a rendering engine whose documented capabilities fit the requirement.
OpenHTMLToPDF is another pure-Java option. Its project describes a renderer for a reasonable subset of well-formed XML/XHTML and some HTML5, using CSS 2.1 and later to produce PDFs or images. It cautions that modern HTML5 should be specially crafted for its engine. Treat that as a distinct rendering model, not as a drop-in guarantee of browser behavior; test your actual template with the candidate engine.
Set up the dependency and check the license
iText’s installation guidance documents the Maven artifact com.itextpdf:html2pdf. Add it using the version and dependency management appropriate to your project, then verify that the iText Core and pdfHTML versions are compatible. The version is intentionally not hard-coded here because the referenced installation guidance, rather than this example, should be consulted for the current release.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Licensing is a deployment requirement, not just a build detail. iText’s installation page says AGPL licensing applies to non-commercial use and commercial use requires a commercial license. Confirm the current terms for your use case and distribution model before release; do not infer that a dependency’s availability from Maven makes every use permitted.
Troubleshoot missing assets and unexpected layout
The stylesheet or image is missing
Likely cause: the HTML contains a relative URL, but no base URI tells the converter where it should start resolving that path. Fix: use the three-argument conversion overload and set the base URI to the directory or URL that makes the relative reference valid. Check spelling, capitalization, and the actual deployment path as well.
Rank #4
The PDF is created but looks unstyled
Likely cause: the CSS string was not inserted into a valid <style> element, the generated HTML is malformed, a linked stylesheet could not be resolved, or a required CSS feature is outside pdfHTML’s supported subset. Fix: inspect the final HTML string, verify the resource base, and compare the rules used by the template with the feature matrix. Start with a minimal document and add styles back until the difference is clear.
A font is missing or substituted
Likely cause: the font is referenced by a relative URL that cannot be resolved, or the font/resource is not available to the converter in the deployed environment. Fix: make the font resource reachable from the configured base URI, and verify the generated PDF in the same environment where the application runs. A path that works on a developer workstation may not exist in a container or production host.
Browser effects or modern layout rules do not appear
Likely cause: the HTML-to-PDF engine does not implement the browser feature the template depends on. The documented pdfHTML matrix identifies scripts and some CSS modules as unsupported or partial. Fix: replace the dependency with static markup or supported CSS where practical, or evaluate an alternative renderer against the exact document and requirements.
Best Value
The output stream or destination fails
Likely cause: the application cannot create or write the target file, or the stream is already closed or managed elsewhere. Fix: check the destination directory and permissions, use a valid output stream, and keep ownership clear. The example owns and closes its file stream; an application-managed response stream may have different lifecycle rules.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your HTML is already published at a URL and your goal is a screenshot or a PDF capture of the rendered page, rather than conversion of an in-memory HTML/CSS string into a conventional paginated document, ScreenshotNeo is a website screenshot API and MCP server. It is not a replacement for the Java pdfHTML call above: it captures a page by URL, so it does not accept the Java string in this example. A single request looks like this:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. ScreenshotNeo can accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and whether the request was billed. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots a month without a card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month with no card.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteDecide between embedded CSS, a base URI, and another renderer
Use a style block inside the HTML string when the stylesheet is generated in Java and the document is otherwise self-contained. Add a base URI when any relative stylesheet, image, or font must be resolved. If the layout relies on browser features, inspect the engine’s documented support and test the output before committing to it. For an accessible, paginated PDF made from an in-memory string, the direct pdfHTML conversion path remains the one shown above; URL-based screenshot capture serves a different need.
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.

