webcontent_converter
This plugin was made for developer to convert any webcontent, web uri to image bitmap or pdf file. It uses each platform's native webview directly: WebView on Android, WKWebView on iOS/macOS, and WebView2 on Windows. On Web it renders through html2canvas/html2pdf.js in the browser instead (see Web setup below). No bundled/downloaded Chrome or Puppeteer is required on any platform.
Support
| Android | iOS | macOS | Windows | Web |
|---|---|---|---|---|
| WebView | WKWebView | WKWebView | WebView2 | html2canvas / html2pdf.js |
- Android minimum SDK version: 21
- iOS minimum deployment target: 13.0
- macOS minimum deployment target: 10.15
- Windows: requires the WebView2 Runtime on the end-user's machine. It ships with modern Windows 10/11 via Edge, but isn't guaranteed on Windows Server or locked-down/LTSC images.
- Dart SDK
>=3.9.2 <4.0.0, Flutter>=3.0.0(seepubspec.yaml)
Installation
dependencies:
webcontent_converter: ^0.0.11
flutter pub get
Platform setup
Android
No manifest changes needed for contentToImage/contentToPDF (local HTML string content). If you use webUriToImage/webUriToPdf to fetch a remote URL, make sure your app declares network access in its release manifest (android/app/src/main/AndroidManifest.xml) -- it isn't added for you:
<uses-permission android:name="android.permission.INTERNET"/>
iOS / macOS
WKWebView's default App Transport Security policy blocks plain http:// loads. If you pass an http:// (not https://) URL to webUriToImage/webUriToPdf, add an ATS exception to your app's Info.plist (ios/Runner/Info.plist, macos/Runner/Info.plist) -- ideally scoped to your specific domain, or broadly for local development:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
If you distribute a sandboxed macOS app (e.g. via the Mac App Store), keep com.apple.security.app-sandbox enabled in your entitlements and make sure com.apple.security.network.client is true -- WKWebView needs it to reach remote URLs from inside the sandbox.
Windows
No extra project setup, but see the WebView2 Runtime requirement noted under Support above -- it's expected to already be present on the machine running your app.
Web
Run this once after adding the dependency:
flutter pub run webcontent_converter:install_web
This injects the html2canvas/html2pdf.js/jspdf script tags this platform's implementation depends on into web/index.html. Without it, ensureInitialized() fails its debug-mode assertion, and contentToImage/contentToPDF fail outright since those scripts won't be defined.
Methods
Convert to image
static Future<Uint8List> contentToImage({
required String content,
double duration = 2000,
int scale = 3,
Map<String, dynamic> args = const {},
bool enableLogger = true,
})
filePathToImage({required String path, ...}) and webUriToImage({required String uri, ...}) take the same duration/scale/args/enableLogger parameters, read their HTML from an asset path or a remote URL respectively, then call contentToImage under the hood.
duration-- milliseconds to wait for the page to finish loading/rendering before capturing.scale-- capture scale factor (mobile/web paths).
Basic example:
final content = Demo.getReceiptContent();
final bytes = await WebcontentConverter.contentToImage(content: content);
if (bytes.isNotEmpty) _saveFile(bytes);

contentToImage also accepts a format (and optional margins) through args, which routes it through each platform's PDF-page rasterizer instead of a plain screenshot -- useful for producing a paginated, print-accurate bitmap (e.g. for a receipt/invoice at a specific paper size) rather than a screenshot sized to the page's natural content:
final bytes = await WebcontentConverter.contentToImage(
content: Demo.getInvoiceContent(),
args: {
'format': {
'width': PaperFormat.letter.width,
'height': PaperFormat.letter.height,
'name': PaperFormat.letter.name,
},
'margins': {'top': 0.25, 'bottom': 0.25, 'left': 0.25, 'right': 0.25},
},
);
Note: each platform rasterizes this path through a different native renderer, so the exact output pixel size per page isn't identical across Android/iOS/macOS/Windows (see example/integration_test/webcontent_converter_test.dart for the verified per-platform pixel formulas if you need to reason about exact dimensions).
*** Purpose: get a screenshot of html content as a Uint8List PNG/JPEG, e.g. to push to an ESC/POS receipt printer.
Convert to PDF
static Future<String?> contentToPDF({
required String content,
double duration = 2000,
required String savedPath,
PdfMargins? margins,
PaperFormat format = PaperFormat.a4,
Map<String, dynamic> args = const {},
bool enableLogger = true,
})
filePathToPdf/webUriToPdf mirror this with path/uri in place of content. All three write the PDF to savedPath and return that path on success (null on failure).
final content = Demo.getInvoiceContent();
final dir = await getApplicationDocumentsDirectory();
final savedPath = join(dir.path, "sample.pdf");
final result = await WebcontentConverter.contentToPDF(
content: content,
savedPath: savedPath,
format: PaperFormat.a4,
margins: PdfMargins.px(top: 55, bottom: 55, right: 55, left: 55),
);
contentToPDFImage({required String content, double duration = 2000, PdfMargins? margins, PaperFormat format = PaperFormat.a4, Map<String, dynamic> args = const {}, bool enableLogger = true}) returns Future<Uint8List?> -- the same PDF generation as contentToPDF, but returned as raw bytes (via a temp file under the hood) instead of a saved path, for when you want the PDF in memory:
final bytes = await WebcontentConverter.contentToPDFImage(
content: Demo.getInvoiceContent(),
format: PaperFormat.a4,
);
*** Purpose: produce a real, paginated PDF file (or its bytes) of html content, e.g. for an invoice.
Print preview
static Future<bool> printPreview({
String? url,
String? content,
bool autoClose = true,
double? duration,
PdfMargins? margins,
PaperFormat format = PaperFormat.a4,
Map<String, dynamic> args = const {},
})
Opens the platform's native print UI: a WebView2/WKWebView-backed preview window on Windows/macOS, the OS print sheet on Android/iOS, and a window.print() popup on Web.
Utilities
isWebviewAvailable()--Future<bool>, whether this platform's native webview (WebView2/WKWebView/android.webkit.WebView) is actually usable right now. Alwaystrueon Web.embedWebView({String? url, String? content, double? width, double? height, Map<String, dynamic> args})-- aWidgetthat embeds the content/url directly in your widget tree.ensureInitialized({String? content})-- warms up the native webview once (skips if already done); call it early (e.g. at app start) to avoid a cold-start delay on the first real conversion.
PaperFormat & PdfMargins
PaperFormat (lib/page.dart) has named presets in inches -- .a0-.a6, .letter, .legal, .tabloid, .ledger -- plus PaperFormat.px(width:, height:), .cm(...), .mm(...), and .inches(...) constructors if you need a custom size.
PdfMargins mirrors this: PdfMargins.zero, or PdfMargins.px(top:, bottom:, left:, right:) / .cm(...) / .mm(...) / .inches(...).
Desktop (Windows/macOS)
Windows and macOS work through WebView2/WKWebView -- there's no Chrome/Chromium to download or bundle. Just call ensureInitialized() (or any convert method) directly:
await WebcontentConverter.ensureInitialized();
Older versions of this plugin (pre-0.0.11) shipped a Puppeteer-based fallback for desktop that required downloading a Chrome binary via
flutter pub run webcontent_converter:install_desktopand pointingWebViewHelper.customBrowserPathat it. That code path has no effect on the current nativeWebView2/WKWebViewimplementation and should no longer be used.