Correct Bangla/Bengali Unicode rendering in PDFs generated with Flutter's pdf package.

Bangla PDF Fixer Version 3 is a full architectural reset. It uses pdf_text_shaper + HarfBuzz for proper OpenType shaping instead of translating Bangla Unicode into legacy ANSI font codes.

What changed in 3.0

Before

Bangla Unicode
→ handwritten rearrangement rules
→ ANSI/legacy character mapping
→ bundled legacy font
→ PDF

Now

Bangla Unicode
→ HarfBuzz GSUB/GPOS shaping
→ positioned glyph IDs
→ vector glyph rendering
→ invisible Unicode extraction layer
→ PDF

Benefits:

  • conjuncts and vowel signs are driven by the font's real OpenType rules;
  • original Unicode is never destroyed;
  • multiline input stays multiline;
  • no giant replacement map;
  • no package-bundled third-party fonts;
  • PDFs can retain useful copy/search text;
  • the same shaping engine is reusable for Hindi, Tamil, Arabic, etc.

Platforms

Android, iOS, Linux, macOS and Windows.

Web is not currently supported because the shaping backend uses native HarfBuzz FFI.

Legacy ANSI fonts

Do not use a legacy Bijoy/ANSI font with the Unicode shaper. Use a proper Unicode OpenType Bengali font.

Installation

dependencies:
  bangla_pdf_fixer: ^3.1.0
  pdf: ^3.13.0

Add a Unicode Bengali OpenType font to your app:

flutter:
  assets:
    - assets/fonts/NotoSansBengali-Regular.ttf
    - assets/fonts/NotoSansBengali-Bold.ttf

The package intentionally does not bundle fonts. Make sure the font license permits your use.

Load fonts

final regular = await BanglaFontManager.instance.loadAsset(
  'assets/fonts/NotoSansBengali-Regular.ttf',
  name: 'Noto Sans Bengali Regular',
);

final bold = await BanglaFontManager.instance.loadAsset(
  'assets/fonts/NotoSansBengali-Bold.ttf',
  name: 'Noto Sans Bengali Bold',
);

Repeated/concurrent requests for the same asset share the cache. A failed load is evicted automatically so it can be retried.

BanglaText

Use the concise font API:

BanglaText(
  'আমি বাংলায় লিখছি।',
  font: regular,
  fontSize: 16,
)

Or pass the underlying shaping style directly:

BanglaText(
  'Invoice ১২৩ — মোট ৳৫০০',
  style: ShapedTextStyle(
    font: regular,
    fallbackFonts: [latinFont],
    fontSize: 14,
    preserveUnicodeText: true,
  ),
)

Reusable typography

For larger documents, define the font/fallback family once:

final typography = BanglaTypography(
  regularFont: regular,
  boldFont: bold,
  fallbackFonts: [latinRegular],
  boldFallbackFonts: [latinBold],
);

Then reuse it:

BanglaHeader(
  'ফলাফল প্রতিবেদন',
  style: typography.heading(fontSize: 24),
),

BanglaParagraph(
  'বাংলা অনুচ্ছেদ এখন আসল Unicode হিসেবেই থাকে।',
  style: typography.body(fontSize: 12),
),

Bullet list

BanglaBulletList(
  font: regular,
  fontSize: 13,
  lineHeight: 1.3,
  markerGap: 8,
  items: const [
    'প্রথম বিষয়',
    'দ্বিতীয় বিষয়',
    'তৃতীয় বিষয়',
  ],
)

You can also pass a complete ShapedTextStyle instead of separate font/style arguments.

Rich text

BanglaRichText is intended for short mixed-style labels/headings. Each run is independently shaped so it can flow through pw.Wrap.

BanglaRichText(
  font: regular,
  fallbackFonts: [latinRegular],
  spans: [
    const BanglaTextSpan('মোট: '),
    BanglaTextSpan(
      '৳১২,৫০০',
      style: typography.style(bold: true, fontSize: 14),
    ),
  ],
)

For long flowing body text, prefer BanglaText or BanglaParagraph so the shaping engine owns the complete paragraph layout.

Table

BanglaTable.fromRows(
  font: regular,
  headerFont: bold,
  headerColor: PdfColors.blueGrey50,
  alternateRowColor: PdfColors.grey50,
  headers: const ['নাম', 'শ্রেণি', 'ফলাফল'],
  rows: const [
    ['আরিফ', 'দশম', 'A+'],
    ['নাবিলা', 'নবম', 'A'],
  ],
)

Or use BanglaTable(data: ...) when you already have a complete matrix. The first row is treated as a header by default; set headerRows: 0 for a table without headers. Header rows repeat automatically when a table spans pages; set repeatHeaderRows: false to disable that behavior.

Text detection

'Invoice ১২৩'.containsBangla; // true
'আমি বাংলা লিখি'.isBanglaOnly; // true

isBanglaText remains available as a compatibility alias for containsBangla.

Mixed Bangla + English

Use the universal style's fallback support:

BanglaText(
  'Invoice ১২৩ — মোট ৳৫০০',
  style: ShapedTextStyle(
    font: banglaFont,
    fallbackFonts: [latinFont],
    fontSize: 14,
  ),
)

Migration from 2.x

.fix

You no longer need:

'বাংলা'.fix

The deprecated getter remains as an identity operation for migration only. Pass the original Unicode string directly to BanglaText.

Font lifecycle

The singleton manager is designed for long-running Flutter apps. Keep commonly used fonts cached while generating PDFs and dispose them when the font service is genuinely being torn down:


await document.save();
await BanglaFontManager.instance.dispose();

You can evict one asset when needed:

await BanglaFontManager.instance.evict(
  'assets/fonts/NotoSansBengali-Regular.ttf',
);

Author

Maintained by AR Rahman GitHub: @ardevcraft

Crafted with ❤️ for Bangla and the open-source community. 🇧🇩

Stand With Palestine

Repository

https://github.com/ardevcraft/bangla_pdf_fixer

Contributions, bug reports, feature requests, and pull requests are welcome.

License

Licensed under the Apache License 2.0.

Libraries

bangla_pdf_fixer
Unicode-first Bangla/Bengali text rendering for package:pdf.