extract-pdf 0.1.0
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/README.md +68 -0
- package/dist/pdf-to-html.cjs.js +1 -0
- package/dist/pdf-to-html.d.ts +41 -0
- package/dist/pdf-to-html.es.js +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# pdf-to-html
|
|
2
|
+
|
|
3
|
+
Converts a PDF (URL or `ArrayBuffer`) into clean HTML with structural tagging — headings, lists, footnotes, code blocks, bold/italic, and Table of Contents entries. Works in Node.js, Cloudflare Workers, and browser environments via [pdfjs-serverless](https://github.com/johannschopplich/pdfjs-serverless).
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { convertPDFToHTML } from "./pdf-to-html";
|
|
9
|
+
|
|
10
|
+
const { html, title, author } = await convertPDFToHTML(
|
|
11
|
+
"https://example.com/paper.pdf",
|
|
12
|
+
);
|
|
13
|
+
// or pass an ArrayBuffer from fs.readFile / fetch
|
|
14
|
+
const { html } = await convertPDFToHTML(buffer, { addPageNumbers: true });
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Options
|
|
18
|
+
|
|
19
|
+
| Option | Default | Description |
|
|
20
|
+
| ---------------- | ------- | ------------------------------------------------------------------------------------------ |
|
|
21
|
+
| `addPageNumbers` | `false` | Inserts `[n]` markers at each page boundary |
|
|
22
|
+
| `addCitation` | `true` | Reads PDF metadata and first-page heading to populate `title`/`author` in the return value |
|
|
23
|
+
|
|
24
|
+
### Return value
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
{ html: string, title?: string, author?: string, format: "pdf" }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Pipeline
|
|
31
|
+
|
|
32
|
+
The conversion runs a sequential chain of transformations on a `ParseResult` (pages → items):
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Raw pdfjs text spans
|
|
36
|
+
→ CalculateGlobalStats — font heights, distances, format map
|
|
37
|
+
→ CompactLines — merge spans on the same y-line into LineItems
|
|
38
|
+
→ RemoveRepetitiveElements — strip recurring page headers/footers
|
|
39
|
+
→ VerticalToHorizontal — rotate vertical character runs
|
|
40
|
+
→ DetectTOC — identify Table of Contents pages, link headings
|
|
41
|
+
→ DetectHeaders — classify items as H1–H6 by font height
|
|
42
|
+
→ DetectListItems — detect bullet/numbered list items
|
|
43
|
+
→ GatherBlocks — group adjacent same-type lines into blocks
|
|
44
|
+
→ DetectCodeQuoteBlocks — mark indented blocks as CODE
|
|
45
|
+
→ DetectListLevels — add indentation for nested list levels
|
|
46
|
+
→ ToTextBlocks — flatten blocks to { category, text } pairs
|
|
47
|
+
→ ToHTML — render pairs as <p>, <h1>–<h6>, <ul>, <code>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Folder structure
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
pdf-to-html/
|
|
54
|
+
pdf-to-html.ts — main entry point (convertPDFToHTML)
|
|
55
|
+
models/ — data classes: Page, ParseResult, TextItem,
|
|
56
|
+
│ LineItem, LineItemBlock, Word, BlockType, …
|
|
57
|
+
transformations/
|
|
58
|
+
│ Transformation.ts — abstract base
|
|
59
|
+
│ CalculateGlobalStats.ts
|
|
60
|
+
│ ToTextBlocks.ts
|
|
61
|
+
│ ToHTML.ts
|
|
62
|
+
│ line-item/ — per-line-item transformations
|
|
63
|
+
│ line-item-block/ — per-block transformations
|
|
64
|
+
util/
|
|
65
|
+
string-functions.ts
|
|
66
|
+
page-item-functions.ts
|
|
67
|
+
page-number-functions.ts
|
|
68
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.create,Object.defineProperty,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getPrototypeOf,Object.prototype.hasOwnProperty;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("grab-url");function e(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function s(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function n(t){return t>=48&&t<=57}function o(t){for(var e=0;e<t.length;e++){if(!n(t.charCodeAt(e)))return!1}return!0}function r(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++){if(t.charCodeAt(n)!==s)return!1}return!0}function a(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function i(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function h(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function l(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}const c=(t,e,s)=>Math.floor(t/e*s),m=(t,n,r)=>{for(const{str:a}of t){const t=s(e(a));o(t)&&(n[r]||(n[r]=[]),n[r].push(Number(t)))}return n},u=(t,e,s)=>{const n=c(1,6,s.length),o=c(5,6,s.length),r=m(s.slice(0,n),t,e);return m(s.slice(o),r,e)},f=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},p=(t,e)=>{const s={items:[...t.items]},n=c(1,6,s.items.length),o=c(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s};class d{type;annotation;parsedElements;constructor(t){if(this.constructor===d)throw new TypeError("Can not construct abstract class.");this.type=t.type??null,this.annotation=t.annotation??null,this.parsedElements=t.parsedElements??null}}class g extends d{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}}class y{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}}class x{name;itemType;constructor(t,e){if(this.constructor===x)throw new TypeError("Can not construct abstract class.");if(this.transform===x.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=t,this.itemType=e}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}}class w{category;color;constructor(t){this.category=t.category,this.color=t.color}}const E=new w({category:"Added",color:"green"}),T=new w({category:"Removed",color:"red"}),v=new w({category:"Unchanged",color:"brown"}),b=new w({category:"Detected",color:"green"}),O=new w({category:"Modified",color:"green"});class L extends x{constructor(t){if(super(t,g.name),this.constructor===L)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class I{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}}class S{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}}class k extends d{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new S({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}}class F{results;stash;constructor(){if(this.constructor===F)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}}class C{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}}function N(t){t.sort((t,e)=>t.x-e.x)}const D={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},M={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}};class H{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){N(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new g({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new k({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new C({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}}class B extends F{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=o(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=o(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new S({string:`${s}`,type:M.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new S({string:`${s}`,type:M.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){var s,n;const o=(s="",n=null,t.forEach(t=>{var e=t.text;s.endsWith(" ")||e.startsWith(" ")||(n?t.x-n.x-n.width>5&&(s+=" "):i(t.text)&&(e+=" ")),s+=e,n=t}),s).split(" "),r=e?D[e]:null;return o.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=M.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=M.LINK),r&&this.formattedWords++,new S({string:t,type:e,format:r})})}}class U extends L{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt(A(e)),a=A(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt(A(i)),l=[],c=new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=D.BOLD_OBLIQUE:s.includes("bold")?o=D.BOLD:s.includes("oblique")||s.includes("italic")?o=D.OBLIQUE:s===n&&(o=D.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new I({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}}function A(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}class P extends x{constructor(t){if(super(t,k.name),this.constructor===P)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class W{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{N(t)}),e}}const j={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+$(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+$(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+$(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+$(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+$(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+$(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>$(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+$(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+$(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+$(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+$(t.items,!1)+"</p>"}};function $(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}j.enumValueOf=function(t){return j[t]},j.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},j.blockToText=function(t){return t.type?t.type.toText(t):$(t.items,!1)},j.headlineByLevel=function(t){return 1===t?j.H1:2===t?j.H2:3===t?j.H3:4===t?j.H4:5===t?j.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),j.H6)};class q extends P{constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new W({mostUsedDistance:e}),h=new H(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=E,s.forEach(t=>{t.annotation=T,e.push(new k({...t}))})),0===i.words.length&&(i.annotation=T),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=j.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new I({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}}function Y(t){var e=0;if(0===t.trim().length)return e;for(var s=0;s<t.length;s++){const o=t.charCodeAt(s);n(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}class R extends P{constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=Y(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=Y(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=T}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=T}),o++)}),new I({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}}class V extends P{constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new K;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new I({...t,messages:["Converted "+e+" verticals"]})}}class K extends F{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=T,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new k({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:E})),this.foundVerticals++}else e.push(...t)}}class J{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=a(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=a(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}}class Q extends P{constructor(){super("Detect TOC")}transform(t){const e=[],s=Math.min(20,t.pages.length),a=new G;var i,h,c=[];t.pages.slice(0,s).forEach(t=>{var s=0;const l=new Set,m=[];var u,f;if(t.items.filter(t=>t.words.includes(t=>r(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!r(t.string,"."));const a=[];for(;e.length>0&&o(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;n(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new X({pageNumber:parseInt(a.join("")),lineItem:new k({...t,words:e})})),s++):h?(u&&l.add(f),u=e,f=t):h=t}),100*s/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{l.has(t)||(t.annotation=T),s.push(t),t===h&&s.push(new k({...t,type:j.H2,annotation:E}))}),t.items=s}else h=null});var m=c.length;const u=[],f=[],p={};if(e.length>0){c.forEach(t=>{i.items.push(new k({words:[new S({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:j.TOC,annotation:E}))});const e=function(t,e){for(var s of e){const e=_(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=z(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=z(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=T);const o=j.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new k({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:E}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,p):u.push(s)});var d=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=j.headlineByLevel(s.level+2),o=p[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>{if(!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max){return l(r,t.text())>=.5}return!1});if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,d,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=T,e.items.splice(a+1,0,new k({...s.lineItem,type:n,annotation:E})),f.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),d=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(p)),y.push("Found TOC headlines: "+(m-u.length+f.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+f.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!f.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new I({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:p},messages:y})}}function _(t,e){for(var s of t)if(z(s,e))return s;return null}function z(t,e){const s=new J({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}class G{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod){if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}}class X{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}}class Z extends P{constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(i(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=b,t.type=j.LIST;else{t.annotation=T;const e=t.words.map(t=>new S({...t}));e[0].string="-",n.push(new k({...t,words:e,annotation:E,type:j.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=b,t.type=j.LIST)}}),t.items=n}),new I({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}}class tt extends P{constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,i=e.length>0;var l=0;const c=function(t,e){const s=new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?j.H1:j.H2,t.annotation=b,l++)})}),i){Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=b,t.type=j.enumValueOf(e),l++)})})})}else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!h(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=j.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||h(t.text())||(l++,t.annotation=b,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=j.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=b,t.type=e),s=t})})}return new I({...t,messages:["Detected "+l+" headlines."]})}}class et extends d{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new k({...t});e.type=null,this.items.push(e)}}class st extends x{constructor(t){if(super(t,et.name),this.constructor===st)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class nt extends st{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new et({});const a=()=>{r.items.length>1&&(r.annotation=b),o.push(r),r=new et({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);if(o>r)return!0;return!1}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new I({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}}class ot extends st{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=b,t.type=j.CODE,s++)})}),new I({...t,messages:["Detected "+s+" code/quote items."]})}}class rt extends st{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===j.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new S({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=O):t.annotation=v})}),new I({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}}class at extends x{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:j.blockToText(t)})}),t.items=e}),new I({...t})}}class it extends x{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new I({...t})}}exports.convertPDFToHTML=async function(e,s={}){var{addPageNumbers:n=!1,addCitation:o=!0}=s,r="string"==typeof e?await t(e,{responseType:"arraybuffer",timeout:10}):e;let a;try{let{resolvePDFJS:t}=await import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm");const{getDocument:e}=await t();a=await e({data:new Uint8Array(r),useSystemFonts:!0,verbosity:0}).promise}catch(b){return{error:b.message}}const i=[...Array(a.numPages).keys()].map(t=>new y({index:t}));let h,l={};for(let t=1;t<=a.numPages;t++){const e=await a.getPage(t),s=await e.getTextContent();if(!(Object.keys(l).length<10)){h=f(l);break}l=u(l,e.pageNumber-1,s.items)}let c=h?h.pageNum:0;for(let t=1;t<=a.numPages;t++){const e=await a.getPage(t);await e.getOperatorList();const s=1,n=e.getViewport({scale:s});let o=await e.getTextContent();h&&e.pageIndex>=h.pageIndex&&(o=p(o,c),c++);const r=o.items.map(t=>{const e=[1,0,0,1,0,0];for(let r=0;r<6;r++)e[r]+=t.transform[r]*n.transform[r%2?3:0],r%2&&(e[r+1]+=t.transform[r]*n.transform[1]);const s=Math.sqrt(e[2]*e[2]+e[3]*e[3]),o=t.height/s;return new g({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});i[e.pageNumber-1].items=r}var m=new I({pages:i});let d,x=[new U,new q,new R,new V,new Q,new tt,new Z,new nt,new ot,new rt,new at,new it];x?.forEach(t=>{d&&(m=d.completeTransform(m)),m=t.transform(m),d=t});var w=m.pages.reduce((t,e,s)=>t+`<p id="page-${s+1}">${n?` [${s+1}] `:""}${e.items.join('</p><p id="page-'+s+'">')}</p>`,"");if(o){var E=await a.getMetadata(),{Author:T,Title:v}=E.info;v=w.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||v}return{author:T,title:v,html:w,format:"pdf"}};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ### Convert PDF to HTML
|
|
3
|
+
* <img src="https://i.imgur.com/6IdNDLP.png" width="350px" />
|
|
4
|
+
*
|
|
5
|
+
* Extracts formatted text from PDF with parsing of linebreaks ,
|
|
6
|
+
* page headers, footnotes, and section headings. Supports fonts, links, bold,
|
|
7
|
+
* italics, lists, headings, headers, footnotes, and Table of Contents,
|
|
8
|
+
* Quotes, and Code Blocks, . Removes repeated headers, links footnote anchors to the footnote,
|
|
9
|
+
* and preserves number of the PDF page with invisible I element.
|
|
10
|
+
*
|
|
11
|
+
* This function uses [pdfjs-serverless](https://github.com/johannschopplich/pdfjs-serverless)
|
|
12
|
+
* to work in more environments than PDF.js-based tools:
|
|
13
|
+
* Cloudflare workers, serverless, node.js, and front-end only.
|
|
14
|
+
* @param {string} pdfURLOrBuffer - URL to a PDF file or buffer from fs.readFile
|
|
15
|
+
* @param {Object} [options]
|
|
16
|
+
* @param {boolean} options.addPageNumbers default=false - Adds # to end of each page
|
|
17
|
+
* @param {boolean} options.removePageHeaders default=true - Removes repeated headers found on each page
|
|
18
|
+
* @returns {string|Object} HTML formatted text
|
|
19
|
+
* @category Extract
|
|
20
|
+
* @author [vtempest (2025)](https://github.com/vtempest),
|
|
21
|
+
* [pdf-to-markdown (2017)](https://github.com/jzillmann/pdf-to-markdown/tree/master),
|
|
22
|
+
* [pdf.js (2012-)](https://github.com/mozilla/pdf.js/releases),
|
|
23
|
+
*/
|
|
24
|
+
export declare function convertPDFToHTML(pdfURLOrBuffer: any, options?: {
|
|
25
|
+
addPageNumbers?: boolean;
|
|
26
|
+
addCitation?: boolean;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
error: any;
|
|
29
|
+
author?: undefined;
|
|
30
|
+
title?: undefined;
|
|
31
|
+
html?: undefined;
|
|
32
|
+
format?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
author: any;
|
|
35
|
+
title: any;
|
|
36
|
+
html: string;
|
|
37
|
+
format: string;
|
|
38
|
+
error?: undefined;
|
|
39
|
+
}>;
|
|
40
|
+
|
|
41
|
+
export { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import t from"grab-url";function e(t){for(;32===t.charCodeAt(0);)t=t.substring(1,t.length);return t}function s(t){for(;32===t.charCodeAt(t.length-1);)t=t.substring(0,t.length-1);return t}function n(t){return t>=48&&t<=57}function o(t){for(var e=0;e<t.length;e++){if(!n(t.charCodeAt(e)))return!1}return!0}function r(t,e){const s=e.charCodeAt(0);for(var n=0;n<t.length;n++){if(t.charCodeAt(n)!==s)return!1}return!0}function a(t){return function(t){const e=[];for(var s=0;s<t.length;s++)e.push(t.charCodeAt(s));return e}(t=t.toUpperCase()).filter(t=>32!==t&&9!==t&&46!==t)}function i(t){if(t.length>1)return!1;const e=t.charAt(0);return"-"===e||"•"===e||"–"===e}function h(t){return/^[\s]*[-•–][\s].*$/g.test(t)}function l(t,e){const s=new Set(t.toUpperCase().split(" ")),n=new Set(e.toUpperCase().split(" "));return new Set([...s].filter(t=>n.has(t))).size/Math.max(s.size,n.size)}const c=(t,e,s)=>Math.floor(t/e*s),m=(t,n,r)=>{for(const{str:a}of t){const t=s(e(a));o(t)&&(n[r]||(n[r]=[]),n[r].push(Number(t)))}return n},u=(t,e,s)=>{const n=c(1,6,s.length),o=c(5,6,s.length),r=m(s.slice(0,n),t,e);return m(s.slice(o),r,e)},f=t=>{let e=0;const s=Object.keys(t);if(0!==s.length&&1!==s.length)for(let n=0;n<s.length-1;n++){const o=t[s[n]],r=t[s[n+1]],a=e;for(let t=0;t<o.length&&e<2;t++)for(let a=0;a<r.length&&e<2;a++){const i=Number(s[n+1])-Number(s[n]);(o[t]+1===r[a]||i>1&&o[t]+i===r[a])&&e++}let i=n>0?Object.entries(t)[n-1]:Object.entries(t)[n];if(a===e)e=0,i=Object.entries(t)[n];else if(e>=2)return{pageIndex:Number(i[0]),pageNum:i[1][0]}}},d=(t,e)=>{const s={items:[...t.items]},n=c(1,6,s.items.length),o=c(5,6,s.items.length);return s.items=s.items.filter((t,r)=>{const a=r>0&&r<n,i=r>o&&r<s.items.length;return a||i?Number(t.str)!==Number(e):t}),s};class p{type;annotation;parsedElements;constructor(t){if(this.constructor===p)throw new TypeError("Can not construct abstract class.");this.type=t.type??null,this.annotation=t.annotation??null,this.parsedElements=t.parsedElements??null}}class g extends p{x;y;width;height;text;font;lineFormat;unopenedFormat;unclosedFormat;constructor(t){super(t),this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height,this.text=t.text,this.font=t.font,this.lineFormat=t.lineFormat??null,this.unopenedFormat=t.unopenedFormat??null,this.unclosedFormat=t.unclosedFormat??null}}class y{index;items;constructor(t){this.index=t.index,this.items=t.items||[]}}class x{name;itemType;constructor(t,e){if(this.constructor===x)throw new TypeError("Can not construct abstract class.");if(this.transform===x.prototype.transform)throw new TypeError("Please implement abstract method 'transform()'.");this.name=t,this.itemType=e}transform(t){throw new TypeError("Do not call abstract method foo from child.")}completeTransform(t){return t.messages=[],t}}class w{category;color;constructor(t){this.category=t.category,this.color=t.color}}const E=new w({category:"Added",color:"green"}),T=new w({category:"Removed",color:"red"}),v=new w({category:"Unchanged",color:"brown"}),b=new w({category:"Detected",color:"green"}),L=new w({category:"Modified",color:"green"});class I extends x{constructor(t){if(super(t,g.name),this.constructor===I)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class O{pages;globals;messages;constructor(t){this.pages=t.pages||[],this.globals=t.globals||{},this.messages=t.messages||[]}}class S{string;type;format;constructor(t){this.string=t.string,this.type=t.type??null,this.format=t.format??null}}class k extends p{x;y;width;height;words;constructor(t){super(t),this.x=t.x??0,this.y=t.y??0,this.width=t.width??0,this.height=t.height??0,this.words=t.words||[],t.text&&!t.words&&(this.words=t.text.split(" ").filter(t=>t.trim().length>0).map(t=>new S({string:t})))}text(){return this.wordStrings().join(" ")}wordStrings(){return this.words.map(t=>t.string)}}class C{results;stash;constructor(){if(this.constructor===C)throw new TypeError("Can not construct abstract class.");this.results=[],this.stash=[]}consumeAll(t){t.forEach(t=>this.consume(t))}consume(t){this.shouldStash(t)?(this.matchesStash(t)||this.flushStash(),this.pushOnStash(t)):(this.stash.length>0&&this.flushStash(),this.results.push(t))}pushOnStash(t){this.onPushOnStash(t),this.stash.push(t)}complete(){return this.stash.length>0&&this.flushStash(),this.results}matchesStash(t){if(0===this.stash.length)return!0;const e=this.stash[this.stash.length-1];return this.doMatchesStash(e,t)}flushStash(){this.stash.length>0&&(this.doFlushStash(this.stash,this.results),this.stash=[])}onPushOnStash(t){}shouldStash(t){throw new TypeError(" Do not call abstract method foo from child."+t)}doMatchesStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}doFlushStash(t,e){throw new TypeError(" Do not call abstract method foo from child."+t+e)}}class F{footnoteLinks;footnotes;containLinks;formattedWords;constructor(t){this.footnoteLinks=t.footnoteLinks||[],this.footnotes=t.footnotes||[],this.containLinks=t.containLinks??!1,this.formattedWords=t.formattedWords??0}add(t){this.footnoteLinks=this.footnoteLinks.concat(t.footnoteLinks),this.footnotes=this.footnotes.concat(t.footnotes),this.containLinks=this.containLinks||t.containLinks,this.formattedWords+=t.formattedWords}}function N(t){t.sort((t,e)=>t.x-e.x)}const D={BOLD:{name:"BOLD",startSymbol:"<strong>",endSymbol:"</strong>"},OBLIQUE:{name:"OBLIQUE",startSymbol:"<em>",endSymbol:"</em>"},BOLD_OBLIQUE:{name:"BOLD_OBLIQUE",startSymbol:"<strong><em>",endSymbol:"</em></strong>"}},H={LINK:{name:"LINK",toText:t=>`<a href="${t}">${t}</a>`},FOOTNOTE_LINK:{name:"FOOTNOTE_LINK",attachWithoutWhitespace:!0,plainTextFormat:!0,toText:t=>`<sup><a href="#${t}">${t}</a></sup>`},FOOTNOTE:{name:"FOOTNOTE",toText:t=>`<p id="${t}">^${t}</p>`}};class M{fontToFormats;constructor(t){this.fontToFormats=t}compact(t){N(t);const e=new B(this.fontToFormats);e.consumeAll(t.map(t=>new g({...t})));const s=e.complete();var n=0,o=0;return t.forEach(t=>{n=Math.max(n,t.height),o+=t.width}),new k({x:t[0].x,y:t[0].y,height:n,width:o,words:s,parsedElements:new F({footnoteLinks:e.footnoteLinks,footnotes:e.footnotes,containLinks:e.containLinks,formattedWords:e.formattedWords})})}}class B extends C{fontToFormats;footnoteLinks;footnotes;formattedWords;containLinks;stashedNumber;firstY;currentItem;constructor(t){super(),this.fontToFormats=t,this.footnoteLinks=[],this.footnotes=[],this.formattedWords=0,this.containLinks=!1,this.stashedNumber=!1,this.currentItem=null}shouldStash(t){return this.firstY||(this.firstY=t.y),this.currentItem=t,!0}onPushOnStash(t){this.stashedNumber=o(t.text.trim())}doMatchesStash(t,e){if(this.fontToFormats.get(t.font)!==this.fontToFormats.get(e.font))return!1;const s=o(e.text.trim());return this.stashedNumber===s}doFlushStash(t,e){if(this.stashedNumber){const s=t.map(t=>t.text).join("").trim();t[0].y>this.firstY?(e.push(new S({string:`${s}`,type:H.FOOTNOTE_LINK})),this.footnoteLinks.push(parseInt(s))):this.currentItem&&this.currentItem.y<t[0].y?(e.push(new S({string:`${s}`,type:H.FOOTNOTE})),this.footnotes.push(s)):this.copyStashItemsAsText(t,e)}else this.copyStashItemsAsText(t,e)}copyStashItemsAsText(t,e){const s=this.fontToFormats.get(t[0].font);e.push(...this.itemsToWords(t,s))}itemsToWords(t,e){var s,n;const o=(s="",n=null,t.forEach(t=>{var e=t.text;s.endsWith(" ")||e.startsWith(" ")||(n?t.x-n.x-n.width>5&&(s+=" "):i(t.text)&&(e+=" ")),s+=e,n=t}),s).split(" "),r=e?D[e]:null;return o.filter(t=>t.trim().length>0).map(t=>{var e=null;return t.startsWith("http:")?(this.containLinks=!0,e=H.LINK):t.startsWith("www.")&&(this.containLinks=!0,t=`http://${t}`,e=H.LINK),r&&this.formattedWords++,new S({string:t,type:e,format:r})})}}class U extends I{fontMap;constructor(t){super("Calculate Global Stats"),this.fontMap=t}transform(t){const e={},s={};var n,o=0;t.pages.forEach(t=>{t.items.forEach(t=>{t.height&&(e[t.height]=e[t.height]?e[t.height]+1:1,s[t.font]=s[t.font]?s[t.font]+1:1,t.height>o&&(o=t.height,n=t.font))})});const r=parseInt(A(e)),a=A(s),i={};t.pages.forEach(t=>{var e;t.items.forEach(t=>{if(t.height===r&&t.text.trim().length>0){if(e&&t.y!==e.y){const s=e.y-t.y;s>0&&(i[s]=i[s]?i[s]+1:1)}e=t}else e=null})});const h=parseInt(A(i)),l=[],c=/* @__PURE__ */new Map;this.fontMap?.forEach(function(t,e){l.push(e+" = "+t.name);const s=t.name.toLowerCase();var o=null;e===a?o=null:s.includes("bold")&&(s.includes("oblique")||s.includes("italic"))?o=D.BOLD_OBLIQUE:s.includes("bold")?o=D.BOLD:s.includes("oblique")||s.includes("italic")?o=D.OBLIQUE:s===n&&(o=D.BOLD),o&&c.set(e,o.name)}),l.sort();const m=t.pages.map(t=>({...t,items:t.items.map(t=>({...t}))}));return new O({...t,pages:m,globals:{mostUsedHeight:r,mostUsedFont:a,mostUsedDistance:h,maxHeight:o,maxHeightFont:n,fontToFormats:c},messages:["Items per height: "+JSON.stringify(e),"Items per font: "+JSON.stringify(s),"Items per distance: "+JSON.stringify(i),"Fonts:"+JSON.stringify(l)]})}}function A(t){var e=0,s="";return Object.keys(t).map(n=>{(!s||t[n]>e)&&(e=t[n],s=n)}),s}class W extends x{constructor(t){if(super(t,k.name),this.constructor===W)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class P{mostUsedDistance;constructor(t){this.mostUsedDistance=t.mostUsedDistance||12}group(t){const e=[];var s=[];return t.forEach(t=>{s.length>0&&Math.abs(s[0].y-t.y)>=this.mostUsedDistance/2&&(e.push(s),s=[]),s.push(t)}),e.push(s),e.forEach(t=>{N(t)}),e}}const $={H1:{name:"H1",headline:!0,headlineLevel:1,toText:t=>"<h1>"+j(t.items,!0)+"</h1>"},H2:{name:"H2",headline:!0,headlineLevel:2,toText:t=>"<h2>"+j(t.items,!0)+"</h2>"},H3:{name:"H3",headline:!0,headlineLevel:3,toText:t=>"<h3>"+j(t.items,!0)+"</h3>"},H4:{name:"H4",headline:!0,headlineLevel:4,toText:t=>"<h4>"+j(t.items,!0)+"</h4>"},H5:{name:"H5",headline:!0,headlineLevel:5,toText:t=>"<h5>"+j(t.items,!0)+"</h5>"},H6:{name:"H6",headline:!0,headlineLevel:6,toText:t=>"<h6>"+j(t.items,!0)+"</h6>"},TOC:{name:"TOC",mergeToBlock:!0,toText:t=>j(t.items,!0)},FOOTNOTES:{name:"FOOTNOTES",mergeToBlock:!0,mergeFollowingNonTypedItems:!0,toText:t=>"<p>"+j(t.items,!1)+"</p>"},CODE:{name:"CODE",mergeToBlock:!0,toText:t=>"<code>"+j(t.items,!0)+"</code>"},LIST:{name:"LIST",mergeToBlock:!1,mergeFollowingNonTypedItemsWithSmallDistance:!0,toText:t=>"<ul>\n"+j(t.items,!1)+"</ul>"},PARAGRAPH:{name:"PARAGRAPH",toText:t=>"<p>"+j(t.items,!1)+"</p>"}};function j(t,e){var s,n="";const o=()=>{n+=s.endSymbol,s=null};return t.forEach((r,a)=>{var i;r&&(r.words.forEach((t,r)=>{const a=t.type,i=t.format;var h;!s||i&&i===s||o(),r>0&&(!a||!a.attachWithoutWhitespace)&&(1!==(h=t.string).length||"."!==h[0]&&"!"!==h[0]&&"?"!==h[0])&&(n+=" "),!i||s||e||(n+=(s=i).startSymbol),!a||e&&!a.plainTextFormat?n+=t.string:n+=a.toText(t.string)}),!s||a!==t.length-1&&(0===(i=t[a+1]).words.length?null:i.words[0].format)===s||o(),n+="\n")}),n}$.enumValueOf=function(t){return $[t]},$.isHeadline=function(t){return t&&2===t.name.length&&"H"===t.name[0]},$.blockToText=function(t){return t.type?t.type.toText(t):j(t.items,!1)},$.headlineByLevel=function(t){return 1===t?$.H1:2===t?$.H2:3===t?$.H3:4===t?$.H4:5===t?$.H5:(t>6&&console.warn("Unsupported headline level: "+t+" (supported are 1-6), defaulting to level 6"),$.H6)};class q extends W{constructor(){super("Compact To Lines")}transform(t){const{mostUsedDistance:e,fontToFormats:s}=t.globals,n=[],o=[];var r=0,a=0;const i=new P({mostUsedDistance:e}),h=new M(s);return t.pages.forEach(t=>{if(t.items.length>0){const e=[];i.group(t.items).forEach(s=>{const i=h.compact(s);if(s.length>1&&(i.annotation=E,s.forEach(t=>{t.annotation=T,e.push(new k({...t}))})),0===i.words.length&&(i.annotation=T),e.push(i),i.parsedElements.formattedWords&&(a+=i.parsedElements.formattedWords),i.parsedElements.containLinks&&r++,i.parsedElements.footnoteLinks.length>0){const e=i.parsedElements.footnoteLinks.map(e=>({footnoteLink:e,page:t.index+1}));o.push.apply(o,e)}if(i.parsedElements.footnotes.length>0){i.type=$.FOOTNOTES;const e=i.parsedElements.footnotes.map(e=>({footnote:e,page:t.index+1}));n.push.apply(n,e)}}),t.items=e}}),new O({...t,messages:["Detected "+a+" formatted words","Found "+r+" links","Detected "+o.length+" footnotes links","Detected "+n.length+" footnotes"]})}}function Y(t){var e=0;if(0===t.trim().length)return e;for(var s=0;s<t.length;s++){const o=t.charCodeAt(s);n(o)||32===o||160===o||(e=(e<<5)-e+o,e|=0)}return e}class R extends W{constructor(){super("Remove Repetitive Elements")}transform(t){const e=[],s={},n={};t.pages.forEach(t=>{const o=t.items.reduce((t,e)=>(e.y<t.minY?(t.minElements=[e],t.minY=e.y):e.y===t.minY&&t.minElements.push(e),e.y>t.maxY?(t.maxElements=[e],t.maxY=e.y):e.y===t.maxY&&t.maxElements.push(e),t),{minY:999,maxY:0,minElements:[],maxElements:[]}),r=Y(o.minElements.reduce((t,e)=>t+e.text().toUpperCase(),"")),a=Y(o.maxElements.reduce((t,e)=>t+e.text().toUpperCase(),""));e.push({minElements:o.minElements,maxElements:o.maxElements,minLineHash:r,maxLineHash:a}),s[r]=s[r]?s[r]+1:1,n[a]=n[a]?n[a]+1:1});var o=0,r=0;return t.pages.forEach((a,i)=>{s[e[i].minLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].minElements.forEach(t=>{t.annotation=T}),r++),n[e[i].maxLineHash]>=Math.max(3,2*t.pages.length/3)&&(e[i].maxElements.forEach(t=>{t.annotation=T}),o++)}),new O({...t,messages:["Removed Header: "+o,"Removed Footers: "+r]})}}class V extends W{constructor(){super("Vertical to Horizontal Text")}transform(t){var e=0;return t.pages.forEach(t=>{const s=new K;s.consumeAll(t.items),t.items=s.complete(),e+=s.foundVerticals}),new O({...t,messages:["Converted "+e+" verticals"]})}}class K extends C{foundVerticals;constructor(){super(),this.foundVerticals=0}shouldStash(t){return 1===t.words.length&&1===t.words[0].string.length}doMatchesStash(t,e){return t.y-e.y>5&&t.words[0].type===e.words[0].type}doFlushStash(t,e){if(t.length>5){var s=[],n=999,o=0,r=0,a=0;t.forEach(t=>{t.annotation=T,e.push(t),s.push(t.words[0]),n=Math.min(n,t.x),o=Math.max(o,t.y),r+=t.width,a=Math.max(a,t.height)}),e.push(new k({...t[0],x:n,y:o,width:r,height:a,words:s,annotation:E})),this.foundVerticals++}else e.push(...t)}}class J{headlineCharCodes;stackedLineItems;stackedChars;constructor(t){this.headlineCharCodes=a(t.headline),this.stackedLineItems=[],this.stackedChars=0}consume(t){const e=a(t.text());if(this.matchAll(e)){if(this.stackedLineItems.push(t),this.stackedChars+=e.length,this.stackedChars===this.headlineCharCodes.length)return this.stackedLineItems}else this.stackedChars>0&&(this.stackedChars=0,this.stackedLineItems=[],this.consume(t));return null}matchAll(t){for(var e=0;e<t.length;e++){const s=this.headlineCharCodes[this.stackedChars+e];if(t[e]!==s)return!1}return!0}}class Q extends W{constructor(){super("Detect TOC")}transform(t){const e=[],s=Math.min(20,t.pages.length),a=new G;var i,h,c=[];t.pages.slice(0,s).forEach(t=>{var s=0;const l=/* @__PURE__ */new Set,m=[];var u,f;if(t.items.filter(t=>t.words.includes(t=>r(t.string,"."))).forEach(t=>{var e=t.words.filter(t=>!r(t.string,"."));const a=[];for(;e.length>0&&o(e[e.length-1].string);){const t=e.pop();a.unshift(t.string)}if(0===a.length&&e.length>0){const t=e[e.length-1];for(;n(t.string.charCodeAt(t.string.length-1));)a.unshift(t.string.charAt(t.string.length-1)),t.string=t.string.substring(0,t.string.length-1)}var i=a.length>0;i?(i=!0,u&&(e.push(...u),u=null),m.push(new X({pageNumber:parseInt(a.join("")),lineItem:new k({...t,words:e})})),s++):h?(u&&l.add(f),u=e,f=t):h=t}),100*s/t.items.length>75){e.push(t.index+1),i=t,a.levelPageItems(m),c.push(...m);const s=[];t.items.forEach(t=>{l.has(t)||(t.annotation=T),s.push(t),t===h&&s.push(new k({...t,type:$.H2,annotation:E}))}),t.items=s}else h=null});var m=c.length;const u=[],f=[],d={};if(e.length>0){c.forEach(t=>{i.items.push(new k({words:[new S({string:" ".repeat(3*t.level)+"-"})].concat(t.lineItem.words),type:$.TOC,annotation:E}))});const e=function(t,e){for(var s of e){const e=_(t,s.lineItem.text());if(e)return e.index-s.pageNumber}return null}(t.pages.filter(t=>t.index>i.index),c);c.forEach(s=>{var n,o=t.pages[s.pageNumber+e];o&&((n=z(o,s.lineItem.text()))||(o=t.pages[s.pageNumber+e+1])&&(n=z(o,s.lineItem.text()))),n?function(t,e,s,n){s.headlineItems.forEach(t=>t.annotation=T);const o=$.headlineByLevel(e.level+2),r=s.headlineItems.reduce((t,e)=>Math.max(t,e.height),0);t.items.splice(s.lineIndex+1,0,new k({...s.headlineItems[0],words:e.lineItem.words,height:r,type:o,annotation:E}));var a=n[o.name];a?(a.min=Math.min(a.min,r),a.max=Math.max(a.max,r)):(a={min:r,max:r},n[o.name]=a)}(o,s,n,d):u.push(s)});var p=i.index+2,g=[];const s=e=>{g.length>0&&(g.forEach(s=>{const n=$.headlineByLevel(s.level+2),o=d[n.name];if(o){const[r,a]=function(t,e,s,n,o){const r=e.lineItem.text().toUpperCase();for(var a=n;a<=o;a++){const e=t[a-1];if(e){const t=e.items.findIndex(t=>{if(!t.type&&!t.annotation&&t.height>=s.min&&t.height<=s.max){return l(r,t.text())>=.5}return!1});if(t>-1)return[a-1,t]}}return[-1,-1]}(t.pages,s,o,p,e);if(a>-1){const e=t.pages[r];e.items[a].annotation=T,e.items.splice(a+1,0,new k({...s.lineItem,type:n,annotation:E})),f.push(s)}}}),g=[])};u.length>0&&(c.forEach(t=>{u.includes(t)?g.push(t):(s(t.pageNumber),p=t.pageNumber)}),g.length>0&&s(t.pages.length))}const y=[];return y.push("Detected "+e.length+" table of content pages"),e.length>0&&(y.push("TOC headline heights: "+JSON.stringify(d)),y.push("Found TOC headlines: "+(m-u.length+f.length)+"/"+m)),u.length>0&&(y.push("Found TOC headlines (by size): "+f.map(t=>t.lineItem.text())),y.push("Missing TOC headlines: "+u.filter(t=>!f.includes(t)).map(t=>t.lineItem.text()+"=>"+t.pageNumber))),new O({...t,globals:{...t.globals,tocPages:e,headlineTypeToHeightRange:d},messages:y})}}function _(t,e){for(var s of t)if(z(s,e))return s;return null}function z(t,e){const s=new J({headline:e});var n=0;for(var o of t.items){const t=s.consume(o);if(t)return{lineIndex:n,headlineItems:t};n++}return null}class G{levelByMethod;uniqueFonts;constructor(){this.levelByMethod=null,this.uniqueFonts=[]}levelPageItems(t){if(!this.levelByMethod){if(this.calculateUniqueX(t).length>1)this.levelByMethod=this.levelByXDiff;else{const e=this.calculateUniqueFonts(t);e.length>1?(this.uniqueFonts=e,this.levelByMethod=this.levelByFont):this.levelByMethod=this.levelToZero}}this.levelByMethod(t)}levelByXDiff(t){const e=this.calculateUniqueX(t);t.forEach(t=>{t.level=e.indexOf(t.lineItem.x)})}levelByFont(t){t.forEach(t=>{t.level=this.uniqueFonts.indexOf(t.lineItem.font)})}levelToZero(t){t.forEach(t=>{t.level=0})}calculateUniqueX(t){var e=t.reduce(function(t,e){return t.indexOf(e.lineItem.x)<0&&t.push(e.lineItem.x),t},[]);return e.sort((t,e)=>t-e),e}calculateUniqueFonts(t){return t.reduce(function(t,e){return t.indexOf(e.lineItem.font)<0&&t.push(e.lineItem.font),t},[])}}class X{lineItem;pageNumber;level;constructor(t){this.lineItem=t.lineItem,this.pageNumber=t.pageNumber,this.level=0}}class Z extends W{constructor(){super("Detect List Items")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{const n=[];t.items.forEach(t=>{if(n.push(t),!t.type){var o=t.text();if(i(t.words[0].string))if(e++,"-"===t.words[0].string)t.annotation=b,t.type=$.LIST;else{t.annotation=T;const e=t.words.map(t=>new S({...t}));e[0].string="-",n.push(new k({...t,words:e,annotation:E,type:$.LIST}))}else/^[\s]*[\d]*[.][\s].*$/g.test(o)&&(s++,t.annotation=b,t.type=$.LIST)}}),t.items=n}),new O({...t,messages:["Detected "+e+" plain list items.","Detected "+s+" numbered list items."]})}}class tt extends W{constructor(){super("Detect Headers")}transform(t){const{tocPages:e,headlineTypeToHeightRange:s,mostUsedHeight:n,mostUsedDistance:o,mostUsedFont:r,maxHeight:a}=t.globals,i=e.length>0;var l=0;const c=function(t,e){const s=/* @__PURE__ */new Set;return t.forEach(t=>{t.items.forEach(n=>{n.type||n.height!==e||s.add(t)})}),s}(t.pages,a),m=n+(a-n)/4;if(c.forEach(t=>{t.items.forEach(t=>{const e=t.height;!t.type&&e>m&&(t.type=e===a?$.H1:$.H2,t.annotation=b,l++)})}),i){Object.keys(s).forEach(e=>{var o=s[e];o.max>n&&t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==o.max||(t.annotation=b,t.type=$.enumValueOf(e),l++)})})})}else{const e=[];t.pages.forEach(t=>{t.items.forEach(t=>{!t.type&&t.height>n&&!h(t.text())&&(e.includes(t.height)||e.push(t.height))})}),e.sort((t,e)=>e-t),e.forEach((e,s)=>{if(s+2<=6){const n=$.headlineByLevel(2+s);t.pages.forEach(t=>{t.items.forEach(t=>{t.type||t.height!==e||h(t.text())||(l++,t.annotation=b,t.type=n)})})}})}var u=1;if(t.pages.forEach(t=>{t.items.forEach(t=>{t.type&&t.type.headline&&(u=Math.max(u,t.type.headlineLevel))})}),u<6){const e=$.headlineByLevel(u+1);t.pages.forEach(t=>{var s;t.items.forEach(t=>{!t.type&&t.height===n&&t.font!==r&&(!s||s.y<t.y||s.type&&s.type.headline||s.y-t.y>2*o)&&t.text()===t.text().toUpperCase()&&(l++,t.annotation=b,t.type=e),s=t})})}return new O({...t,messages:["Detected "+l+" headlines."]})}}class et extends p{items;constructor(t){super(t),this.items=[],t.items&&t.items.forEach(t=>this.addItem(t))}addItem(t){if(this.type&&t.type&&this.type!==t.type)throw new Error(`Adding item of type ${t.type.name} to block of type ${this.type.name}`);this.type||(this.type=t.type),t.parsedElements&&(this.parsedElements?this.parsedElements.add(t.parsedElements):this.parsedElements=t.parsedElements);const e=new k({...t});e.type=null,this.items.push(e)}}class st extends x{constructor(t){if(super(t,et.name),this.constructor===st)throw new TypeError("Can not construct abstract class.")}completeTransform(t){return t.messages=[],t.pages.forEach(t=>{t.items=t.items.filter(t=>!t.annotation||t.annotation!==T),t.items.forEach(t=>t.annotation=null)}),t}}class nt extends st{constructor(){super("Gather Blocks")}transform(t){const{mostUsedDistance:e}=t.globals;var s=0,n=0;return t.pages.map(t=>{n+=t.items.length;const o=[];var r=new et({});const a=()=>{r.items.length>1&&(r.annotation=b),o.push(r),r=new et({}),s++};var i=function(t){var e=999;return t.forEach(t=>{e=Math.min(e,t.x)}),999===e?null:e}(t.items);t.items.forEach(t=>{r.items.length>0&&function(t,e,s,n){if(t.type&&t.type.mergeFollowingNonTypedItems&&!e.type)return!1;const o=t.items[t.items.length-1],r=function(t,e,s,n){const o=t.y-e.y;if(o<0-n/2)return!0;var r=n+1;t.x>s&&e.x>s&&(r=n+n/2);if(o>r)return!0;return!1}(o,e,s,n);if(t.type&&t.type.mergeFollowingNonTypedItemsWithSmallDistance&&!e.type&&!r)return!1;if(e.type!==t.type)return!0;return e.type?!e.type.mergeToBlock:r}(r,t,i,e)&&a(),r.addItem(t)}),r.items.length>0&&a(),t.items=o}),new O({...t,messages:["Gathered "+s+" blocks out of "+n+" line items"]})}}class ot extends st{constructor(){super("$1")}transform(t){const e=t.globals.mostUsedHeight??0;var s=0;return t.pages.forEach(t=>{var n=function(t){var e=999;return t.forEach(t=>{t.items.forEach(t=>{e=Math.min(e,t.x)})}),999===e?null:e}(t.items);t.items.forEach(t=>{!t.type&&function(t,e,s){if(0===e.length)return!1;if(1===e.length)return e[0].x>t&&e[0].height<=s+1;for(var n of e)if(n.x===t)return!1;return!0}(n,t.items,e)&&(t.annotation=b,t.type=$.CODE,s++)})}),new O({...t,messages:["Detected "+s+" code/quote items."]})}}class rt extends st{constructor(){super("Level Lists")}transform(t){var e=0,s=0;return t.pages.forEach(t=>{t.items.filter(t=>t.type===$.LIST).forEach(t=>{var n,o=0;const r={};var a=!1;t.items.forEach(t=>{n?t.x>n?(o++,r[t.x]=o):t.x<n&&(o=r[t.x]):r[t.x]=0,o>0&&(t.words=[new S({string:" ".repeat(3*o)})].concat(t.words),a=!0),n=t.x}),e++,a?(s++,t.annotation=L):t.annotation=v})}),new O({...t,messages:["Modified "+s+" / "+e+" list blocks."]})}}class at extends x{constructor(){super("To Text Blocks","TextBlock")}transform(t){return t.pages.forEach(t=>{const e=[];t.items.forEach(t=>{const s=t.type?t.type.name:"Unknown";e.push({category:s,text:$.blockToText(t)})}),t.items=e}),new O({...t})}}class it extends x{constructor(){super("To HTML","String")}transform(t){return t.pages.forEach(t=>{var e="";t.items.forEach(t=>{let s;s="TOC"===t.category?t.text:t.text.replace(/(\r\n|\n|\r)/gm,"\n"),"LIST"!==t.category&&(s=s.split("- ").join("")),"CODE"===t.category&&(s=s.split("<code>").join("").split("</code>").join("")),e+=`<p>${s}</p>\n\n`}),t.items=[e]}),new O({...t})}}async function ht(e,s={}){var{addPageNumbers:n=!1,addCitation:o=!0}=s,r="string"==typeof e?await t(e,{responseType:"arraybuffer",timeout:10}):e;let a;try{let{resolvePDFJS:t}=await import("https://cdn.jsdelivr.net/npm/pdfjs-serverless@1.1.0/+esm");const{getDocument:e}=await t();a=await e({data:new Uint8Array(r),useSystemFonts:!0,verbosity:0}).promise}catch(b){return{error:b.message}}const i=[...Array(a.numPages).keys()].map(t=>new y({index:t}));let h,l={};for(let t=1;t<=a.numPages;t++){const e=await a.getPage(t),s=await e.getTextContent();if(!(Object.keys(l).length<10)){h=f(l);break}l=u(l,e.pageNumber-1,s.items)}let c=h?h.pageNum:0;for(let t=1;t<=a.numPages;t++){const e=await a.getPage(t);await e.getOperatorList();const s=1,n=e.getViewport({scale:s});let o=await e.getTextContent();h&&e.pageIndex>=h.pageIndex&&(o=d(o,c),c++);const r=o.items.map(t=>{const e=[1,0,0,1,0,0];for(let r=0;r<6;r++)e[r]+=t.transform[r]*n.transform[r%2?3:0],r%2&&(e[r+1]+=t.transform[r]*n.transform[1]);const s=Math.sqrt(e[2]*e[2]+e[3]*e[3]),o=t.height/s;return new g({x:Math.round(t.transform[4]),y:Math.round(t.transform[5]),width:Math.round(t.width),height:Math.round(o<=1?t.height:o),text:t.str,font:t.fontName})});i[e.pageNumber-1].items=r}var m=new O({pages:i});let p,x=[new U,new q,new R,new V,new Q,new tt,new Z,new nt,new ot,new rt,new at,new it];x?.forEach(t=>{p&&(m=p.completeTransform(m)),m=t.transform(m),p=t});var w=m.pages.reduce((t,e,s)=>t+`<p id="page-${s+1}">${n?` [${s+1}] `:""}${e.items.join('</p><p id="page-'+s+'">')}</p>`,"");if(o){var E=await a.getMetadata(),{Author:T,Title:v}=E.info;v=w.slice(0,400).match(/<h[0-9]>(.*?)<\/h[0-9]>/)?.[1]||v}return{author:T,title:v,html:w,format:"pdf"}}export{ht as convertPDFToHTML};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "extract-pdf",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Convert a PDF (URL or ArrayBuffer) into clean HTML with structural tagging — headings, lists, footnotes, code blocks, bold/italic. Works in Node.js, Cloudflare Workers, and browser environments.",
|
|
5
|
+
"author": "vtempest <grokthiscontact@gmail.com>",
|
|
6
|
+
"license": "rights.institute/PROSPER",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/pdf-to-html.cjs.js",
|
|
9
|
+
"module": "./dist/pdf-to-html.es.js",
|
|
10
|
+
"types": "./dist/pdf-to-html.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/pdf-to-html.d.ts",
|
|
14
|
+
"import": "./dist/pdf-to-html.es.js",
|
|
15
|
+
"require": "./dist/pdf-to-html.cjs.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"pdf-to-html.ts",
|
|
21
|
+
"models",
|
|
22
|
+
"transforms",
|
|
23
|
+
"utils"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "vite build",
|
|
27
|
+
"ship": "npm run build && npx standard-version --release-as patch; rm -f CHANGELOG.md; npm publish"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"grab-url": "^1.6.19"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"terser": "^5.46.0",
|
|
34
|
+
"typescript": "^5.9.3",
|
|
35
|
+
"vite": "^7.3.1",
|
|
36
|
+
"vite-plugin-dts": "^4.5.4"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"pdf",
|
|
40
|
+
"html",
|
|
41
|
+
"pdf-parser",
|
|
42
|
+
"pdfjs",
|
|
43
|
+
"pdf-to-text",
|
|
44
|
+
"document-extraction"
|
|
45
|
+
],
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/vtempest/qwksearch-research-agent"
|
|
49
|
+
}
|
|
50
|
+
}
|