formatferry 1.0.23 → 1.0.25

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.
Files changed (2) hide show
  1. package/dist/index.js +317 -56
  2. 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(document2, args) {
2799
- var docFrag = document2.createDocumentFragment();
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 : document2.createTextNode(String(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 document2 = this.ownerDocument;
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 = document2.implementation.mozHTMLParser(
3083
- document2._address,
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, document2, form, element) {
5675
+ function EventHandlerBuilder(body, document3, form, element) {
5669
5676
  this.body = body;
5670
- this.document = document2;
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(document2) {
16546
- this.document = document2 || new DOMImplementation(null).createHTMLDocument("");
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 document2 = exports.createDocument(html);
16684
+ var document3 = exports.createDocument(html);
16678
16685
  if (address !== void 0) {
16679
- document2._address = address;
16686
+ document3._address = address;
16680
16687
  }
16681
- return new impl.Window(document2);
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 = 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/feature-flags.ts
21453
- var _flags = {
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]/;
@@ -22089,17 +22214,18 @@ function esc(str) {
22089
22214
  function isContent(node) {
22090
22215
  return "id" in node && !("role" in node);
22091
22216
  }
22092
- function walkChildren(children, mcidMap, depth) {
22093
- return children.map((c) => walkNode(c, mcidMap, depth)).join("");
22217
+ function walkChildren(children, mcidMap, depth, visitedMcids) {
22218
+ return children.map((c) => walkNode(c, mcidMap, depth, visitedMcids)).join("");
22094
22219
  }
22095
- function walkNode(node, mcidMap, depth = 0) {
22220
+ function walkNode(node, mcidMap, depth = 0, visitedMcids = /* @__PURE__ */ new Set()) {
22096
22221
  if (depth > 50) return "";
22097
22222
  if (isContent(node)) {
22223
+ visitedMcids.add(node.id);
22098
22224
  const text = mcidMap.get(node.id) ?? "";
22099
22225
  return esc(text);
22100
22226
  }
22101
22227
  const children = node.children ?? [];
22102
- const inner = walkChildren(children, mcidMap, depth + 1);
22228
+ const inner = walkChildren(children, mcidMap, depth + 1, visitedMcids);
22103
22229
  switch (node.role) {
22104
22230
  case "H":
22105
22231
  return `<h1>${inner}</h1>`;
@@ -22182,10 +22308,11 @@ async function structTreeToHtml(page) {
22182
22308
  return null;
22183
22309
  }
22184
22310
  const mcidMap = buildMcidMap(textContent.items);
22185
- const html = walkNode(structTree, mcidMap);
22311
+ const claimedMcids = /* @__PURE__ */ new Set();
22312
+ const html = walkNode(structTree, mcidMap, 0, claimedMcids);
22186
22313
  const textOnly = html.replace(/<[^>]+>/g, "").trim();
22187
22314
  if (!textOnly) return null;
22188
- return html;
22315
+ return { html, claimedMcids };
22189
22316
  }
22190
22317
 
22191
22318
  // ../../src/shared/adapters/pdf-adapter.ts
@@ -23042,8 +23169,9 @@ var PdfAdapter = class {
23042
23169
  onProgress?.(pageNum / numPages);
23043
23170
  const page = await pdf.getPage(pageNum);
23044
23171
  const viewport = page.getViewport({ scale: 1 });
23172
+ const useMarkedContent = getFeatureFlags().enablePdfEnhanced && isTaggedPdf;
23045
23173
  const [textContent, annotations] = await Promise.all([
23046
- page.getTextContent(),
23174
+ page.getTextContent(useMarkedContent ? { includeMarkedContent: true } : void 0),
23047
23175
  page.getAnnotations().catch((err) => {
23048
23176
  console.warn(`[PdfAdapter] getAnnotations failed for page ${pageNum}:`, err);
23049
23177
  return [];
@@ -23051,10 +23179,23 @@ var PdfAdapter = class {
23051
23179
  ]);
23052
23180
  const positionedText = [];
23053
23181
  const xPositions = [];
23182
+ let currentMcid;
23054
23183
  for (const item of textContent.items) {
23184
+ const itemType = "type" in item ? item.type : void 0;
23185
+ if (itemType === "beginMarkedContentProps") {
23186
+ currentMcid = item.id?.toString();
23187
+ continue;
23188
+ }
23189
+ if (itemType === "endMarkedContent") {
23190
+ currentMcid = void 0;
23191
+ continue;
23192
+ }
23055
23193
  if (!("str" in item) || typeof item.str !== "string") continue;
23056
23194
  const positioned = textItemToPositioned(item);
23057
23195
  if (!positioned) continue;
23196
+ if (currentMcid !== void 0) {
23197
+ positioned.mcid = currentMcid;
23198
+ }
23058
23199
  positionedText.push(positioned);
23059
23200
  xPositions.push(positioned.x);
23060
23201
  }
@@ -23069,35 +23210,90 @@ var PdfAdapter = class {
23069
23210
  const renderItems = getFeatureFlags().enablePdfEnhanced && hfSuppressSet.size > 0 ? items.filter((it) => !isHeaderFooterItem(it, hfSuppressSet)) : items;
23070
23211
  if (getFeatureFlags().enablePdfEnhanced && isTaggedPdf) {
23071
23212
  let structHtml = null;
23213
+ let claimedMcids = null;
23072
23214
  try {
23073
23215
  if (hasStructTree(page)) {
23074
- structHtml = await structTreeToHtml(page);
23216
+ const structResult = await structTreeToHtml(page);
23217
+ if (structResult !== null) {
23218
+ structHtml = structResult.html;
23219
+ claimedMcids = structResult.claimedMcids;
23220
+ }
23075
23221
  }
23076
23222
  } catch {
23077
23223
  }
23078
- if (structHtml !== null) {
23079
- const structTextLen = structHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim().length;
23080
- const geoTextLen = renderItems.map((it) => it.str).join(" ").length;
23081
- if (geoTextLen > 0 && structTextLen / geoTextLen < 0.7) {
23082
- structHtml = null;
23224
+ let fusionStructHtml = null;
23225
+ let fusionClaimedMcids = null;
23226
+ if (structHtml !== null && claimedMcids !== null) {
23227
+ const textItems = renderItems.filter((it) => it.source !== "acroform");
23228
+ const covered = textItems.filter((it) => it.mcid != null && claimedMcids.has(it.mcid)).length;
23229
+ const coverage = covered / Math.max(textItems.length, 1);
23230
+ if (coverage >= 0.7) {
23231
+ const plainText = structHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
23232
+ totalTextLength += plainText.length;
23233
+ let hasImages2 = false;
23234
+ try {
23235
+ const opList = await page.getOperatorList();
23236
+ hasImages2 = opList.fnArray.some((op) => op === 85 || op === 86);
23237
+ } catch {
23238
+ }
23239
+ pages.push({
23240
+ pageNumber: pageNum,
23241
+ textContent: plainText,
23242
+ hasImages: hasImages2,
23243
+ viewportWidth: viewport.width,
23244
+ htmlBlocks: [structHtml],
23245
+ tablesDetected: 0
23246
+ });
23247
+ continue;
23248
+ } else if (coverage > 0) {
23249
+ fusionStructHtml = structHtml;
23250
+ fusionClaimedMcids = claimedMcids;
23083
23251
  }
23084
23252
  }
23085
- if (structHtml !== null) {
23086
- const plainText = structHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
23087
- totalTextLength += plainText.length;
23088
- let hasImages2 = false;
23253
+ if (fusionStructHtml !== null && fusionClaimedMcids !== null) {
23254
+ const unclaimedItems = renderItems.filter(
23255
+ (it) => !it.mcid || !fusionClaimedMcids.has(it.mcid)
23256
+ );
23257
+ const fsSamples = unclaimedItems.map((it) => it.fontSize ?? 0).filter((f) => f > 0);
23258
+ const medianFontSize = fsSamples.length > 0 ? [...fsSamples].sort((a, b) => a - b)[Math.floor(fsSamples.length / 2)] : 12;
23259
+ const fusionEnhancedOpts = getFeatureFlags().enablePdfEnhanced ? { medianFontSize, outlineTitles } : void 0;
23260
+ const pageBottomY2 = Array.isArray(page.view) && page.view.length >= 2 ? page.view[1] : 0;
23261
+ let pageOpList2;
23262
+ let ruleSeparators2;
23089
23263
  try {
23090
- const opList = await page.getOperatorList();
23091
- hasImages2 = opList.fnArray.some((op) => op === 85 || op === 86);
23264
+ pageOpList2 = await page.getOperatorList();
23265
+ if (getFeatureFlags().enablePdfEnhanced && tableDetectionEnabled) {
23266
+ ruleSeparators2 = extractVectorLines(
23267
+ pageOpList2.fnArray,
23268
+ pageOpList2.argsArray ?? [],
23269
+ viewport.width,
23270
+ viewport.height
23271
+ );
23272
+ }
23092
23273
  } catch {
23093
23274
  }
23275
+ const rendered2 = renderPage(
23276
+ unclaimedItems,
23277
+ pageNum,
23278
+ pageNum < numPages ? pageNum + 1 : void 0,
23279
+ tableDetectionEnabled,
23280
+ translate,
23281
+ pageBottomY2,
23282
+ fusionEnhancedOpts,
23283
+ ruleSeparators2
23284
+ );
23285
+ for (const w of rendered2.warnings) warnings.push(w);
23286
+ const structPlainText = fusionStructHtml.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
23287
+ totalTextLength += structPlainText.length + rendered2.textContent.length;
23288
+ const hasImages2 = pageOpList2?.fnArray.some((op) => op === 85 || op === 86) ?? false;
23289
+ const mergedHtmlBlocks = [fusionStructHtml, ...rendered2.htmlBlocks];
23094
23290
  pages.push({
23095
23291
  pageNumber: pageNum,
23096
- textContent: plainText,
23292
+ textContent: structPlainText + "\n" + rendered2.textContent,
23097
23293
  hasImages: hasImages2,
23098
23294
  viewportWidth: viewport.width,
23099
- htmlBlocks: [structHtml],
23100
- tablesDetected: 0
23295
+ htmlBlocks: mergedHtmlBlocks,
23296
+ tablesDetected: rendered2.tablesDetected
23101
23297
  });
23102
23298
  continue;
23103
23299
  }
@@ -23169,6 +23365,12 @@ var PdfAdapter = class {
23169
23365
  const hasNoText = totalTextLength === 0;
23170
23366
  const hasMinimalTextWithImages = totalTextLength < MIN_TEXT_CHARS_THRESHOLD && hasAnyImages;
23171
23367
  if (hasNoText || hasMinimalTextWithImages) {
23368
+ if (getFeatureFlags().enablePdfOcr) {
23369
+ const ocrResult = await this.runOcrOnPages(pdf, numPages);
23370
+ if (ocrResult !== null) {
23371
+ return ocrResult;
23372
+ }
23373
+ }
23172
23374
  throw new PdfParseError(
23173
23375
  "PDF contains only images \u2014 no text layer available.",
23174
23376
  "IMAGE_ONLY"
@@ -23274,6 +23476,65 @@ var PdfAdapter = class {
23274
23476
  }
23275
23477
  }
23276
23478
  }
23479
+ /**
23480
+ * Attempt OCR extraction on all pages of an image-only PDF.
23481
+ *
23482
+ * Renders each page to a canvas, passes them to Tesseract.js (lazy-loaded),
23483
+ * and returns a standard PdfParseResult if text is found.
23484
+ *
23485
+ * Returns null if:
23486
+ * - Tesseract.js cannot be loaded
23487
+ * - OCR produces no usable text across all pages
23488
+ */
23489
+ async runOcrOnPages(pdf, numPages) {
23490
+ const { isOcrAvailable: isOcrAvailable2, runOcr: runOcr2 } = await Promise.resolve().then(() => (init_pdf_ocr_adapter(), pdf_ocr_adapter_exports));
23491
+ if (!await isOcrAvailable2()) {
23492
+ return null;
23493
+ }
23494
+ const SCALE = 2;
23495
+ const pageCanvases = [];
23496
+ const viewportWidths = /* @__PURE__ */ new Map();
23497
+ for (let pageNum = 1; pageNum <= numPages; pageNum++) {
23498
+ const page = await pdf.getPage(pageNum);
23499
+ const viewport = page.getViewport({ scale: 1 });
23500
+ viewportWidths.set(pageNum, viewport.width);
23501
+ const renderViewport = page.getViewport({ scale: SCALE });
23502
+ const canvas = document.createElement("canvas");
23503
+ canvas.width = renderViewport.width;
23504
+ canvas.height = renderViewport.height;
23505
+ const ctx = canvas.getContext("2d");
23506
+ if (!ctx) continue;
23507
+ await page.render({ canvasContext: ctx, viewport: renderViewport }).promise;
23508
+ pageCanvases.push({ pageNumber: pageNum, canvas });
23509
+ }
23510
+ if (pageCanvases.length === 0) return null;
23511
+ const ocrResult = await runOcr2(pageCanvases);
23512
+ const pagesWithText = ocrResult.pages.filter((p) => p.text.length > 0);
23513
+ if (pagesWithText.length === 0) return null;
23514
+ const ocrPages = ocrResult.pages.map((p) => ({
23515
+ pageNumber: p.pageNumber,
23516
+ textContent: p.text,
23517
+ hasImages: true,
23518
+ viewportWidth: viewportWidths.get(p.pageNumber),
23519
+ tablesDetected: 0
23520
+ }));
23521
+ const html = this.pagesToHtml(ocrPages);
23522
+ const allWarnings = [
23523
+ "OCR was used to extract text from this image-only PDF. Quality may vary.",
23524
+ ...ocrResult.warnings
23525
+ ];
23526
+ return {
23527
+ html,
23528
+ pages: ocrPages,
23529
+ metadata: {
23530
+ isTextBased: false,
23531
+ isOcrBased: true,
23532
+ pageCount: numPages
23533
+ },
23534
+ isTextBased: false,
23535
+ warnings: allWarnings
23536
+ };
23537
+ }
23277
23538
  };
23278
23539
  var pdfAdapter = new PdfAdapter();
23279
23540
 
@@ -24677,12 +24938,12 @@ var ToonifyService = class {
24677
24938
  };
24678
24939
  }
24679
24940
  const blocks = this.parseMarkdown(markdown, opts);
24680
- const document2 = { t: "md", blocks };
24941
+ const document3 = { t: "md", blocks };
24681
24942
  const encodeOptions = {
24682
24943
  keyFolding: opts.keyFolding,
24683
24944
  tableFormat: opts.tableFormat
24684
24945
  };
24685
- const compressed = ToonEncoder.encode(document2, encodeOptions);
24946
+ const compressed = ToonEncoder.encode(document3, encodeOptions);
24686
24947
  const compressedTokenEstimate = estimateTokens(compressed);
24687
24948
  const reductionPercent = originalTokenEstimate > 0 ? Math.max(0, Math.min(100, Math.round(
24688
24949
  (originalTokenEstimate - compressedTokenEstimate) / originalTokenEstimate * 100
@@ -25500,8 +25761,8 @@ import { readFileSync as readFileSync4 } from "fs";
25500
25761
  import { resolve, dirname as dirname3 } from "path";
25501
25762
  import { fileURLToPath } from "url";
25502
25763
  var getVersion = () => {
25503
- if ("1.0.23") {
25504
- return "1.0.23";
25764
+ if ("1.0.25") {
25765
+ return "1.0.25";
25505
25766
  }
25506
25767
  try {
25507
25768
  const __dirname = dirname3(fileURLToPath(import.meta.url));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formatferry",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "FormatFerry CLI — Convert HTML, DOCX, PDF, XLSX, CSV, JSON, XML, PPTX to Markdown",
5
5
  "keywords": [
6
6
  "markdown",