quick_html_pdf 3.1.0
quick_html_pdf: ^3.1.0 copied to clipboard
A fast, high-performance Flutter Web package for converting HTML templates with dynamic data into vector PDFs using a custom measure-and-flow paginator + jsPDF.
Changelog #
3.1.0 #
New #
border-radiussupport in the vector pipeline (PdfOutput.download/PdfOutput.bytes). Previously dropped — flatpdf.rect+ four straightpdf.linecalls ignored CSS rounding. Backgrounds and borders are now emitted via jsPDF'sroundedRectwhen the element has a non-zero radius. Print mode was unaffected and remains unchanged.JsPDF.roundedRect(x, y, w, h, rx, ry, {style})bridged injs_interop.dart.
Scope and limits #
- Only uniform 4-corner radii are honored. If
border-top-left-radius,border-top-right-radius,border-bottom-right-radius, andborder-bottom-left-radiusare not all identical (e.g.border-radius: 6px 0 6px 0), the element renders with sharp corners. A one-time debug log is emitted per distinct non-uniform combination so the consumer can spot it. - Elliptical radii (different rx and ry) are supported when applied uniformly across all four corners.
- Border rounding requires all four sides to share the same width, style, and color. Mixed-side borders fall back to the existing per-side straight-line path (radius is dropped in that case).
- Radii are clamped to
min(w/2, h/2)since jsPDF does not auto-clamp like CSS does.
3.0.0 #
Production-grade vector PDF pipeline. Replaces the v2 raster (html2pdf/html2canvas) bytes path. Three output modes with consistent layout. No CDN at runtime.
Breaking changes #
PdfOutputenum reshape:{ bytes, download }→{ print, download, bytes }.print— opens the browser print dialog (wasdownloadin v2).download— silent file save, no dialog. Uses the vector pipeline.bytes— vector emission, returnsUint8List. v2's html2pdf raster path is gone.
- Default output mode changed from
downloadtoprint(semantics preserved — both default behaviours open the browser print dialog). - Vector modes (
download/bytes) require a registered font. PassPdfOptions.fonts: [PdfFont(...)]. Without registration, generation throwsPdfGenerationException(code: 'no-fonts-registered')rather than silently substituting wrong glyphs (e.g. ₹ → ¹).printmode is unaffected. - No CDN at runtime. jsPDF (~360 KB) is vendored as a Flutter package asset and lazy-loaded on the first vector-mode call. Consumer apps no longer add
<script>tags toweb/index.html. - Deprecated fields:
PdfOptions.scale,PdfOptions.imageQuality,PdfOptions.pageBreakModes(andPageBreakModeenum). Vector pipeline uses CSSpage-break-*directly. Will be removed in v3.1.
New #
CustomPaginator— measure-and-flow paginator written in Dart. ReadsgetBoundingClientRect()deltas off the rendered iframe DOM, slices oversized tables row-by-row (preserving<thead>), handles single-table containers AND multi-table flex-row containers (Form 26AS-style "Sections" panels) with a two-phase pass: half-width slices while both children have content, then full-width tail slices once the shorter sibling exhausts. Replaces the previously-considered Paged.js polyfill — 100–200× faster on table-heavy docs (~1 s vs ~4–5 min on a 200-page tax form).PdfFont— describes a TTF for jsPDF registration. Provide font data via eithersrc(URL —fetch'd at register time) orbytes(rawUint8List, e.g. fromrootBundle.load). Plusfamily,weight,style.- Per-page chrome built by the paginator — header / footer / watermark slots assembled inside each
<div class="qhp-page">wrapper fromPdfOptions.headerHtml,footerHtml,watermarkUrl(andwatermarkSize/watermarkPosition).{{page}},{{pages}},{{date}},{{time}},{{datetime}}substitution is applied per-page. - Walker-level content clip —
DomWalkerhonors theqhp-page-contentslot'soverflow: hiddenso descendants of the content area don't bleed into the footer band even if pagination measurements drift. - Pagination safety buffer — paginator targets
contentHeight − 2 mmso sub-pixel layout drift between source measurement and per-page re-layout doesn't push the last row past the content rectangle. - Fail-loud glyph fallback in non-debug builds.
- Background-image emission in
_emitElementBox(data: URL only in v3.0; network URLs deferred to v3.1). - Width-sanity per-line check in DOM walker — drops down to per-word emission when jsPDF's metrics drift >5% from the browser's.
- Per-word + per-character fallback for high-fidelity text positioning when CSS letter-spacing / font-cascade differences cause drift.
letter-spacingandword-spacingCSS propagated to jsPDF (charSpaceparameter / per-word gap measurement).- New
PdfGenerationPhasevalues:domWalking,vectorEmission. - New
PdfGenerationException.codefield — stable machine-readable codes for telemetry / consumer branching (no-fonts-registered,glyph-fallback,jspdf-bootstrap-failed, etc.).
Migration from v2 #
// v2
await QuickHtmlPdf.generate(
htmlTemplate: tpl,
data: data,
options: PdfOptions(output: PdfOutput.download), // ← was: print dialog
);
// v3 — keep the dialog UX
await QuickHtmlPdf.generate(
htmlTemplate: tpl,
data: data,
options: PdfOptions(output: PdfOutput.print), // explicit
);
// v3 — silent download (new!)
await QuickHtmlPdf.generate(
htmlTemplate: tpl,
data: data,
options: PdfOptions(
output: PdfOutput.download,
filename: 'report.pdf',
fonts: [
PdfFont(family: 'Liberation Sans', src: 'assets/fonts/LiberationSans-Regular.ttf'),
PdfFont(family: 'Liberation Sans', src: 'assets/fonts/LiberationSans-Bold.ttf', weight: 'bold'),
],
),
);
Bundled JS versions #
- jsPDF:
2.5.1
2.0.1 #
Bug Fixes #
-
Fixed NativeByteBuffer to Uint8List conversion error
jsPDF.output('arraybuffer')returns JavaScriptArrayBuffer, notUint8Array- Fixed conversion:
JSArrayBuffer→ByteBuffer→Uint8Listusing.toDart.asUint8List() - Resolved
TypeError: type 'NativeByteBuffer' is not a subtype of type 'NativeUint8List'
-
Fixed Unicode/Hindi text not rendering in headers and footers
- Previous implementation used
pdf.text()which relies on jsPDF's built-in fonts (Helvetica, Times, Courier) without Unicode support - Now renders headers/footers using html2canvas (same as main content)
- Browser's font rendering engine properly handles Hindi, Chinese, Arabic, and all Unicode characters
- Added 'Noto Sans Devanagari' to default font stack for Hindi support
- Previous implementation used
Improvements #
- Headers and footers now use the same rendering pipeline as main content for consistent output
- Temporary DOM elements used for header/footer rendering are properly cleaned up
2.0.0 #
New Features #
-
Intelligent Page Breaks for Bytes Mode
- Integrated html2pdf.js for smart content splitting
- Respects CSS
page-break-inside: avoidon elements - Respects CSS
page-break-before: alwaysandpage-break-after: always - Respects
orphansandwidowsCSS properties - Finds natural break points between block elements
- Falls back to legacy html2canvas + jsPDF if html2pdf.js is not available
- Configurable
pageBreakModesoption:css,avoidAll,legacy
-
Headers/Footers with Dynamic Page Numbers
{{page}}placeholder replaced with current page number (1, 2, 3...){{pages}}placeholder replaced with total page count{{date}}placeholder for current date{{time}}placeholder for current time{{datetime}}placeholder for date and time- Headers/footers render on every page at consistent positions
- Configurable
headerHeightMmandfooterHeightMm - Configurable
headerFontSizeandfooterFontSize - Optional separator lines with
showHeaderLineandshowFooterLine - Content area automatically adjusted for header/footer space
Breaking Changes #
- Bytes mode now requires html2pdf.js for intelligent page breaks (recommended)
- Update your
web/index.htmlto use the new script:<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
Improvements #
- Added utility CSS classes:
.page-break-before,.keep-with-next - Cards, sections, and invoice items now have
page-break-inside: avoidby default - Better orphan/widow handling for paragraphs and list items
1.0.2 #
- Add repository metadata
1.0.1 #
- Documentation improvements
1.0.0 #
Initial release of QuickHtmlPdf - a fast HTML to PDF conversion package for Flutter Web.
Features #
-
Hybrid PDF Generation Strategy
PdfOutput.download: Instant PDF via native browser print (~50ms)PdfOutput.bytes: Returns PDF asUint8Listusing html2canvas + jsPDF
-
Template Engine
{{key}}- HTML-escaped interpolation{{nested.path}}- Dot notation for nested objects{{{rawHtml}}}- Unescaped HTML insertion{{#each items}}...{{/each}}- Loop blocks{{@index}},{{@index1}}- Loop index variables
-
PDF Options
- Page formats: A4, Letter, Legal
- Orientations: Portrait, Landscape
- Custom margins
- Custom header and footer HTML
- Configurable scale and image quality
-
Print CSS
- Automatic
@pagerules for correct sizing - Table header repetition across pages
- Page break utilities (
.page-break,.no-break)
- Automatic
-
Large Document Support
- Chunked rendering for 200+ page documents
- Memory-efficient sequential page processing
-
Developer Experience
- Debug mode with timing logs
- Clear error messages with phase information
UnsupportedErroron non-web platforms