Skip to content

When generating a PDF with Arabic text, the library may throw the following exception: Bad state: No element #1919

@MazenxELGayar

Description

@MazenxELGayar

Describe the bug

When generating a PDF with Arabic text, the library may throw the following exception:

Bad state: No element
Iterable.first

Tracing the issue shows it originates from:

TtfWriter.withChars

Specifically this line:

glyphsInfo.add(glyphsMap[glyphsIndex] ?? glyphsMap.values.first);

If glyphsMap becomes empty, glyphsMap.values.first throws Bad state: No element, which provides no information about which character caused the failure.

After debugging and modifying the package locally, the failing character was:

ﻱ (U+FEF1)

This belongs to the Unicode block:

Arabic Presentation Forms-B (U+FE70–U+FEFF)

These characters often appear when text is copied from external sources (Word, PDFs, APIs, etc.) and many fonts do not contain glyphs for them.

The issue is therefore very difficult to diagnose because the thrown exception does not reveal the problematic character or text.


Suggested improvements

1️⃣ Better debugging / error reporting

Instead of throwing:

Bad state: No element

the library could provide a clearer error such as:

PdfFontException: Missing glyph for character 'ﻱ' (U+FEF1)

For example:

if (glyphsMap.isEmpty) {
  throw PdfFontException(
    "Missing glyph for character '${String.fromCharCode(char)}' "
    "(U+${char.toRadixString(16).toUpperCase()})"
  );
}

This would significantly improve debugging.


2️⃣ Optional normalization of compatibility characters

Many of these failures are caused by Unicode compatibility characters such as:

Arabic Presentation Forms
Ligatures
Compatibility glyphs

A potential solution would be to normalize input text using Unicode NFKC normalization, which converts these characters to their canonical forms.

Example using unorm_dart:

import 'package:unorm_dart/unorm_dart.dart' as unorm;


class TtfWriter {
  Uint8List withChars(List<int> chars) {
    ...
    for (final char in chars) {
      var glyphsIndex = charMap[char];

      if (glyphsIndex != null) {
        var glyph = glyphsMap[glyphsIndex];

        if (glyph == null) {
          if (glyphsMap.isEmpty) {
            final normalized = unorm.nfkc(String.fromCharCode(char));

            if (normalized.isNotEmpty) {
              final normalizedCode = normalized.runes.first;

              final normalizedIndex = ttf.charToGlyphIndexMap[normalizedCode];

              if (normalizedIndex != null &&
                  normalizedIndex < ttf.glyphOffsets.length) {
                glyph = ttf.readGlyph(normalizedIndex).copy();
                glyphsIndex = normalizedIndex;
              }
            }
          }

          if (glyph == null) {
            final wholeText =
                chars.map((e) => unorm.nfkc(String.fromCharCode(e))).join();

            final codes = chars
                .map((e) => 'U+${e.toRadixString(16).toUpperCase()}')
                .join(', ');

            print('⚠️ PDF glyph missing');
            print('char: ${String.fromCharCode(char)}');
            print('unicode: U+${char.toRadixString(16).toUpperCase()}');
            print('text: $wholeText');
            print('codes: $codes');
          }
        }

        if (glyph != null) {
          glyphsInfo.add(glyph);
          glyphsMap.remove(glyphsIndex);
        } else {
          continue;
        }
      }
    }

This would convert characters like:

ﻱ → ي
ﺗ → ت
ﺜ → ث

and prevent missing glyph errors.


To Reproduce

Example that may trigger the issue when the font does not contain Arabic presentation glyphs:

final pdf = pw.Document();

pdf.addPage(
  pw.Page(
    build: (context) => pw.Text("ﻱ"),
  ),
);

await pdf.save();

This can produce:

Bad state: No element

Expected behavior

The library should either:

  1. Provide a clear error message identifying the missing glyph, or
  2. Optionally normalize compatibility characters before glyph lookup.

Flutter Doctor

Paste output of: flutter doctor -v

Desktop

  • iOS
  • Android
  • Browser
  • Windows
  • Linux

Additional context

Arabic presentation forms frequently appear when text is copied from:

  • Word documents
  • PDFs
  • ERP systems
  • external APIs

Since the error message currently does not identify the problematic character, debugging this issue requires modifying the package source code.

Improved error reporting would make diagnosing font issues much easier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions