html_to_markdown_ffi 1.1.0
html_to_markdown_ffi: ^1.1.0 copied to clipboard
A high-performance HTML to Markdown converter for Dart and Flutter, powered by Rust FFI.
html_to_markdown #
High-performance HTML to Markdown converter for Dart and Flutter, powered by the Rust html-to-markdown engine via FFI bindings. 150-280 MB/s throughput — 10-80x faster than pure Dart alternatives.
Features #
- Blazing fast: Rust-powered conversion engine via FFI
- Byte-identical output: Matches the Rust core exactly for all input
- Full metadata extraction: Title, description, author, keywords, OpenGraph, JSON-LD
- Comprehensive options: 40+ conversion settings (heading style, code blocks, links, whitespace, etc.)
- Visitor pattern: Customize element-level conversion behavior
- Cross-platform: Android, iOS, macOS, Linux, Windows
Installation #
dart pub add html_to_markdown
Quick Start #
import 'package:html_to_markdown/html_to_markdown.dart';
void main() {
final html = '<h1>Hello World</h1><p>This is a <strong>test</strong>.</p>';
// Basic conversion
final result = convert(html);
print(result.content);
// # Hello World
//
// This is a **test**.
}
Configuration #
final options = ConversionOptions()
..headingStyle = HeadingStyle.setext
..linkStyle = LinkStyle.referenced
..extractMetadata = true
..wrap = true
..wrapWidth = 80;
final result = convert(html, options: options);
Metadata Extraction #
final options = ConversionOptions()..extractMetadata = true;
final result = convert(htmlWithMeta, options: options);
print(result.metadata?.title); // Page title
print(result.metadata?.description); // Meta description
print(result.metadata?.author); // Author
print(result.metadata?.keywords); // Keywords list
Custom Visitor #
class ScriptStripper extends Visitor {
@override
VisitResult visitElementStart(NodeContext ctx) {
if (ctx.tagName == 'script' || ctx.tagName == 'style') {
return VisitResult.skip;
}
return VisitResult.continue_;
}
}
final result = convert(html, visitor: ScriptStripper());
Platform Support #
| Platform | Arch | Status |
|---|---|---|
| macOS | arm64, x64 | ✓ (binary bundled) |
| iOS (device) | arm64 | ✓ (static lib bundled) |
| iOS Simulator | arm64, x64 | ✓ (static lib bundled) |
| Android | arm64-v8a, armeabi-v7a, x86_64 | ✓ (.so bundled) |
| Linux | arm64, x64 | ✓ (build from source) |
| Windows | x64 | ✓ (build from source) |
| Web | — | Not supported (use WASM binding) |
Native libraries #
Prebuilt native binaries are shipped inside the package under native/, so
the library is already there when the package is installed — no download step
or manual toolchain setup is needed on the supported platforms:
native/
├── include/html_to_markdown.h # C header (for custom integration)
├── macos-x64/libhtml_to_markdown_ffi.dylib
├── macos-arm64/libhtml_to_markdown_ffi.dylib
├── ios/
│ ├── ios-arm64.a # device
│ ├── ios-sim-arm64.a # Apple Silicon simulator
│ └── ios-sim-x64.a # Intel simulator
└── android/
├── arm64-v8a/libhtml_to_markdown_ffi.so
├── armeabi-v7a/libhtml_to_markdown_ffi.so
└── x86_64/libhtml_to_markdown_ffi.so
-
macOS — the correct dylib for the host architecture is loaded automatically from the package directory. Nothing to do.
-
Android — copy the
.sofile(s) you need into your app's jniLibs; the loader resolveslibhtml_to_markdown_ffi.sofrom the Android loader path:cp native/android/arm64-v8a/libhtml_to_markdown_ffi.so \ <your-app>/android/app/src/main/jniLibs/arm64-v8a/ cp native/android/armeabi-v7a/libhtml_to_markdown_ffi.so \ <your-app>/android/app/src/main/jniLibs/armeabi-v7a/ cp native/android/x86_64/libhtml_to_markdown_ffi.so \ <your-app>/android/app/src/main/jniLibs/x86_64/ -
iOS — iOS uses a static library linked into the app at build time (not dlopen'd). Add the
.afor your target to the Runner (e.g.ios/Runner/ Frameworks+ the Xcode "Link Binary With Libraries" build phase); the loader then finds the symbols viaDynamicLibrary.process():- device:
native/ios/ios-arm64.a - Apple Silicon simulator:
native/ios/ios-sim-arm64.a - Intel simulator:
native/ios/ios-sim-x64.a
- device:
Native library resolution order #
NativeLibrary tries, in order:
HTML_TO_MARKDOWN_FFI_LIB_PATHenv var (testing / custom paths)- Bundled binary —
native/<rid>/libhtml_to_markdown_ffi.*shipped inside the package (macOS arm64/x64) ~/.html_to_markdown_ffi/cache (populated bydownloadIfNeeded())- A checked-out Cargo workspace's
target/release/(development) - Platform default name (
DynamicLibrary.open(libName)— Android jniLibs) DynamicLibrary.process()/executable()(iOS static link)
NativeLibrary.downloadIfNeeded() short-circuits when a bundled binary is
present and is otherwise only needed on platforms without bundled artifacts
(Linux, Windows).
API Reference #
Functions #
convert(String html, {ConversionOptions? options, Visitor? visitor}) → ConversionResult
Classes #
ConversionOptions— 40+ configuration fieldsConversionResult— Output with content, metadata, tables, images, warningsHtmlMetadata— Extracted page metadataVisitor— Abstract class with 38 element-level callbacksNodeContext— Context passed to visitor callbacks
Enums #
HeadingStyle, LinkStyle, CodeBlockStyle, WhitespaceMode, OutputFormat,
NewlineStyle, HighlightStyle, ListIndentType, PreprocessingPreset,
VisitResult, NodeType, WarningKind
Exceptions #
HtmlToMarkdownException, InvalidInputException, ConversionErrorException
Development #
Prebuilt binaries for the supported platforms ship with the package
(native/), so tests and examples run out of the box. To rebuild the native
library (libhtml_to_markdown_ffi) from source instead, use the Rust repo:
git clone https://github.com/arrrrny/html-to-markdown.git
cd html-to-markdown/crates/html-to-markdown-ffi
cargo build --release
Run tests #
dart pub get dart test
Related #
- Rust core
- kreuzberg — Document intelligence framework
- All language bindings