formatferry 1.0.24 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +365 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,9 +5,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __commonJS = (cb, mod) => function __require() {
|
|
9
12
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
13
|
};
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
11
18
|
var __copyProps = (to, from, except, desc) => {
|
|
12
19
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
20
|
for (let key of __getOwnPropNames(from))
|
|
@@ -2795,12 +2802,12 @@ var require_ChildNode = __commonJS({
|
|
|
2795
2802
|
"use strict";
|
|
2796
2803
|
var Node2 = require_Node();
|
|
2797
2804
|
var LinkedList = require_LinkedList();
|
|
2798
|
-
var createDocumentFragmentFromArguments = function(
|
|
2799
|
-
var docFrag =
|
|
2805
|
+
var createDocumentFragmentFromArguments = function(document3, args) {
|
|
2806
|
+
var docFrag = document3.createDocumentFragment();
|
|
2800
2807
|
for (var i = 0; i < args.length; i++) {
|
|
2801
2808
|
var argItem = args[i];
|
|
2802
2809
|
var isNode = argItem instanceof Node2;
|
|
2803
|
-
docFrag.appendChild(isNode ? argItem :
|
|
2810
|
+
docFrag.appendChild(isNode ? argItem : document3.createTextNode(String(argItem)));
|
|
2804
2811
|
}
|
|
2805
2812
|
return docFrag;
|
|
2806
2813
|
};
|
|
@@ -3068,7 +3075,7 @@ var require_Element = __commonJS({
|
|
|
3068
3075
|
return NodeUtils.serializeOne(this, { nodeType: 0 });
|
|
3069
3076
|
},
|
|
3070
3077
|
set: function(v) {
|
|
3071
|
-
var
|
|
3078
|
+
var document3 = this.ownerDocument;
|
|
3072
3079
|
var parent = this.parentNode;
|
|
3073
3080
|
if (parent === null) {
|
|
3074
3081
|
return;
|
|
@@ -3079,8 +3086,8 @@ var require_Element = __commonJS({
|
|
|
3079
3086
|
if (parent.nodeType === Node2.DOCUMENT_FRAGMENT_NODE) {
|
|
3080
3087
|
parent = parent.ownerDocument.createElement("body");
|
|
3081
3088
|
}
|
|
3082
|
-
var parser =
|
|
3083
|
-
|
|
3089
|
+
var parser = document3.implementation.mozHTMLParser(
|
|
3090
|
+
document3._address,
|
|
3084
3091
|
parent
|
|
3085
3092
|
);
|
|
3086
3093
|
parser.parse(v === null ? "" : String(v), true);
|
|
@@ -5665,9 +5672,9 @@ var require_defineElement = __commonJS({
|
|
|
5665
5672
|
});
|
|
5666
5673
|
return c;
|
|
5667
5674
|
};
|
|
5668
|
-
function EventHandlerBuilder(body,
|
|
5675
|
+
function EventHandlerBuilder(body, document3, form, element) {
|
|
5669
5676
|
this.body = body;
|
|
5670
|
-
this.document =
|
|
5677
|
+
this.document = document3;
|
|
5671
5678
|
this.form = form;
|
|
5672
5679
|
this.element = element;
|
|
5673
5680
|
}
|
|
@@ -16542,8 +16549,8 @@ var require_Window = __commonJS({
|
|
|
16542
16549
|
var Location = require_Location();
|
|
16543
16550
|
var utils = require_utils();
|
|
16544
16551
|
module.exports = Window;
|
|
16545
|
-
function Window(
|
|
16546
|
-
this.document =
|
|
16552
|
+
function Window(document3) {
|
|
16553
|
+
this.document = document3 || new DOMImplementation(null).createHTMLDocument("");
|
|
16547
16554
|
this.document._scripting_enabled = true;
|
|
16548
16555
|
this.document.defaultView = this;
|
|
16549
16556
|
this.location = new Location(this, this.document._address || "about:blank");
|
|
@@ -16674,11 +16681,11 @@ var require_lib = __commonJS({
|
|
|
16674
16681
|
};
|
|
16675
16682
|
};
|
|
16676
16683
|
exports.createWindow = function(html, address) {
|
|
16677
|
-
var
|
|
16684
|
+
var document3 = exports.createDocument(html);
|
|
16678
16685
|
if (address !== void 0) {
|
|
16679
|
-
|
|
16686
|
+
document3._address = address;
|
|
16680
16687
|
}
|
|
16681
|
-
return new impl.Window(
|
|
16688
|
+
return new impl.Window(document3);
|
|
16682
16689
|
};
|
|
16683
16690
|
exports.impl = impl;
|
|
16684
16691
|
}
|
|
@@ -17409,6 +17416,137 @@ var require_turndown_cjs = __commonJS({
|
|
|
17409
17416
|
}
|
|
17410
17417
|
});
|
|
17411
17418
|
|
|
17419
|
+
// ../../src/shared/feature-flags.ts
|
|
17420
|
+
function getFeatureFlags() {
|
|
17421
|
+
return { ..._flags };
|
|
17422
|
+
}
|
|
17423
|
+
var _flags;
|
|
17424
|
+
var init_feature_flags = __esm({
|
|
17425
|
+
"../../src/shared/feature-flags.ts"() {
|
|
17426
|
+
_flags = {
|
|
17427
|
+
enableDocx: true,
|
|
17428
|
+
enableXlsx: true,
|
|
17429
|
+
enablePdf: true,
|
|
17430
|
+
enableHtml: true,
|
|
17431
|
+
enablePdfTableDetection: true,
|
|
17432
|
+
enableData: true,
|
|
17433
|
+
enablePptx: true,
|
|
17434
|
+
enablePdfEnhanced: true,
|
|
17435
|
+
enablePdfMultiColumn: true,
|
|
17436
|
+
enablePdfOcr: false
|
|
17437
|
+
};
|
|
17438
|
+
}
|
|
17439
|
+
});
|
|
17440
|
+
|
|
17441
|
+
// ../../src/shared/adapters/pdf-ocr-adapter.ts
|
|
17442
|
+
var pdf_ocr_adapter_exports = {};
|
|
17443
|
+
__export(pdf_ocr_adapter_exports, {
|
|
17444
|
+
isOcrAvailable: () => isOcrAvailable,
|
|
17445
|
+
runOcr: () => runOcr
|
|
17446
|
+
});
|
|
17447
|
+
async function loadTesseract() {
|
|
17448
|
+
try {
|
|
17449
|
+
const mod = await import("tesseract.js");
|
|
17450
|
+
if (mod && typeof mod.createWorker === "function") {
|
|
17451
|
+
return mod;
|
|
17452
|
+
}
|
|
17453
|
+
return null;
|
|
17454
|
+
} catch {
|
|
17455
|
+
return null;
|
|
17456
|
+
}
|
|
17457
|
+
}
|
|
17458
|
+
function preScaleCanvas(canvas) {
|
|
17459
|
+
if (canvas.width <= MAX_IMAGE_WIDTH) return canvas;
|
|
17460
|
+
const scale = MAX_IMAGE_WIDTH / canvas.width;
|
|
17461
|
+
const scaled = document.createElement("canvas");
|
|
17462
|
+
scaled.width = MAX_IMAGE_WIDTH;
|
|
17463
|
+
scaled.height = Math.round(canvas.height * scale);
|
|
17464
|
+
const ctx = scaled.getContext("2d");
|
|
17465
|
+
if (ctx) {
|
|
17466
|
+
ctx.drawImage(canvas, 0, 0, scaled.width, scaled.height);
|
|
17467
|
+
}
|
|
17468
|
+
return scaled;
|
|
17469
|
+
}
|
|
17470
|
+
function canvasToBlob(canvas) {
|
|
17471
|
+
return new Promise((resolve2, reject) => {
|
|
17472
|
+
canvas.toBlob(
|
|
17473
|
+
(blob) => {
|
|
17474
|
+
if (blob) resolve2(blob);
|
|
17475
|
+
else reject(new Error("canvas.toBlob returned null"));
|
|
17476
|
+
},
|
|
17477
|
+
"image/png"
|
|
17478
|
+
);
|
|
17479
|
+
});
|
|
17480
|
+
}
|
|
17481
|
+
async function isOcrAvailable() {
|
|
17482
|
+
if (!getFeatureFlags().enablePdfOcr) return false;
|
|
17483
|
+
const lib = await loadTesseract();
|
|
17484
|
+
return lib !== null;
|
|
17485
|
+
}
|
|
17486
|
+
async function runOcr(pageCanvases, options) {
|
|
17487
|
+
const lib = await loadTesseract();
|
|
17488
|
+
if (!lib) {
|
|
17489
|
+
throw new Error(
|
|
17490
|
+
"OCR is not available: tesseract.js could not be loaded. Ensure the tesseract.js package is installed."
|
|
17491
|
+
);
|
|
17492
|
+
}
|
|
17493
|
+
const warnings = [];
|
|
17494
|
+
const pages = [];
|
|
17495
|
+
const worker = await lib.createWorker("eng", 1, {
|
|
17496
|
+
logger: (m) => {
|
|
17497
|
+
if (options?.onProgress) {
|
|
17498
|
+
options.onProgress({
|
|
17499
|
+
progress: m.progress,
|
|
17500
|
+
status: m.status
|
|
17501
|
+
});
|
|
17502
|
+
}
|
|
17503
|
+
}
|
|
17504
|
+
});
|
|
17505
|
+
try {
|
|
17506
|
+
for (let i = 0; i < pageCanvases.length; i++) {
|
|
17507
|
+
const { pageNumber, canvas } = pageCanvases[i];
|
|
17508
|
+
const scaled = preScaleCanvas(canvas);
|
|
17509
|
+
const blob = await canvasToBlob(scaled);
|
|
17510
|
+
try {
|
|
17511
|
+
const { data } = await worker.recognize(blob);
|
|
17512
|
+
const text = data.text.trim();
|
|
17513
|
+
if (data.confidence < MIN_CONFIDENCE) {
|
|
17514
|
+
warnings.push(
|
|
17515
|
+
`Page ${pageNumber}: low OCR confidence (${Math.round(data.confidence)}%). Text quality may be poor.`
|
|
17516
|
+
);
|
|
17517
|
+
}
|
|
17518
|
+
pages.push({
|
|
17519
|
+
pageNumber,
|
|
17520
|
+
text: text || "",
|
|
17521
|
+
confidence: data.confidence
|
|
17522
|
+
});
|
|
17523
|
+
} catch (err) {
|
|
17524
|
+
warnings.push(
|
|
17525
|
+
`Page ${pageNumber}: OCR failed \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
17526
|
+
);
|
|
17527
|
+
pages.push({ pageNumber, text: "", confidence: 0 });
|
|
17528
|
+
}
|
|
17529
|
+
if (options?.onProgress) {
|
|
17530
|
+
options.onProgress({
|
|
17531
|
+
progress: (i + 1) / pageCanvases.length,
|
|
17532
|
+
status: `OCR page ${i + 1}/${pageCanvases.length}`
|
|
17533
|
+
});
|
|
17534
|
+
}
|
|
17535
|
+
}
|
|
17536
|
+
} finally {
|
|
17537
|
+
await worker.terminate();
|
|
17538
|
+
}
|
|
17539
|
+
return { pages, warnings };
|
|
17540
|
+
}
|
|
17541
|
+
var MAX_IMAGE_WIDTH, MIN_CONFIDENCE;
|
|
17542
|
+
var init_pdf_ocr_adapter = __esm({
|
|
17543
|
+
"../../src/shared/adapters/pdf-ocr-adapter.ts"() {
|
|
17544
|
+
init_feature_flags();
|
|
17545
|
+
MAX_IMAGE_WIDTH = 2e3;
|
|
17546
|
+
MIN_CONFIDENCE = 40;
|
|
17547
|
+
}
|
|
17548
|
+
});
|
|
17549
|
+
|
|
17412
17550
|
// ../../node_modules/@mozilla/readability/Readability.js
|
|
17413
17551
|
var require_Readability = __commonJS({
|
|
17414
17552
|
"../../node_modules/@mozilla/readability/Readability.js"(exports, module) {
|
|
@@ -19471,9 +19609,9 @@ var require_readability = __commonJS({
|
|
|
19471
19609
|
// src/shim.ts
|
|
19472
19610
|
import { parseHTML } from "linkedom";
|
|
19473
19611
|
import createDOMPurify from "dompurify";
|
|
19474
|
-
var { document, window: window2 } = parseHTML("<!DOCTYPE html><html><body></body></html>");
|
|
19612
|
+
var { document: document2, window: window2 } = parseHTML("<!DOCTYPE html><html><body></body></html>");
|
|
19475
19613
|
globalThis.window = window2;
|
|
19476
|
-
globalThis.document =
|
|
19614
|
+
globalThis.document = document2;
|
|
19477
19615
|
globalThis.DOMParser = window2.DOMParser;
|
|
19478
19616
|
globalThis.Node = window2.Node;
|
|
19479
19617
|
globalThis.HTMLElement = window2.HTMLElement;
|
|
@@ -21449,21 +21587,8 @@ var DocxAdapter = class {
|
|
|
21449
21587
|
};
|
|
21450
21588
|
var docxAdapter = new DocxAdapter();
|
|
21451
21589
|
|
|
21452
|
-
// ../../src/shared/
|
|
21453
|
-
|
|
21454
|
-
enableDocx: true,
|
|
21455
|
-
enableXlsx: true,
|
|
21456
|
-
enablePdf: true,
|
|
21457
|
-
enableHtml: true,
|
|
21458
|
-
enablePdfTableDetection: true,
|
|
21459
|
-
enableData: true,
|
|
21460
|
-
enablePptx: true,
|
|
21461
|
-
enablePdfEnhanced: true,
|
|
21462
|
-
enablePdfMultiColumn: true
|
|
21463
|
-
};
|
|
21464
|
-
function getFeatureFlags() {
|
|
21465
|
-
return { ..._flags };
|
|
21466
|
-
}
|
|
21590
|
+
// ../../src/shared/adapters/pdf-adapter.ts
|
|
21591
|
+
init_feature_flags();
|
|
21467
21592
|
|
|
21468
21593
|
// ../../src/shared/adapters/pdf-table-detector.ts
|
|
21469
21594
|
var CJK_REGEX = /[\u3400-\u9FFF\uF900-\uFAFF\u3040-\u30FF\uAC00-\uD7AF]/;
|
|
@@ -22424,6 +22549,58 @@ function dedupAgainstWidgets(textItems, widgets) {
|
|
|
22424
22549
|
}
|
|
22425
22550
|
return kept;
|
|
22426
22551
|
}
|
|
22552
|
+
function associateLabelsToWidgets(widgets, textItems) {
|
|
22553
|
+
if (widgets.length === 0 || textItems.length === 0) return [widgets, textItems];
|
|
22554
|
+
const consumedIndices = /* @__PURE__ */ new Set();
|
|
22555
|
+
const updatedWidgets = widgets.map((w) => {
|
|
22556
|
+
if (/^\[([ X]|Signed|Signature)\]$/.test(w.str)) return w;
|
|
22557
|
+
const refSize = Math.max(w.height, 10);
|
|
22558
|
+
const leftTolerance = refSize * 3;
|
|
22559
|
+
const aboveTolerance = refSize * 1;
|
|
22560
|
+
let bestCandidate = null;
|
|
22561
|
+
for (let i = 0; i < textItems.length; i++) {
|
|
22562
|
+
if (consumedIndices.has(i)) continue;
|
|
22563
|
+
const txt = textItems[i];
|
|
22564
|
+
const isToLeft = txt.right <= w.x + 2;
|
|
22565
|
+
if (isToLeft) {
|
|
22566
|
+
const hGap = w.x - txt.right;
|
|
22567
|
+
if (hGap <= leftTolerance) {
|
|
22568
|
+
const yOverlap = Math.min(txt.y + txt.height, w.y + w.height) - Math.max(txt.y, w.y);
|
|
22569
|
+
const minH = Math.min(txt.height, w.height);
|
|
22570
|
+
if (yOverlap / minH >= 0.5) {
|
|
22571
|
+
const score = hGap;
|
|
22572
|
+
if (!bestCandidate || score < bestCandidate.score) {
|
|
22573
|
+
bestCandidate = { idx: i, str: txt.str, score };
|
|
22574
|
+
}
|
|
22575
|
+
}
|
|
22576
|
+
}
|
|
22577
|
+
}
|
|
22578
|
+
if (!isToLeft) {
|
|
22579
|
+
const widgetTop = w.y + w.height;
|
|
22580
|
+
const labelBottom = txt.y;
|
|
22581
|
+
const vGap = labelBottom - widgetTop;
|
|
22582
|
+
if (vGap >= 0 && vGap <= aboveTolerance) {
|
|
22583
|
+
const xOverlap = Math.min(txt.right, w.right) - Math.max(txt.x, w.x);
|
|
22584
|
+
if (xOverlap > 0) {
|
|
22585
|
+
const score = vGap;
|
|
22586
|
+
if (!bestCandidate || score < bestCandidate.score) {
|
|
22587
|
+
bestCandidate = { idx: i, str: txt.str, score };
|
|
22588
|
+
}
|
|
22589
|
+
}
|
|
22590
|
+
}
|
|
22591
|
+
}
|
|
22592
|
+
}
|
|
22593
|
+
if (bestCandidate) {
|
|
22594
|
+
consumedIndices.add(bestCandidate.idx);
|
|
22595
|
+
const labelStr = bestCandidate.str.trimEnd();
|
|
22596
|
+
const separator = /[::]\s*$/.test(labelStr) ? " " : ": ";
|
|
22597
|
+
return { ...w, str: `${labelStr}${separator}${w.str}` };
|
|
22598
|
+
}
|
|
22599
|
+
return w;
|
|
22600
|
+
});
|
|
22601
|
+
const remainingText = textItems.filter((_, i) => !consumedIndices.has(i));
|
|
22602
|
+
return [updatedWidgets, remainingText];
|
|
22603
|
+
}
|
|
22427
22604
|
function itemsToLinearText(items) {
|
|
22428
22605
|
if (items.length === 0) return "";
|
|
22429
22606
|
const sorted = [...items].sort((a, b) => b.y + b.height - (a.y + a.height) || a.x - b.x);
|
|
@@ -23044,8 +23221,9 @@ var PdfAdapter = class {
|
|
|
23044
23221
|
onProgress?.(pageNum / numPages);
|
|
23045
23222
|
const page = await pdf.getPage(pageNum);
|
|
23046
23223
|
const viewport = page.getViewport({ scale: 1 });
|
|
23224
|
+
const useMarkedContent = getFeatureFlags().enablePdfEnhanced && isTaggedPdf;
|
|
23047
23225
|
const [textContent, annotations] = await Promise.all([
|
|
23048
|
-
page.getTextContent(),
|
|
23226
|
+
page.getTextContent(useMarkedContent ? { includeMarkedContent: true } : void 0),
|
|
23049
23227
|
page.getAnnotations().catch((err) => {
|
|
23050
23228
|
console.warn(`[PdfAdapter] getAnnotations failed for page ${pageNum}:`, err);
|
|
23051
23229
|
return [];
|
|
@@ -23053,10 +23231,23 @@ var PdfAdapter = class {
|
|
|
23053
23231
|
]);
|
|
23054
23232
|
const positionedText = [];
|
|
23055
23233
|
const xPositions = [];
|
|
23234
|
+
let currentMcid;
|
|
23056
23235
|
for (const item of textContent.items) {
|
|
23236
|
+
const itemType = "type" in item ? item.type : void 0;
|
|
23237
|
+
if (itemType === "beginMarkedContentProps") {
|
|
23238
|
+
currentMcid = item.id?.toString();
|
|
23239
|
+
continue;
|
|
23240
|
+
}
|
|
23241
|
+
if (itemType === "endMarkedContent") {
|
|
23242
|
+
currentMcid = void 0;
|
|
23243
|
+
continue;
|
|
23244
|
+
}
|
|
23057
23245
|
if (!("str" in item) || typeof item.str !== "string") continue;
|
|
23058
23246
|
const positioned = textItemToPositioned(item);
|
|
23059
23247
|
if (!positioned) continue;
|
|
23248
|
+
if (currentMcid !== void 0) {
|
|
23249
|
+
positioned.mcid = currentMcid;
|
|
23250
|
+
}
|
|
23060
23251
|
positionedText.push(positioned);
|
|
23061
23252
|
xPositions.push(positioned.x);
|
|
23062
23253
|
}
|
|
@@ -23064,45 +23255,104 @@ var PdfAdapter = class {
|
|
|
23064
23255
|
...annotations.flatMap(widgetToPositionedItems),
|
|
23065
23256
|
...groupRadioButtons(annotations)
|
|
23066
23257
|
];
|
|
23067
|
-
|
|
23258
|
+
let items;
|
|
23259
|
+
if (widgetItems.length > 0) {
|
|
23260
|
+
const dedupedText = dedupAgainstWidgets(positionedText, widgetItems);
|
|
23261
|
+
const [labelledWidgets, remainingText] = associateLabelsToWidgets(widgetItems, dedupedText);
|
|
23262
|
+
items = [...remainingText, ...labelledWidgets];
|
|
23263
|
+
} else {
|
|
23264
|
+
items = positionedText;
|
|
23265
|
+
}
|
|
23068
23266
|
if (getFeatureFlags().enablePdfEnhanced) {
|
|
23069
23267
|
applyLinkAnnotations(items, annotations);
|
|
23070
23268
|
}
|
|
23071
23269
|
const renderItems = getFeatureFlags().enablePdfEnhanced && hfSuppressSet.size > 0 ? items.filter((it) => !isHeaderFooterItem(it, hfSuppressSet)) : items;
|
|
23072
23270
|
if (getFeatureFlags().enablePdfEnhanced && isTaggedPdf) {
|
|
23073
23271
|
let structHtml = null;
|
|
23272
|
+
let claimedMcids = null;
|
|
23074
23273
|
try {
|
|
23075
23274
|
if (hasStructTree(page)) {
|
|
23076
23275
|
const structResult = await structTreeToHtml(page);
|
|
23077
23276
|
if (structResult !== null) {
|
|
23078
23277
|
structHtml = structResult.html;
|
|
23278
|
+
claimedMcids = structResult.claimedMcids;
|
|
23079
23279
|
}
|
|
23080
23280
|
}
|
|
23081
23281
|
} catch {
|
|
23082
23282
|
}
|
|
23083
|
-
|
|
23084
|
-
|
|
23085
|
-
|
|
23086
|
-
|
|
23087
|
-
|
|
23283
|
+
let fusionStructHtml = null;
|
|
23284
|
+
let fusionClaimedMcids = null;
|
|
23285
|
+
if (structHtml !== null && claimedMcids !== null) {
|
|
23286
|
+
const textItems = renderItems.filter((it) => it.source !== "acroform");
|
|
23287
|
+
const covered = textItems.filter((it) => it.mcid != null && claimedMcids.has(it.mcid)).length;
|
|
23288
|
+
const coverage = covered / Math.max(textItems.length, 1);
|
|
23289
|
+
if (coverage >= 0.7) {
|
|
23290
|
+
const plainText = structHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
23291
|
+
totalTextLength += plainText.length;
|
|
23292
|
+
let hasImages2 = false;
|
|
23293
|
+
try {
|
|
23294
|
+
const opList = await page.getOperatorList();
|
|
23295
|
+
hasImages2 = opList.fnArray.some((op) => op === 85 || op === 86);
|
|
23296
|
+
} catch {
|
|
23297
|
+
}
|
|
23298
|
+
pages.push({
|
|
23299
|
+
pageNumber: pageNum,
|
|
23300
|
+
textContent: plainText,
|
|
23301
|
+
hasImages: hasImages2,
|
|
23302
|
+
viewportWidth: viewport.width,
|
|
23303
|
+
htmlBlocks: [structHtml],
|
|
23304
|
+
tablesDetected: 0
|
|
23305
|
+
});
|
|
23306
|
+
continue;
|
|
23307
|
+
} else if (coverage > 0) {
|
|
23308
|
+
fusionStructHtml = structHtml;
|
|
23309
|
+
fusionClaimedMcids = claimedMcids;
|
|
23088
23310
|
}
|
|
23089
23311
|
}
|
|
23090
|
-
if (
|
|
23091
|
-
const
|
|
23092
|
-
|
|
23093
|
-
|
|
23312
|
+
if (fusionStructHtml !== null && fusionClaimedMcids !== null) {
|
|
23313
|
+
const unclaimedItems = renderItems.filter(
|
|
23314
|
+
(it) => !it.mcid || !fusionClaimedMcids.has(it.mcid)
|
|
23315
|
+
);
|
|
23316
|
+
const fsSamples = unclaimedItems.map((it) => it.fontSize ?? 0).filter((f) => f > 0);
|
|
23317
|
+
const medianFontSize = fsSamples.length > 0 ? [...fsSamples].sort((a, b) => a - b)[Math.floor(fsSamples.length / 2)] : 12;
|
|
23318
|
+
const fusionEnhancedOpts = getFeatureFlags().enablePdfEnhanced ? { medianFontSize, outlineTitles } : void 0;
|
|
23319
|
+
const pageBottomY2 = Array.isArray(page.view) && page.view.length >= 2 ? page.view[1] : 0;
|
|
23320
|
+
let pageOpList2;
|
|
23321
|
+
let ruleSeparators2;
|
|
23094
23322
|
try {
|
|
23095
|
-
|
|
23096
|
-
|
|
23323
|
+
pageOpList2 = await page.getOperatorList();
|
|
23324
|
+
if (getFeatureFlags().enablePdfEnhanced && tableDetectionEnabled) {
|
|
23325
|
+
ruleSeparators2 = extractVectorLines(
|
|
23326
|
+
pageOpList2.fnArray,
|
|
23327
|
+
pageOpList2.argsArray ?? [],
|
|
23328
|
+
viewport.width,
|
|
23329
|
+
viewport.height
|
|
23330
|
+
);
|
|
23331
|
+
}
|
|
23097
23332
|
} catch {
|
|
23098
23333
|
}
|
|
23334
|
+
const rendered2 = renderPage(
|
|
23335
|
+
unclaimedItems,
|
|
23336
|
+
pageNum,
|
|
23337
|
+
pageNum < numPages ? pageNum + 1 : void 0,
|
|
23338
|
+
tableDetectionEnabled,
|
|
23339
|
+
translate,
|
|
23340
|
+
pageBottomY2,
|
|
23341
|
+
fusionEnhancedOpts,
|
|
23342
|
+
ruleSeparators2
|
|
23343
|
+
);
|
|
23344
|
+
for (const w of rendered2.warnings) warnings.push(w);
|
|
23345
|
+
const structPlainText = fusionStructHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
23346
|
+
totalTextLength += structPlainText.length + rendered2.textContent.length;
|
|
23347
|
+
const hasImages2 = pageOpList2?.fnArray.some((op) => op === 85 || op === 86) ?? false;
|
|
23348
|
+
const mergedHtmlBlocks = [fusionStructHtml, ...rendered2.htmlBlocks];
|
|
23099
23349
|
pages.push({
|
|
23100
23350
|
pageNumber: pageNum,
|
|
23101
|
-
textContent:
|
|
23351
|
+
textContent: structPlainText + "\n" + rendered2.textContent,
|
|
23102
23352
|
hasImages: hasImages2,
|
|
23103
23353
|
viewportWidth: viewport.width,
|
|
23104
|
-
htmlBlocks:
|
|
23105
|
-
tablesDetected:
|
|
23354
|
+
htmlBlocks: mergedHtmlBlocks,
|
|
23355
|
+
tablesDetected: rendered2.tablesDetected
|
|
23106
23356
|
});
|
|
23107
23357
|
continue;
|
|
23108
23358
|
}
|
|
@@ -23174,6 +23424,12 @@ var PdfAdapter = class {
|
|
|
23174
23424
|
const hasNoText = totalTextLength === 0;
|
|
23175
23425
|
const hasMinimalTextWithImages = totalTextLength < MIN_TEXT_CHARS_THRESHOLD && hasAnyImages;
|
|
23176
23426
|
if (hasNoText || hasMinimalTextWithImages) {
|
|
23427
|
+
if (getFeatureFlags().enablePdfOcr) {
|
|
23428
|
+
const ocrResult = await this.runOcrOnPages(pdf, numPages);
|
|
23429
|
+
if (ocrResult !== null) {
|
|
23430
|
+
return ocrResult;
|
|
23431
|
+
}
|
|
23432
|
+
}
|
|
23177
23433
|
throw new PdfParseError(
|
|
23178
23434
|
"PDF contains only images \u2014 no text layer available.",
|
|
23179
23435
|
"IMAGE_ONLY"
|
|
@@ -23279,6 +23535,65 @@ var PdfAdapter = class {
|
|
|
23279
23535
|
}
|
|
23280
23536
|
}
|
|
23281
23537
|
}
|
|
23538
|
+
/**
|
|
23539
|
+
* Attempt OCR extraction on all pages of an image-only PDF.
|
|
23540
|
+
*
|
|
23541
|
+
* Renders each page to a canvas, passes them to Tesseract.js (lazy-loaded),
|
|
23542
|
+
* and returns a standard PdfParseResult if text is found.
|
|
23543
|
+
*
|
|
23544
|
+
* Returns null if:
|
|
23545
|
+
* - Tesseract.js cannot be loaded
|
|
23546
|
+
* - OCR produces no usable text across all pages
|
|
23547
|
+
*/
|
|
23548
|
+
async runOcrOnPages(pdf, numPages) {
|
|
23549
|
+
const { isOcrAvailable: isOcrAvailable2, runOcr: runOcr2 } = await Promise.resolve().then(() => (init_pdf_ocr_adapter(), pdf_ocr_adapter_exports));
|
|
23550
|
+
if (!await isOcrAvailable2()) {
|
|
23551
|
+
return null;
|
|
23552
|
+
}
|
|
23553
|
+
const SCALE = 2;
|
|
23554
|
+
const pageCanvases = [];
|
|
23555
|
+
const viewportWidths = /* @__PURE__ */ new Map();
|
|
23556
|
+
for (let pageNum = 1; pageNum <= numPages; pageNum++) {
|
|
23557
|
+
const page = await pdf.getPage(pageNum);
|
|
23558
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
23559
|
+
viewportWidths.set(pageNum, viewport.width);
|
|
23560
|
+
const renderViewport = page.getViewport({ scale: SCALE });
|
|
23561
|
+
const canvas = document.createElement("canvas");
|
|
23562
|
+
canvas.width = renderViewport.width;
|
|
23563
|
+
canvas.height = renderViewport.height;
|
|
23564
|
+
const ctx = canvas.getContext("2d");
|
|
23565
|
+
if (!ctx) continue;
|
|
23566
|
+
await page.render({ canvasContext: ctx, viewport: renderViewport }).promise;
|
|
23567
|
+
pageCanvases.push({ pageNumber: pageNum, canvas });
|
|
23568
|
+
}
|
|
23569
|
+
if (pageCanvases.length === 0) return null;
|
|
23570
|
+
const ocrResult = await runOcr2(pageCanvases);
|
|
23571
|
+
const pagesWithText = ocrResult.pages.filter((p) => p.text.length > 0);
|
|
23572
|
+
if (pagesWithText.length === 0) return null;
|
|
23573
|
+
const ocrPages = ocrResult.pages.map((p) => ({
|
|
23574
|
+
pageNumber: p.pageNumber,
|
|
23575
|
+
textContent: p.text,
|
|
23576
|
+
hasImages: true,
|
|
23577
|
+
viewportWidth: viewportWidths.get(p.pageNumber),
|
|
23578
|
+
tablesDetected: 0
|
|
23579
|
+
}));
|
|
23580
|
+
const html = this.pagesToHtml(ocrPages);
|
|
23581
|
+
const allWarnings = [
|
|
23582
|
+
"OCR was used to extract text from this image-only PDF. Quality may vary.",
|
|
23583
|
+
...ocrResult.warnings
|
|
23584
|
+
];
|
|
23585
|
+
return {
|
|
23586
|
+
html,
|
|
23587
|
+
pages: ocrPages,
|
|
23588
|
+
metadata: {
|
|
23589
|
+
isTextBased: false,
|
|
23590
|
+
isOcrBased: true,
|
|
23591
|
+
pageCount: numPages
|
|
23592
|
+
},
|
|
23593
|
+
isTextBased: false,
|
|
23594
|
+
warnings: allWarnings
|
|
23595
|
+
};
|
|
23596
|
+
}
|
|
23282
23597
|
};
|
|
23283
23598
|
var pdfAdapter = new PdfAdapter();
|
|
23284
23599
|
|
|
@@ -24682,12 +24997,12 @@ var ToonifyService = class {
|
|
|
24682
24997
|
};
|
|
24683
24998
|
}
|
|
24684
24999
|
const blocks = this.parseMarkdown(markdown, opts);
|
|
24685
|
-
const
|
|
25000
|
+
const document3 = { t: "md", blocks };
|
|
24686
25001
|
const encodeOptions = {
|
|
24687
25002
|
keyFolding: opts.keyFolding,
|
|
24688
25003
|
tableFormat: opts.tableFormat
|
|
24689
25004
|
};
|
|
24690
|
-
const compressed = ToonEncoder.encode(
|
|
25005
|
+
const compressed = ToonEncoder.encode(document3, encodeOptions);
|
|
24691
25006
|
const compressedTokenEstimate = estimateTokens(compressed);
|
|
24692
25007
|
const reductionPercent = originalTokenEstimate > 0 ? Math.max(0, Math.min(100, Math.round(
|
|
24693
25008
|
(originalTokenEstimate - compressedTokenEstimate) / originalTokenEstimate * 100
|
|
@@ -25505,8 +25820,8 @@ import { readFileSync as readFileSync4 } from "fs";
|
|
|
25505
25820
|
import { resolve, dirname as dirname3 } from "path";
|
|
25506
25821
|
import { fileURLToPath } from "url";
|
|
25507
25822
|
var getVersion = () => {
|
|
25508
|
-
if ("1.0.
|
|
25509
|
-
return "1.0.
|
|
25823
|
+
if ("1.0.26") {
|
|
25824
|
+
return "1.0.26";
|
|
25510
25825
|
}
|
|
25511
25826
|
try {
|
|
25512
25827
|
const __dirname = dirname3(fileURLToPath(import.meta.url));
|