bangla_pdf 1.9.2
bangla_pdf: ^1.9.2 copied to clipboard
Correct Bangla (Bengali) text in PDFs: real OpenType shaping for conjuncts, reph and vowel signs, with text that copies back out as clean Unicode.
1.9.2 #
Fixed #
- A dotted circle Word's shaper inserted inside a word is dropped. Word
shapes each formatting span separately, so a word split across two spans
(
মূল+্যায়নের) is drawn with◌before the virama that starts the second, and came back asমূল◌্যায়নের. A dotted circle directly after a Bangla letter and before a sign or virama is now left out; one an author typed to show a sign on its own (◌া) is kept.
1.9.1 #
Fixed #
- Vowel signs a subset pruned from the font's
cmapare recovered. Word's NikoshBAN subsets keep the glyphs ofৃandূ, and ligatures such asতৃ, but drop the signs from thecmap, so they could not be read back through the font;তৃতীয়came back asর্ততীয়every time. The document's own claims are now used for such a sign, but only where they fit the ligature's structure —পৃ,কৃvoting for ৃ — and only when they agree. - Words in table cells are no longer split. Word clips each glyph of a cell
with
q … Q, and writes the cell's spaces as one-byte( )shows; the first ended a run mid-word (ব ণ্ট ন,খ্রী ষ্ট) and the second lost the space. Runs now span the graphics state, and such a byte counts as a word gap. - A vowel sign drawn before a ya-phala is put after it:
নূ্যনতমreadsন্যূনতম.
1.9.0 #
Reads Word-exported Bangla PDFs correctly. Found through a real document — the NCTB primary assessment guideline, reported as extracting badly through the npm port — which exposed defects shared by both packages.
Fixed #
- A
/ToUnicodethat contradicts its own font is no longer believed. Microsoft Word pairs glyphs with characters by position, so every pair Bengali reorders comes out exchanged:শিis drawn[ি, শ], and the CMap recordsি→শandশ→ি. Which pairs depends on each document's words, so no fixed correction table can undo it. The extractor now compares the CMap with the embedded font's owncmap, and when they disagree reads the glyphs back through the font. On the reported 56-page document the share of malformed Bangla words goes from 23.4% to 1 in 14,448; poppler reads 24.8%. - Glyphs are read back as runs, not one operator at a time. Word shows one
glyph per
Tj, positions each with its ownTm, and on justified lines gives each its own text object and structure tag. Run boundaries now come from geometry — same baseline, pen continuity — so a vowel sign is reordered with the consonant it belongs to. - Un-shaping no longer reads a simple font's bytes as glyph ids. Only a CID
font's codes name glyphs; a WinAnsi space read as glyph 32 of NikoshBAN
produced
=10,668 times in one document. - A lone byte shown with a two-byte CID font is ignored, as poppler does, rather than taken as a glyph.
- A Unicode font that carries a Bengali
GSUBis never taken for Bijoy, even when a subsetter has pruned every Bengali entry from itscmap. Word's WinAnsi copy of NikoshBAN was being converted as Bijoy, and pages whose only text was a page number were labelledbijoy. - SutonnyMJ's alternate e-kar (
†) and ra-phala (Ö) are converted. The Bijoy table is generated from the forward mapping, which only writes the canonical codes, so these are handled as aliases. - Reordering read-back text: a pre-base vowel sign fused into a ligature (
টিas one glyph), a reph fused with its vowel sign (র্ী), a phala drawn after the base, and a zero-width joiner drawn with the space glyph all now come back in typing order.
Changed #
ocrHookis also offered a page that draws an image and has no words — only a page number, as Word stamps on an inserted scan. It previously saw only pages with no text at all, so those scans were never offered to OCR.confidencecounts text recovered by reading glyphs back at 0.75, whether the document had no mapping or one that had to be ignored, and no longer counts whitespace-only runs or a simple font's encoded text as unmapped.
Verification #
test/word_export_test.dart, 8 tests over the real document, 7 of which fail against 1.8.0. The npm port carries the same fixture and checks, and the two implementations produce byte-identical text from it.
1.8.0 #
Reads the documents it previously refused: ones that carry no text, and ones that are encrypted.
Added #
-
Encrypted PDFs are decrypted. Most "protected" documents — the kind a government office publishes — carry an owner password to discourage editing and an empty user password, so they open without one. Every revision in the wild is handled: RC4 40- and 128-bit (revisions 2 and 3), AES-128 (revision 4) and AES-256 (revisions 5 and 6).
extracttakes apassword:for a document that genuinely needs one, andExtractionResult.isLockeddistinguishes "could not be opened" from "is encrypted", which are no longer the same thing.The ciphers are implemented here rather than pulled in:
package:crypto(already in the tree, now a direct dependency) has MD5 and SHA-2 but no block ciphers. AES and RC4 are checked against the FIPS-197 and published test vectors, and the handler itself against fixtures encrypted by qpdf, so it is tested against another implementation rather than its own assumptions. -
GSUB type 8 and GPOS type 3. Reverse chaining substitution and cursive attachment, the two lookup types the engine was missing, plus the
cursfeature in HarfBuzz's order. No Bengali font uses either — asserted by a test, not assumed — so nothing about Bangla changes; a font that does use them is no longer shaped wrongly with no sign of it. GSUB 8 is verified against HarfBuzz using Noto Sans Coptic, which puts one inccmp.
Added #
-
Un-shaping. A document with no
/ToUnicodeCMap and no/ActualTexthas thrown its text away; all that survives is which glyph was drawn. Such a document is now read by taking the embedded font apart backwards: everyGSUBsubstitution it declares — single, multiple, alternate and ligature, including through extension lookups — is inverted into "this glyph came from those", then resolved until each glyph is expressed as codepoints thecmapknows.Decoding alone is not enough, because Bengali draws a cluster out of order, so reph and pre-base vowel signs are moved back into typing order and the pairs Unicode writes as one character are recomposed.
243 of 251 corpus cases (97%) come back exactly. The shortfall is text that is not in the glyphs at all: an emoji the font cannot draw, a ZWJ (which is invisible), and the dotted circles the shaper inserts for a vowel sign typed with no consonant.
It is used only as a last resort. A document that carries a real
/ToUnicodeis unaffected — that is authoritative, where this is inference. -
/CIDToGIDMapstreams are honoured, so a CID font that remaps its glyphs is read correctly rather than by assuming identity.
Verification #
-
The corpus is now compared as pixels, not only as glyph ids. 238 cases are drawn by this package and by HarfBuzz, rasterised by the same poppler at the same size, cropped to their ink and overlaid: 98.1% mean overlap, 91.4% at worst. Glyph-level parity cannot see a wrong advance written into the embedded font, or a glyph drawn at the wrong offset; this can.
Two things had to be right for the comparison to mean anything. The images are nudged a couple of pixels against each other before scoring, because cropping aligns only to whole pixels while glyphs land on sub-pixel boundaries — without it, a half-pixel offset shears away a large share of the overlap on a script made of thin strokes. And
hb-viewis given--script=Beng: left to guess, it picks Latin for any string starting with Latin and skips Indic shaping altogether, which made correct output look like a defect in four cases until it was checked. -
Chrome, Brave and Adobe Reader confirmed to copy and paste shaped Bangla correctly. Previously only poppler had been checked.
-
Three real PDFs from a Bangladeshi government primary-education site (52 pages) were run through extraction. All three are pure scans, and all 52 pages were reported as having no text layer rather than given invented text.
test/real_documents_test.dartruns over anything placed intest/fixtures/real/, and skips when it is empty.
Notes #
- Inverting
GSUBcannot always tell which side of a consonant its virama belongs on: a reph is typedরthen virama and a ya-phala the other way round, yet a font lists both the same way. Rather than guess, a decode is confirmed by shaping it again and keeping it only if the same glyphs come back; where they do not, virama positions are flipped until they do. That search is bounded, so a long ambiguous run keeps its unverified reading rather than costing exponential time. - If a producer's subsetter dropped
GSUB, only what thecmapreaches can be recovered. This package's own subsetter drops it too, which is harmless because its documents always carry/ActualText.
1.7.0 #
Documents are now a fraction of their former size: only the glyphs actually drawn are embedded.
Added #
-
Font subsetting. A Bengali font is mostly outlines —
glyfis 85% of the bundled Kalpurush and 62% of Noto Sans Bengali — and a document draws a few dozen of them. The shaping tables are dead weight in a PDF as well, since shaping has already been applied before anything is written, soGSUB,GPOSandGDEFare dropped along with the screen-hinting tables and the 8 KB glyph-name table inpost.before after one line of Bangla 73 KB 5 KB a paragraph 73 KB 11 KB a paragraph with a fallback font 222 KB 17 KB the four sample documents ~78 KB each 13–18 KB This matters most for 1.6.0's fallback chains, where every extra font used to add its full weight.
Glyph ids are preserved rather than renumbered, so
/CIDToGIDMap, the/Warray and/ToUnicodeare untouched; the cost is four bytes oflocaper blanked glyph against hundreds saved per dropped outline. Composite glyphs pull in the glyphs they are built from, transitively. Embedded fonts now carry the conventionalABCDEF+subset tag.A font that cannot be cut safely — PostScript/CFF outlines, a damaged table directory — is embedded whole rather than risked.
Verification #
Rendering was checked, not assumed: the four sample documents rasterise
byte-identically to their pre-subsetting renders at 220 dpi. Extraction
alone could not have caught a dropped outline, since /ActualText carries the
source text whether or not a glyph was drawn.
Seven new tests, including every corpus case rendered through a subset font, and a composite glyph requested alone to prove its components survive.
1.6.0 #
Characters your Bangla font does not have now render, and the three Text
options that were being ignored are honoured.
Added #
-
Font fallback.
TextStyle.fontFallbackis honoured, andBanglaPdf.configure(fallbackFonts: [...])sets a chain for the whole document. Each character is drawn by the first font in the chain that has a glyph for it.This is the fix for missing characters generally. Measured across the five tested faces, no Bangla typeface contains arrows, symbols or emoji, and most barely cover Latin-1 — the bundled Kalpurush has 206 glyphs in total, of which 8 of 96 Latin-1 and 0 of 128 Latin Extended-A. So
café,±,°,€and emoji were all silently dropped. Swapping the default typeface could not have fixed this; only a fallback chain can.Bengali is never affected: it is always drawn by the Bangla font, and a fallback boundary can never fall inside a cluster, because combining marks stay with the base they follow.
-
tightBoundsmeasures real ink now.OtFontgained per-glyph extents read fromglyf/loca, so the box hugs the glyphs actually drawn instead of the font's ascent and descent. A font without TrueType outlines falls back to the font metrics. -
softWrap: falselays the text out on a single line. -
textDirectionresolvesTextAlign.startandendto the correct edge. It does not reorder right-to-left text; that needs a bidi pass and is now stated as a limitation rather than left to be discovered.
Fixed #
BanglaPdf's class documentation claimed the bundled font was Noto Sans Bengali. It is Kalpurush, as it has been since 1.0.
Notes #
- The bundled typeface is unchanged. Kalpurush stays the default so existing documents keep their appearance; a fallback chain is the supported way to widen coverage.
1.5.0 #
Long Bangla documents and justified Bangla text both work now. These were the
two largest gaps between shaped text and what package:pdf does with Latin.
Added #
-
Bangla text spans pages.
ShapedTextWidgetimplementsSpanningWidget, so inside apw.MultiPagea paragraph markedoverflow: TextOverflow.spancontinues onto the next page, breaking on a line boundary. Previously it threw:PdfException: Widget won't fit into the page as its height (665.28) exceed a page height (220.0). You probably need a SpanningWidgetwhich made multi-page reports and notices — the package's main use case — impossible with a paragraph longer than one page. Spanning is opt-in through
overflow: TextOverflow.span, exactly as it is forpw.RichText, so no existing document changes. -
TextAlign.justifyjustifies. It previously fell through to left alignment, silently:pw.Paragraphdefaults to justify, so most callers were getting ragged text without being told. Slack is shared between word gaps and the last line of each paragraph is left ragged, as in any typesetting system. Extraction is unaffected — a justified line and a ragged one produce identical text.
Changed #
- The showcase notice and report now show genuinely justified body text.
Notes #
textDirection,softWrapandtightBoundsare still ignored once a string is shaped; they are honoured on thepackage:pdfpath. This is now stated in the README rather than left to be discovered.
1.4.3 #
Fixed #
-
Compat widgets reported zero height.
package:pdf'sTextStyle.lineSpacingis extra leading in points and defaults to0, whileShapedTextWidget's is a multiplier. The bridge passed one straight into the other, so every shaped line computed a height of zero: text still painted, but anyColumn,ContainerorTablearound it laid out as if the text were not there, and neighbouring widgets overlapped.ShapedTextWidgetnow takesextraLeadingseparately, and the compat layer mapsTextStyle.lineSpacingonto it — solineSpacing: 8adds 8 points, as it does inpackage:pdf. A compat widget's box now matches the original API's exactly.Only
package:bangla_pdf/widgets.dart(new in 1.4.0) was affected. The originalText,Header,Tableand friends were never wired this way.
Added #
- A fourth showcase document — a half-yearly report with metric cards and a bar
chart carrying Bangla axis labels and a Bangla legend. It is written against
the drop-in entry point, so
tool/dev/make_showcase.dartnow exercises both APIs the package offers. - Two layout regression tests pinning the box a shaped widget reports, and the
meaning of
lineSpacing.
Changed #
- README shows the four sample documents two per row.
- The first pub.dev screenshot is now a full sample document rather than the before/after comparison.
1.4.2 #
Fixes font selection through the new widgets.dart entry point.
Fixed #
- A legacy Bijoy font passed to a compat widget was silently ignored and
replaced with the bundled Unicode Kalpurush, so 1.0.x documents moved to the
new entry point would have changed typeface without warning. A font is now
classified by what it contains — whether its
cmapcovers Bengali, and how densely it covers the Latin-1 supplement — so a Bijoy face is recognised and drives the transcoding path with that font, as it does in the original API.
Added #
- A plain
pw.Font.ttfcovering Bengali is promoted to a shaping font, both in aTextStyleand inBanglaPdf.configure(defaultFont:). Callers no longer have to know thatBanglaPdf.loadFontexists; either works. - Six tests covering every font route: no font,
loadFont, a plain Banglapw.Font.ttf, two Bijoy faces, and a Latin-only font.
Changed #
- README: the "Want a different font?" section showed
Text(banglaFont: …), which is the original API and does not compile against thepw-shaped widgets the rest of the page now uses.
1.4.1 #
- README: the drop-in section rewritten in plain language, and the three sample documents re-rendered at 220dpi so they are readable at full width. The higher resolution files are also smaller — 104 KB the set, down from 178 KB.
1.4.0 #
Adds a second entry point that makes this package a true drop-in for
package:pdf: change one import and existing code renders Bangla correctly.
Added #
-
package:bangla_pdf/widgets.dart— a replacement forpackage:pdf/widgets.dart. It re-exports everythingpackage:pdfexports, with the text-rendering widgets swapped for versions that shape Bangla and take exactly the same parameters:- import 'package:pdf/widgets.dart' as pw; + import 'package:bangla_pdf/widgets.dart' as pw;Replaced:
Text,RichText,TextSpan,Header,Paragraph,Bullet,TableHelper,Watermark,TableOfContent,ChartLegend,FixedAxis,TextFieldandChoiceField— every widget inpackage:pdfthat builds aTextinternally, so chart labels, watermarks, tables of contents and form field values all shape too.A string with no Bengali in it is passed to
package:pdfuntouched, so a document without Bangla renders exactly as it does without this package. -
tool/dev/check_pw_parity.py, which diffs all 14 replacement constructors against theirpackage:pdfcounterparts. All 156 parameters match. -
test/compat_test.dart(8 tests). It never importspackage:pdf/widgets.dart, so a gap in the re-export or a renamed parameter fails the build rather than reaching a user.
Fixed #
BanglaShapingMode.legacynow routes the compatibility widgets through the 1.0.x Bijoy pipeline. Reaching that mode through the new entry point would otherwise have drawn raw Unicode with a Latin font.
Notes #
- The existing
bangla_pdf.dartwidgets (Text,Header,BulletList,Table, …) are unchanged and unaffected. Nothing is deprecated by this release; the two entry points can be mixed in one file. - Form fields shape their appearance stream only. Once a reader lets someone edit the field it re-renders from the form font, which no producer controls.
1.3.1 #
Completes signature parity with package:pdf and rewrites the README around
real example documents.
Added #
The last parameters that were still missing from a pw counterpart. All
optional, so no existing call changes.
Text,AutoText,RichText—hyphenation.Header—child, matchingpw.Header.TextSpan—baselineandannotation, matchingpw.TextSpan.BulletList—bulletSize,bulletShape,bulletMargin. SettingbulletSizedraws a shape marker instead of a text bullet, aspw.Bulletdoes.Table—headerAlignments,cellDecoration,textStyleBuilder,cellBuilder, completingpw.TableHelper.fromTextArray.
Changed #
- README rewritten to lead with example output and keep the shaping internals in collapsible sections.
- Three new screenshots — an invoice, a notice and a report — generated from
the public widgets by
tool/dev/make_showcase.dart. They replace the old single-page widget preview.
1.3.0 #
Makes the widgets drop-in replacements for their package:pdf counterparts, so
Bangla is the only thing that changes when you switch.
Changed #
pdfis now^3.13.0(was^3.11.3).lib/src/pdf/shaped_pdf_font.dartreaches intopackage:pdf's internals to build a glyph-addressed CID font, so the narrower range is what is actually tested. If you are pinned below 3.13, stay on 1.2.0.
Added #
Every one of these is optional, so no existing call changes.
Header—level,title,margin,padding,decoration,textStyle,outlineColor,outlineStyle, matchingpw.Header.Paragraph—margin,padding, matchingpw.Paragraph.RichText—textDirection,softWrap,tightBounds,textScaleFactor,maxLines,overflow, matchingpw.RichText.TextSpan—style, matchingpw.TextSpan. It takes precedence over the loosefontSize/color/fontWeightarguments.BulletList—bulletColor,margin,padding,itemSpacing,textAlign.Table—headerCount,headerStyle,headerPadding,headerHeight,headerDecoration,headerTextColor,cellStyle,cellTextColor,cellHeight,cellAlignments,rowDecoration,oddRowDecoration,border,defaultColumnWidth,tableWidth,defaultVerticalAlignment, mirroringpw.TableHelper.fromTextArray.
Text already accepted the whole of pw.Text's parameter list and is
unchanged.
Deprecated #
Nothing is removed; both still work and are covered by tests.
AutoText—Textis now identical to it. It existed to split a string into Bangla and non-Bangla runs so each could get its own font; since 1.1.0 a Unicode Bangla font covers Latin and digits too, so there is nothing left to split.Textabsorbed its one extra parameter,generalFont. Scheduled for removal in 2.0.0.RichTextItem— declared in 1.0 and never constructed by anything, in this package or in any documented usage. UseTextSpanwithRichText. Scheduled for removal in 2.0.0.
Notes #
- Header and Paragraph take their text positionally, as they have since
1.0, where
pw.Headerandpw.Paragraphtake it as a namedtext:argument. That is the one call-site difference. ParagraphkeepsTextAlign.startas its default rather thanpw'sjustify, because changing it would alter existing documents.- On the shaping path a single font draws the whole string, so
styleandbanglaStyleno longer style Bangla and Latin differently within one widget;banglaStylewins when both are set. Use separate widgets for two looks. The legacy Bijoy path is unchanged. - A new
test/api_parity_test.dartconstructs every widget with its full parameter set, so a dropped or renamed parameter fails the build.
1.2.0 #
Adds PDF text extraction, in a separate library so generation-only users pay nothing for it.
import 'package:bangla_pdf/extract.dart';
final result = BanglaPdfExtractor.extract(bytes);
Added #
BanglaPdfExtractor.extract(bytes, {ocrHook})returningExtractionResultwithtext,pages,encodingDetected(unicode/bijoy/mixed/none),confidenceandisEncrypted.- Bijoy / ANSI → Unicode. Most Bangladeshi government and newspaper PDFs
store Latin-1 mojibake and rely on an 8-bit font to draw Bangla. These are now
detected from the embedded font's coverage and converted back, including the
reverse reordering: pre-base vowel signs move back after their consonant and a
reph moves back in front of its cluster. Also exposed on its own as
bijoyToUnicode. - Scanned-page handling. A page with images and no text layer reports
BanglaTextEncoding.noneinstead of guessing, andocrHooklets you plug in an OCR engine. None is bundled; the README shows a Tesseractbenexample. - A PDF reader covering cross-reference tables and streams, object streams,
FlateDecode(with PNG and TIFF predictors),LZWDecode,ASCIIHexDecode,ASCII85DecodeandRunLengthDecode. A damaged cross-reference table falls back to scanning the file for objects, so partly-corrupt documents still read. - Ten fixture documents with ground truth, and 12 extraction tests.
Verified #
- All 8 extractable fixtures recover their ground truth exactly; both scans are correctly reported as having no text layer.
- 245 of 247 pure-Bangla corpus cases survive a Bijoy round-trip. The shortfall
is the joiner in
বাক্, which the Bijoy encoding cannot represent.
Changed #
- New dependency on
archivefor stream inflation, chosen overdart:ioso extraction also works on web.
1.1.2 #
Never released on its own; these changes ship as part of 1.2.0.
- FIX: Fonts that declare only the version 1 Indic script tag (
beng) rather thanbng2now shape correctly. SolaimanLipi is the notable one: it formed no ya-phala or ra-phala at all and left a bare virama behind, soব্যক্রপ্রস্ত্রand every conjunct built on a phala came out wrong. Version 1 fonts write theirhalf/blwf/pstfrules as consonant + virama; the shaper now moves the virama after the last consonant of the syllable for those fonts, and applieshalfalone before the base rather thanhalf+blwf. SolaimanLipi goes from 183/234 to 234/234 against HarfBuzz, with no change to any version 2 font. - VERIFIED: Siyam Rupali matches HarfBuzz on all 234 cases with no changes
needed. Both bundled ANSI fonts are correctly detected as legacy and routed
to the Bijoy pipeline by
BanglaShapingMode.auto. - Five fonts are now covered by the corpus tests, spanning both generations of the OpenType Indic spec.
1.1.1 #
Documentation only. No code changes, so nothing behaves differently.
- Rewrote the README: a rendered before/after generated from the real pipeline,
a feature grid, section icons, the sample-page screenshot alongside the widget
list, and a
pdftotextbefore/after showing that the text in the PDF is now real Bangla rather than Bijoy ANSI. - Scoped the
bangla_pdf_fixercredit to the legacy Bijoy pipeline, which is what actually descends from it. - Fixed the screenshot paths:
pubspec.yamlpointed into a directory excluded from the published archive, so the screenshot reference would have dangled. Both screenshots now ship. - The audit and verification write-ups under
docs/stay in the repository and are not shipped in the package; the README links to them by URL.
1.1.0 #
Bangla is now shaped with the font's own OpenType tables instead of being transcoded to Bijoy ANSI. Conjuncts ligate, reph and pre-base vowel signs are reordered correctly, and the text in the PDF is real Unicode that copies, searches and extracts. No API was removed and no existing call needs changing.
Fixed — crashes #
RangeErroron reph.কর্ম,ধর্ম,বর্ষ,পূর্ব,শর্ত,র্কand any other reph word ending a Bangla run threw an uncaughtRangeErrorout ofpw.Widget.build, aborting the wholepdf.save(). 21 of the 253 corpus cases crashed 1.0.6; none crash now. A loneি/েand a leading্রcrashed for the same reason and are fixed.
Fixed — shaping #
Corpus ids that rendered wrongly in 1.0.6 and are correct now:
- 3- and 4-consonant conjuncts that fell back to a visible hasanta —
conj3-01ক্ষ্ম,conj3-02ঙ্ক্ষ,conj3-05ত্ত্ব,conj3-06চ্ছ্ব,conj3-04ম্ভ্র,conj4-00স্ত্র্য,conj4-01ঙ্ক্ষ্য,conj4-02ক্ষ্ম্য. - Seven conjunct entries in the old table were unreachable because a shorter
key consumed the input first (
ঙ্ক্ষ,চ্ছ্ব,ত্ত্ব,ন্দ্ব,ম্ভ্র,ষ্ক্র,স্তু). Conjunct coverage now comes from the font, not a table. reph-00…reph-19andrephconj-00…rephconj-07: reph is placed by the font'srphffeature and the Indic reordering rules.assamese-00…assamese-02(ৰৱ) andpunct-01(॥) had no mapping and rendered as notdef.digits-*: Bengali digits০–৯stayed Bengali instead of being converted to ASCII, and৳stays৳instead of becoming$.zwj-00…zwj-05: ZWJ is no longer rewritten to ZWNJ before the shaping decision, soর্যandর্যdiffer correctly.norm-00…norm-05: NFC and NFD spellings now shape identically.mix-*: Latin, Bengali digits and currency render in one pass with a real font instead of falling back to base-14 Helvetica.
Fixed — the PDF itself #
- Text is emitted as a
/Type0/Identity-HCID font addressed by glyph id, with a/CIDToGIDMapand a/ToUnicodeCMap whose entries may be several codepoints, so a conjunct copies back as its full sequence. - Each line is wrapped in a
/Span <</ActualText …>> BDC … EMCspan, which is what makes copy/paste survive Bengali's glyph reordering.pdftotextrecovers 249 of 251 corpus cases exactly; 1.0.6 recovered none. - Line breaking happens on syllable boundaries, so a line can never break inside a conjunct or between a vowel sign and its consonant.
BulletListdraws its bullet with a real font instead of Helvetica, which has no glyph for•.
Added #
BanglaShapingMode(auto,unicode,legacy) andBanglaPdf.configure({shapingMode, defaultFont}).BanglaPdf.loadFont(ByteData)for a custom Unicode Bangla font.String.shapeForPdf(font)for callers building their own PDF content.BanglaPdf.covers(font, text)to ask whether a font can draw a string.BanglaFontManager().legacyFontexposes the bundled Bijoy/ANSI font.- The bundled font is now the Unicode build of Kalpurush (OFL-1.0),
subsetted to 121 KB with all OpenType layout retained. Same typeface as
1.0.x, so documents look unchanged. Licence in
LICENSE-FONTS.txt. - 253-case test corpus in
test/corpus/bangla_cases.json; 18 automated tests.
Changed #
- The default font is the Unicode build of Kalpurush instead of the 8-bit
Bijoy build. The typeface is identical, so existing documents look the
same; only the shaping is fixed. Pass
BanglaPdf.configure(shapingMode: BanglaShapingMode.legacy)to restore byte-identical 1.0.x output. BulletListfalls back from•to a marker the font has, because Kalpurush carries no U+2022.- A
banglaFont:that is a legacy 8-bit font (SutonnyMJ, Kalpurush ANSI) is detected automatically and keeps the 1.0.x pipeline, so existing custom-font code is unaffected.
Verified #
- Shaping is identical to HarfBuzz — same glyphs, same positions — on all 234 pure-Bangla corpus cases, for all three test fonts: the bundled Kalpurush, Noto Sans Bengali and Noto Serif Bengali.
- 249 of 251 corpus cases round-trip through
pdftotextexactly. The two exceptions are one artefact: a lone ZWJ renders as nothing, so the line-by-line comparison shifts.
Known limitations #
See the README. In short: PDFs embed the full font rather than a per-document
subset, rendering is not pixel-diffed, copy/paste is verified with poppler
only, and PDF text extraction (extract.dart) is not implemented yet.
1.0.6 #
- FIX: Fixed some broken character mappings in the Kalpurush font for better rendering.
1.0.5 #
- FIX: Fixed some broken character mappings in the Kalpurush font for better rendering.
1.0.4 #
- DOCS: Added comprehensive documentation for public API.
- FIX: Fixed formatting issues to comply with Dart formatter.
- EXAMPLE: Verified example app structure for pub.dev analysis.
1.0.3 #
- BREAKING: Removed bundled fonts (except Kalpurush) to reduce package size.
- BREAKING: Removed
BanglaFontManagerinitialization requirement. - BREAKING: Removed
BanglaFontTypeenum. Usepw.Fontdirectly for custom fonts. - NEW:
Textand other widgets now acceptbanglaFontparameter for custom fonts. - NEW: Default font (Kalpurush) is now embedded and loaded automatically.
1.0.2 #
- NEW: Added
BanglaAutoTextwidget for automatic Bangla and English text mixing - ENHANCED: Updated
BanglaTableto support mixed Bangla and English content in all cells - NEW: Added support for Bangla Taka symbol (৳) in text rendering
- FIXED: Resolved all lint errors - improved code quality and maintainability
- IMPROVED: Enhanced Unicode mapping for better character rendering
- CHANGED: Switched from Apache 2.0 to MIT License
- DOCS: Added comprehensive examples for all widgets with proper documentation
1.0.1 #
- Minor bug fixes and stability improvements.
1.0.0 #
- Initial release of the Bangla PDF package 2025-11-20.
- Added support for multiple Bangla fonts.
- Implemented font fixing for PDFs with broken fonts.
- Fixed various issues with font rendering.
