firecrawl/pdf-inspector
 Watch   
 Star   
 Fork   
2026-09-28 14:55:46
pdf-inspector

1.25.2 — Script sizes and ToUnicode repair checks

Changes since 1.25.1:

  • Size a super- or subscript run by its letters and digits: an exponent whose minus sign a symbol font sets a design size above its digits (as TeX does) keeps its <sup> markup; a run of signs alone, or with signs more than a quarter larger than its letters and digits, is still sized by its largest glyph (#603).
  • Skip a subset font's ToUnicode repairs where the font itself shows the CMap is right: the repair through a /CIDToGIDMap for a CMap keyed by code, and the renumbering of a subset that kept its glyph indexes (#605).

No API changes.

Release preparation: #606.

Full changelog

2026-09-28 08:38:56
pdf-inspector

1.25.1 — Font decoding fixes

Changes since 1.25.0:

  • Read simple fonts (Type1, TrueType, Type3) one byte per code when their ToUnicode CMap declares a two-byte codespace: text shown as a kerned run of short strings no longer loses every two-byte string (Income Statement read as Iometatent). The stale-CMap check for Type1 fonts judges such a CMap too, and the page detector counts such a font's text byte by byte (#595).
  • Read a Type1 font whose /Encoding names no base encoding through the built-in encoding of its embedded program (PDF 32000-1:2008, Table 114): TeX's fonts read their ligatures (efficiency, was eciency), curly quotes, dashes and math symbols. A code the program leaves at .notdef reads as nothing, the word space excepted, and the base-14 width fallback measures such fonts as they read (#596).
  • Take a repaired ToUnicode CMap for a string of one or two glyphs only on evidence beyond short common words: engagement no longer reads as engageaent, AND as ANa or Three as ThaTe (#597).

No API changes.

Release preparation: #604.

Full changelog

2026-09-26 04:15:35
pdf-inspector

1.25.0 — Async positions and underline detection speed

Changes since 1.24.0:

  • Node: extractTextWithPositionsAsync, the async variant of extractTextWithPositions: the same arguments and items, run on the libuv thread pool so a slow page no longer blocks the caller's event loop (#592).
  • Underline and strikeout detection no longer takes quadratic time on pages drawn from many thin filled rects or short strokes: a page of about 200,000 thin rects went from about 40 s to under 0.5 s, with the same marks (#592).
  • The linux-x64-gnu Node binary is cross-built for a GLIBC_2.17 floor again, so it loads on Amazon Linux 2023 (the managed AWS Lambda Node runtimes), RHEL 9 and Debian 11 (#586).

API: Node extractTextWithPositionsAsync.

Release preparation: #593.

Full changelog

2026-09-23 12:34:11
pdf-inspector

1.24.0 — Text paint and document information

Changes since 1.23.0:

  • Report the paint each text run was shown with: TextItem gains fill_color and stroke_color (8-bit sRGB, read from DeviceRGB, DeviceGray, DeviceCMYK, ICCBased by component count and Indexed palettes; None for Separation, DeviceN, Pattern and CIE-based spaces) and render_mode (the Tr mode, so invisible text and clipping-only text can be told apart). Extraction and markdown are unchanged (#579).
  • Read the document information dictionary's /Author, /Subject, /Keywords, /Creator, /Producer, /CreationDate and /ModDate beside /Title, each decoded as a PDF text string (#579).
  • Decode the document /Title as a PDF text string: titles in PDFDocEncoding no longer read with U+FFFD, titles in UTF-16LE no longer read as mojibake, and titles given by reference are read (#579).
  • Extract text a page shows with the " operator, which the page parser skipped together with the spacing and line move it makes (#579).
  • Take an ActualText span's weight from the paint of its first painted glyph rather than from the paint in force at the span's end (#579).
  • Keep two lines of small type apart when their baselines lie less than 5 pt apart: a stacked table header at 4.7 pt on a 4.5 pt pitch no longer comes out as words zipped from both lines, and type of 8⅓ pt and above groups exactly as before (#580).

API: TextItem::fill_color, stroke_color and render_mode (Node fillColor, strokeColor, renderMode; Python fill_color, stroke_color, render_mode; the pdf2md --items-json fields), and the PdfProcessResult / PdfTypeResult fields author, subject, keywords, creator, producer, creation_date and mod_date (Node and WebAssembly in camelCase, Python as attributes, and the pdf2md --json / detect-pdf --json members). Rust literals of these types must include the new fields.

Release preparation: #582.

Full changelog

2026-09-22 09:16:27
pdf-inspector

1.23.0 — Text-layer repairs

Changes since 1.22.1:

  • Read a Form XObject whose /BBox numerals are too large for any parser: such numerals are saturated in place before the document is read, so the form's text is extracted and the OCR pipeline renders it instead of an empty page (#560).

  • Read right-to-left runs shown in reading order forwards: a visible run of right-to-left letters painted forwards now votes for visual storage, so pages that came out word-mirrored read correctly; the logical-order reading is kept for invisible text layers (#561).

  • Read a re-encoded simple font by its /Differences names when it kept a stale ToUnicode CMap, and keep one glyph's characters together through the visual-order read-back (#562).

  • Compose a detached spacing accent with the letter it is painted over instead of leaving a stray accent a word on (#563).

  • Treat a return from a zero-advance dependent sign placed behind the pen as no word gap, so scripts that attach signs by stepping the pen back keep their words whole (#564).

  • Classify a page whose text layer is drawn invisibly under a covering image as a scan with the OCR reason invisible_text_layer, following the text rendering mode, the transformation, the graphics state stack and image draws through form content within a per-page budget (#566).

  • Interpolate single-glyph gaps in a ToUnicode CMap when the neighbouring codes make the reading unambiguous, mark the rest as U+FFFD instead of dropping them, and report each font's coverage (#568).

  • A ToUnicode entry whose destination is a control character is a miss, not text: the marker replaces it and the font program, the declared encoding or a blank glyph's advance recovers the letter where it can (#567).

  • pdf2md and detect-pdf take the PDF path as the first non-option argument, so flags may come before or after it, and a missing input names the path that could not be opened; the built-in CMaps are compiled into the binary instead of being read from the crate checkout at run time, so cargo install binaries and published wheels find them (PDF_INSPECTOR_BCMAPS_DIR still overrides) (#570).

API: PdfProcessResult::cmap_gaps (Node cmapGaps, Python cmap_gaps, WebAssembly cmapGaps, and the pdf2md --json / detect-pdf --analyze --json field) lists, per font with gaps among the two-byte codes shown, the codes shown, interpolated and left unmapped (#568). The detector's invisible_text_layer OCR reason is new (#566).

Release preparation: #571.

Full changelog

2026-09-21 06:50:50
pdf-inspector

1.22.1 — Ligature glyph names

Changes since 1.22.0:

  • Read ligature glyph names by their components instead of dropping them: names that spell a ligature by components (f_t, f_f_i, T_h), as a uni sequence of several code points (uni00660069), or with a suffix (a.sc, f_i.liga) decode to their letters per the Adobe Glyph List specification, in /Differences arrays and in embedded font programs' own glyph names; multi-letter results carry their widths through the base-14 fallback. A name that still cannot be read keeps reading as nothing, as in 1.22.0 (#558).

No API changes.

Release preparation: #559.

Full changelog

2026-09-21 00:55:01
pdf-inspector

1.22.0 — Right-to-left text, symbolic fonts, tracked titles and font metadata

Changes since 1.21.0:

  • Read right-to-left lines back through the Unicode Bidirectional Algorithm: Hebrew and Arabic text stored in visual order comes out in reading order even when the line holds numbers, Latin phrases or punctuation; glyph-by-glyph positioned words cluster into words by the line's own gaps; presentation forms normalize to their letters once the text is in reading order (#552).
  • Decode simple fonts through their /BaseEncoding, the Symbol and ZapfDingbats built-in encodings and their glyph names — Adobe Glyph List, uniXXXX and numbered gNN/cidNN names resolved against the embedded program — so symbol bullets, arrows and math operators read as the glyphs they are. A code the /Differences array names but cannot map reads as nothing, and a Type3 font's glyph-procedure names are never taken for glyph indexes (#553).
  • Keep tracked display text whole when its letter spacing is written as TJ offsets, so a spaced-out title reads as words rather than one letter per word (#548).
  • Add bold_source (where is_bold came from) and fixed_pitch to text items, and bold_weight_threshold to the positioned-text options; with bold_from_weight adjacent runs merge by the bold verdict; is_bold_font recognises Demi, Semibold, Ultra, Heavy and Black faces and the foundry abbreviations (#547).
  • Widen the zero-area /BBox of Form XObjects at load so their text is extracted and the page renders; Rust gains widen_degenerate_form_bboxes_mem(bytes) for the repaired document (#550).
  • Judge a CID-keyed font page's text decoded before calling it vector text, and bound Form XObject content inflation (#551).
  • Regression fixtures for the boxes of text drawn with a reflected matrix (#549).

bold_from_weight and bold_weight_threshold stay opt-in; the default is_bold now also reads the weight names above as bold.

Rust migration: TextItem literals need the new bold_source and fixed_pitch fields.

Release preparation: #556.

Full changelog

2026-09-19 14:02:06
pdf-inspector

1.21.0 — Font weight metadata, clipped-text and loading fixes

Changes since 1.20.0:

  • Add font_weight, the font's 100..=900 weight class, to text items in Rust, Node, Python and pdf2md --items-json, with an opt-in bold_from_weight on the positioned-text and region APIs that reads bold from a weight of 600 or more and keeps runs of different weight as separate items (#536).
  • Leave out text painted wholly outside its rectangular clip, so off-canvas labels no longer leak into the surrounding text (#539).
  • Tolerate leading bytes before the %PDF- header, locating it within the first 1024 bytes as mupdf, pdfium and poppler do (#538).

bold_from_weight is opt-in; is_bold and item merging are unchanged by default.

Rust migration: TextItem literals need font_weight: None for items whose weight class is unknown.

Release preparation: #546.

Full changelog

2026-09-15 13:51:55
pdf-inspector

1.20.0 — Display coordinates and extraction fixes

Changes since 1.19.0:

  • Add display-frame coordinates to the Rust and Node positioning/region APIs (#533).
  • Improve word spacing and font decoding (#517, #521, #522, #530).
  • Fix ActualText/dot leaders and TJ glyph positions (#523, #527).
  • Render contents lists one entry per line (#493).
  • Upgrade lopdf to 0.45.0 for malformed cross-reference recovery (#534).

The display frame is opt-in; existing sheet-frame coordinates remain the default.

Release preparation: #535.

Full changelog

2026-09-10 01:39:08
pdf-inspector

1.19.0 — Text extraction fixes and symbol metadata

Changes since 1.18.0:

  • Preserve stroke-simulated bold. #511
  • Honor horizontal text scaling. #510
  • Recover stale single-byte font mappings. #516
  • Expose legacy symbol-rewrite metadata in Rust and Node. #519
  • Keep separately clipped text runs apart. #518

Rust migration: TextItem literals need legacy_symbol_rewrite: false for items without symbol cleanup. The Node legacySymbolRewrite field is optional and emitted only when cleanup changed a character.

Full changelog · Compare with 1.18.0