PC 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 & 11Outdated 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 matchSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
In Grails, the Rendering Plugin converts a GSP that outputs well-formed XHTML into a PDF. Use pdfRenderingService.render(...) when your application needs PDF bytes or an output stream; use the controller’s renderPdf(...) method when the browser should download the generated document.
The plugin reference reviewed for this guide is version 1.0.0 and does not publish a compatibility matrix for current Grails releases. Confirm the dependency coordinates and supported Grails version for your application before deploying.
Choose the output path
Both documented APIs render a GSP template through the XHTML Renderer library. The choice is determined by where the result must go.
Recommended Free Tools
| Need | Use | What you receive |
|---|---|---|
| Store, email, post-process, or test the PDF in application code | pdfRenderingService.render |
Generated bytes by default, or data written to an OutputStream |
| Return a download from a Grails controller | renderPdf |
An HTTP PDF response, with filename and content type options |
The service API accepts a map containing a required template and optional model, plugin, and controller. A template name maps to a GSP partial, so report normally means a file named _report.gsp.
#1 Best Overall
Check version and application prerequisites
Verify the plugin pairing
The reference documentation identifies the Grails Rendering Plugin as version 1.0.0. The Apache Grails documentation landing page lists framework documentation for Grails 7.2.4, 7.1.7, and 7.0.17, but the reviewed pages do not state that plugin 1.0.0 supports any of those releases. Check your build’s dependency metadata, the plugin release information, and your Grails version together; do not assume that a framework upgrade preserves rendering compatibility.
Reference links: Grails Rendering Plugin reference documentation and Apache Grails documentation.
Prepare the template inputs
- Put the report view under the application’s views directory, for example
grails-app/views/pdfs/_report.gsp. - Make the GSP produce valid, well-formed XHTML, not merely forgiving browser HTML.
- Declare an XHTML doctype. Without one, entities such as
can fail to resolve. - Ensure every stylesheet and image can be fetched by the server-side renderer.
Create a PDF GSP that the renderer can parse
A minimal report template can look like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>${report.title}</title>
<style type="text/css">
@page { size: 210mm 297mm; margin: 18mm; }
body { font-family: sans-serif; font-size: 11pt; color: #222; }
h1 { font-size: 20pt; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 0.2mm solid #999; padding: 2mm; }
</style>
</head>
<body>
<h1>${report.title}</h1>
<p>Prepared for ${report.customerName}</p>
<table>
<tr><th>Item</th><th>Amount</th></tr>
<g:each in="${report.items}" var="item">
<tr>
<td>${item.description}</td>
<td>${item.amount}</td>
</tr>
</g:each>
</table>
</body>
</html>
The @page rule illustrates the documented way to set an A4-sized page (210 mm by 297 mm). Add print-specific CSS deliberately; browser-only features and malformed markup may not be understood by the XHTML renderer.
Free tools Windows power users keep installed
One-click scans. No signup required.
Render PDF bytes in a service or other application code
Call the service when another part of the application needs the generated document:
class ReportPdfService {
def pdfRenderingService
byte[] createReportPdf(report) {
pdfRenderingService.render(
template: '/pdfs/report',
model: [report: report]
)
}
}
With no second argument, render returns output from a new ByteArrayOutputStream. To write directly to a destination you control, provide an output stream:
def writeReportPdf(report, OutputStream destination) {
pdfRenderingService.render(
template: '/pdfs/report',
model: [report: report]
, destination
)
}
In normal Groovy style, pass the stream as the method’s second argument rather than as another map entry:
pdfRenderingService.render(
[template: '/pdfs/report', model: [report: report]],
destination
)
A relative template path is resolved from the controller’s views directory and therefore needs controller context. A path beginning with /, such as /pdfs/report, resolves from the application’s views directory.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Return a downloadable PDF from a controller
For a browser download, let the controller supply request context and response headers:
class ReportController {
def download() {
def report = reportService.find(params.id)
if (!report) {
render status: 404, text: 'Report not found'
return
}
renderPdf(
template: '/pdfs/report',
model: [report: report],
filename: report.name
)
}
}
filename sets the Content-Disposition attachment name. The documented default content type is application/pdf; specify contentType when your response policy requires it:
renderPdf(
template: '/pdfs/report',
model: [report: report],
filename: 'invoice.pdf',
contentType: 'application/pdf'
)
Use a filename ending in .pdf and sanitize any user-controlled name before passing it to a response header.
Make images, CSS, and fonts reachable
Images and stylesheets
The renderer, not the end user’s browser, resolves linked resources. The application must be able to serve every image and stylesheet referenced by the GSP. Relative URLs are resolved against grails.serverURL, so configure that value for the environment in which PDFs are generated. A path that works in a browser but points to a private, incorrect, or unreachable host from the server will produce a missing asset in the PDF.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →When an image is available only as bytes, the plugin documents the rendering:inlinePng, inlineGif, and inlineJpeg tags. These generate data-URI-backed image tags and avoid a separate resource request.
Rank #3
Characters and embedded fonts
If glyphs do not render through the underlying iText setup, define an embedded font and its encoding in CSS with @font-face, using the renderer-specific -fs-pdf-font-embed and -fs-pdf-font-encoding properties. Test the actual character set used by names, currencies, and customer data rather than relying on a Latin-only sample.
Performance, buffering, and caching
PDF generation can be expensive because the template is parsed and laid out server-side. The reference describes two cacheable stages: the intermediate DOM Document and the final output bytes. Cache only when the inputs, permissions, locale, and data freshness make reuse safe; a cached PDF can otherwise expose stale or unauthorized information.
When writing a response, output is first buffered so the framework can calculate Content-Length. Supplying a destination stream can avoid that extra copy, but if you bypass buffering you must set Content-Length yourself when your HTTP infrastructure requires it. Measure memory usage for large reports and avoid constructing multiple byte arrays unnecessarily.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute- Keep report queries bounded and paginate or summarize large datasets before rendering.
- Reuse a parsed DOM only when the template and all variable content are handled safely.
- Use deterministic asset URLs and immutable versioned CSS when caching rendered documents.
- Exercise concurrent generation in a staging environment; renderer and font resources are shared server costs even when the request code is small.
Troubleshooting common failures
XmlParseException or malformed-document errors
Cause: the GSP emits invalid XHTML, an unclosed element, or an entity the parser does not know. Fix: add the XHTML doctype, close every element, quote attributes, escape ampersands, and replace unsupported entities such as with valid numeric or supported references.
The template cannot be found
Cause: the path does not match the underscore-prefixed GSP filename or is relative without controller context. Fix: store _report.gsp under the expected views directory and call it as /pdfs/report, or provide the controller context required by a relative path.
Images or CSS are missing
Cause: the renderer cannot reach the URL, or a relative URL resolves against the wrong grails.serverURL. Fix: use an application-reachable absolute URL, correct the server URL for the running environment, check authentication requirements, and verify the resource response from the Grails host itself.
Text appears as boxes or the wrong symbols
Cause: the selected font lacks the glyphs or was not embedded and encoded for PDF output. Fix: configure @font-face with the documented -fs-pdf-font-embed and -fs-pdf-font-encoding properties, then regenerate with representative text.
The download has the wrong name or opens as text
Cause: the controller did not set a filename or content type. Fix: pass filename: 'report.pdf' to renderPdf and use contentType: 'application/pdf' when overriding defaults.
Generation is slow or memory-heavy
Cause: large DOMs, high-resolution images, repeated rendering, or unnecessary byte copies. Fix: reduce input size, cache safe intermediate or final results, stream to a destination where appropriate, and profile concurrent requests before increasing worker counts.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.When a browser-based capture is the better fit
This plugin is a server-side GSP-to-PDF renderer. If the requirement is instead a snapshot of an already deployed page—including modern browser layout, JavaScript, or a public URL—use a browser capture service rather than rewriting that page as XHTML.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and each response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers. It can return PNG, JPEG, WebP, or PDF and supports full-page capture, CSS-selector elements, device and viewport settings, JavaScript, custom headers and cookies, waiting rules, resource blocking, PDF page controls, signed links, asynchronous webhooks, bulk capture, and an MCP server for Claude, Cursor, or another MCP client.
One GET request is enough:
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 the URL and output options. The same request in Python is:
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 data = Buffer.from(await res.arrayBuffer());
The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots, and every feature is included on every plan. Create a free ScreenshotNeo account.
Best Value
FAQ
Does this plugin render arbitrary modern HTML from a URL?
No. Its documented input is a Grails GSP that produces well-formed XHTML. A deployed-page capture service is a different workflow.
Which API should a batch job use?
Use pdfRenderingService.render with an output stream or stored bytes when the job owns delivery or storage. Use renderPdf only when a controller request should produce the HTTP response.
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 →Where should compatibility be confirmed?
Check the plugin’s versioned reference, your build’s resolved dependency metadata, and the Apache Grails release documentation together; the reviewed plugin guide does not provide a matrix for the listed Grails releases.
Frequently Asked Questions
Does this plugin render arbitrary modern HTML from a URL?
No. Its documented input is a Grails GSP that produces well-formed XHTML. A deployed-page capture service is a different workflow.
Which API should a batch job use?
Use pdfRenderingService.render with an output stream or stored bytes when the job owns delivery or storage. Use renderPdf only when a controller request should produce the HTTP response.
Where should compatibility be confirmed?
Check the plugin’s versioned reference, your build’s resolved dependency metadata, and the Apache Grails release documentation together; the reviewed plugin guide does not provide a matrix for the listed Grails releases.
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.

