pdf_text_shaper 1.0.0
pdf_text_shaper: ^1.0.0 copied to clipboard
HarfBuzz-powered complex-script text shaping for the Dart pdf package, with Unicode-preserving PDF output.
any_pdf_fixer #
HarfBuzz-powered complex-script text shaping for Dart's pdf package.
any_pdf_fixer is for text that cannot be rendered correctly by simple Unicode-codepoint-to-glyph mapping: Bengali, Devanagari, Tamil, Telugu, Malayalam, Kannada, Gujarati, Gurmukhi, Arabic, Hebrew, Thai, Khmer, Myanmar, Sinhala, Tibetan, and other scripts supported by HarfBuzz and by the font you provide.
Why #
Complex scripts need OpenType shaping. Conjunct substitution, mark positioning, matra reordering, ligatures, and contextual forms depend on GSUB/GPOS data inside the font.
This package:
- shapes Unicode with HarfBuzz;
- renders the shaped glyph outlines into
package:pdf; - supports font fallback;
- preserves line breaks and wraps text;
- can add an invisible Unicode layer for PDF search/copy;
- does not convert text into legacy ANSI encodings;
- does not bundle or redistribute fonts.
Supported platforms #
| Platform | Support |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| Linux | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Web | ❌ currently |
The native backend uses harfbuzz_ffi. Web is intentionally not advertised until a WASM/native shaping backend is available.
Installation #
dependencies:
any_pdf_fixer: ^0.1.0
pdf: ^3.13.0
The package requires Dart 3.13 or newer.
Basic usage #
final bytes = await File('/path/to/NotoSansBengali.ttf').readAsBytes();
final font = AnyPdfFont.fromBytes(bytes, name: 'Bengali');
final document = pw.Document();
document.addPage(
pw.Page(
build: (_) => ShapedText(
'আমি বাংলায় লিখছি।',
style: AnyPdfTextStyle(
font: font,
fontSize: 18,
),
),
),
);
final pdfBytes = await document.save();
font.dispose();
Use a Unicode OpenType TTF/OTF whose license permits your intended use and whose glyph coverage includes the text you render.
Mixed scripts and fallback fonts #
final style = AnyPdfTextStyle(
font: latinFont,
fallbackFonts: [
bengaliFont,
devanagariFont,
tamilFont,
arabicFont,
],
fontSize: 16,
);
final widget = ShapedText(
'Invoice ১২৩ • हिन्दी • தமிழ் • العربية',
style: style,
);
The renderer selects a font per Unicode run and lets HarfBuzz infer shaping properties.
Searchable/copyable text #
preserveUnicodeText defaults to true.
The visible text is drawn from shaped glyph outlines. A second invisible Unicode text layer is emitted with the matching source text and font. This is designed to retain useful PDF search/copy semantics while avoiding the visual corruption caused by unshaped PDF text.
AnyPdfTextStyle(
font: font,
preserveUnicodeText: true,
)
Set it to false when you only need visual output or when PDF size/text extraction behavior matters more than selection.
Font diagnostics #
final diagnostics = AnyPdfFontDiagnostics(font);
print(diagnostics.report('বাংলা'));
Current limitations #
- Web is not supported by the native HarfBuzz backend.
- Mixed bidirectional paragraphs use script-run direction handling, not a complete Unicode Bidirectional Algorithm implementation yet. Pure RTL runs work; very complex nested LTR/RTL text should be tested.
- Glyphs are rendered as PDF vector paths. This favors correctness and independence from
pdf's text shaper, but can create larger files than native subset-text rendering. - Color emoji/color-font painting is not implemented.
- Vertical text is not implemented.
- The invisible Unicode layer is a pragmatic text-extraction bridge, not a custom CID/ToUnicode shaper.
Resource lifetime #
AnyPdfFont owns native HarfBuzz resources. Reuse a font for the whole PDF generation session and dispose it after document.save():
final font = AnyPdfFont.fromBytes(bytes);
try {
// build + save PDF
} finally {
font.dispose();
}
Repository #
https://github.com/ardevcraft/any_pdf_fixer
License #
Apache-2.0. Fonts supplied by applications remain under their own licenses.