feat: extract invisible OCR text layer from Mixed/template PDFs
Scanned PDFs with OCR text layers use rendering mode 3 (invisible text) positioned behind page images. Previously we skipped all Tr=3 text. Now for Mixed/template PDFs, if normal extraction produces garbage or empty output, we retry with invisible text included. This unlocks text from OCR-generated PDFs without requiring external OCR. Also adds Windows Unicode BMP (3,1) subtable support to the TrueType cmap fallback, and allows TrueType fonts with explicit encoding to extract their embedded cmap (OCR fonts often lie about encoding). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
8e674eeef5
commit
b8211db4b0
+20
-1
@@ -149,6 +149,25 @@ pub(crate) fn extract_positioned_text_from_doc(
|
||||
doc: &Document,
|
||||
font_cmaps: &FontCMaps,
|
||||
page_filter: Option<&HashSet<u32>>,
|
||||
) -> Result<(PageExtraction, PageThresholds), PdfError> {
|
||||
extract_positioned_text_impl(doc, font_cmaps, page_filter, false)
|
||||
}
|
||||
|
||||
/// Extract with option to include invisible (Tr=3) text.
|
||||
/// Used for Mixed/template PDFs where the OCR text layer is invisible.
|
||||
pub(crate) fn extract_positioned_text_include_invisible(
|
||||
doc: &Document,
|
||||
font_cmaps: &FontCMaps,
|
||||
page_filter: Option<&HashSet<u32>>,
|
||||
) -> Result<(PageExtraction, PageThresholds), PdfError> {
|
||||
extract_positioned_text_impl(doc, font_cmaps, page_filter, true)
|
||||
}
|
||||
|
||||
fn extract_positioned_text_impl(
|
||||
doc: &Document,
|
||||
font_cmaps: &FontCMaps,
|
||||
page_filter: Option<&HashSet<u32>>,
|
||||
include_invisible: bool,
|
||||
) -> Result<(PageExtraction, PageThresholds), PdfError> {
|
||||
let pages = doc.get_pages();
|
||||
let mut all_items = Vec::new();
|
||||
@@ -167,7 +186,7 @@ pub(crate) fn extract_positioned_text_from_doc(
|
||||
}
|
||||
}
|
||||
let (mut items, rects, lines) =
|
||||
extract_page_text_items(doc, page_id, *page_num, font_cmaps)?;
|
||||
extract_page_text_items(doc, page_id, *page_num, font_cmaps, include_invisible)?;
|
||||
let threshold = crate::text_utils::fix_letterspaced_items(&mut items);
|
||||
if threshold > 0.10 {
|
||||
page_thresholds.insert(*page_num, threshold);
|
||||
|
||||
Reference in New Issue
Block a user