@boxpdf/html-writer 0.1.2 → 0.1.8
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 +13 -6
- package/dist/index.cjs +286 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +286 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@boxpdf/html-writer`
|
|
2
2
|
|
|
3
|
-
Streams
|
|
3
|
+
Streams visual or semantic HTML from pages produced by `@boxpdf/reader`.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { open } from "node:fs/promises";
|
|
@@ -15,7 +15,7 @@ const output = await open("output.html", "w");
|
|
|
15
15
|
try {
|
|
16
16
|
await writeHtmlDocument(pdf.pages(), async (chunk) => {
|
|
17
17
|
await output.write(chunk);
|
|
18
|
-
});
|
|
18
|
+
}, { profile: "visual" });
|
|
19
19
|
} finally {
|
|
20
20
|
await output.close();
|
|
21
21
|
pdf.close();
|
|
@@ -23,9 +23,16 @@ try {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
The default `
|
|
27
|
-
`
|
|
28
|
-
|
|
26
|
+
The default `visual` profile preserves page dimensions and text coordinates for
|
|
27
|
+
display presentation. The `semantic` profile uses inferred reading order,
|
|
28
|
+
lines, nesting, and tables to produce reflowable HTML. The visual model comes
|
|
29
|
+
first: semantic structure is derived from the complete page evidence rather
|
|
30
|
+
than inferred after presentation information has been discarded.
|
|
31
|
+
|
|
32
|
+
The legacy `layout: "positioned" | "flow"` option remains as an alias for
|
|
33
|
+
`profile: "visual" | "semantic"`. The current visual output surface excludes
|
|
34
|
+
images, vector graphics, and exact font reproduction; the PDFium parity report
|
|
35
|
+
tracks progress toward complete display presentation.
|
|
29
36
|
|
|
30
37
|
The callback is awaited for every chunk, so a file stream, HTTP response, or
|
|
31
38
|
Web `WritableStream` can apply backpressure. The caller owns and closes the PDF
|
|
@@ -41,7 +48,7 @@ Poppler's `pdftohtml -c -hidden -noframes -zoom 1` output. Poppler serves as an
|
|
|
41
48
|
independent test oracle. The writer's memory contract covers the reader and
|
|
42
49
|
HTML serialization.
|
|
43
50
|
|
|
44
|
-
`pnpm poppler:report` runs the
|
|
51
|
+
`pnpm poppler:report` runs the visual writer over all 62 text fixtures in
|
|
45
52
|
the pinned PDF.js corpus. The checked-in baseline currently records exact text
|
|
46
53
|
and geometry agreement on 51 fixtures. The remaining cases are retained in the
|
|
47
54
|
denominator; most exercise intentional PDF.js/Poppler differences in RTL text,
|
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
var import_structure = require("@boxpdf/reader/structure");
|
|
29
|
-
var styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-
|
|
29
|
+
var styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--visual,.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--semantic,.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--semantic p,.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;
|
|
30
30
|
async function writeHtmlDocument(pages, write, options = {}) {
|
|
31
31
|
const includeDocument = options.includeDocument ?? true;
|
|
32
32
|
if (includeDocument) {
|
|
@@ -45,8 +45,8 @@ async function writeHtmlDocument(pages, write, options = {}) {
|
|
|
45
45
|
if (includeDocument) await write("</body></html>");
|
|
46
46
|
}
|
|
47
47
|
async function writePage(page, write, options = {}) {
|
|
48
|
-
if ((options
|
|
49
|
-
else await writePositionedPage(page, write);
|
|
48
|
+
if (resolveProfile(options) === "semantic") await writeFlowPage(page, write);
|
|
49
|
+
else await writePositionedPage(page, write, options);
|
|
50
50
|
}
|
|
51
51
|
async function pageToHtml(page, options = {}) {
|
|
52
52
|
let output = "";
|
|
@@ -59,24 +59,151 @@ async function pageToHtml(page, options = {}) {
|
|
|
59
59
|
);
|
|
60
60
|
return output;
|
|
61
61
|
}
|
|
62
|
-
async function writePositionedPage(page, write) {
|
|
62
|
+
async function writePositionedPage(page, write, options) {
|
|
63
|
+
const visualSpans = page.visualSpans ?? page.spans;
|
|
64
|
+
const reflectedOverlay = usesReflectedVisualOverlay(page, visualSpans);
|
|
63
65
|
const quarterTurn = page.rotate === 90 || page.rotate === 270;
|
|
64
66
|
const displayWidth = quarterTurn ? page.height : page.width;
|
|
65
67
|
const displayHeight = quarterTurn ? page.width : page.height;
|
|
66
68
|
await write(
|
|
67
|
-
`<section class="pdf-page pdf-page--positioned" data-page="${page.number}" data-rotate="${page.rotate}" style="width:${number(displayWidth)}pt;height:${number(displayHeight)}pt">`
|
|
69
|
+
`<section class="pdf-page pdf-page--visual pdf-page--positioned" data-page="${page.number}" data-rotate="${page.rotate}" style="width:${number(displayWidth)}pt;height:${number(displayHeight)}pt">`
|
|
70
|
+
);
|
|
71
|
+
const fontAliases = new Map(
|
|
72
|
+
(page.fonts ?? []).filter((font) => font.format === "truetype" && !/(?:courier|^TTE)/i.test(font.family ?? "")).map((font) => [font.id, `boxpdf-${page.number}-${font.id}`])
|
|
73
|
+
);
|
|
74
|
+
const type3Fonts = new Map(
|
|
75
|
+
(page.fonts ?? []).filter((font) => font.format === "type3").map((font) => [font.id, font])
|
|
76
|
+
);
|
|
77
|
+
if ((options.includeStyles ?? true) && page.fonts?.length) {
|
|
78
|
+
await write(`<style>${page.fonts.map((font) => fontFace(font, fontAliases)).join("")}</style>`);
|
|
79
|
+
}
|
|
80
|
+
await write(
|
|
81
|
+
`<div class="pdf-page-content pdf-page-content--${page.rotate}" style="width:${number(page.width)}pt;height:${number(page.height)}pt${rotationTransform(page)}">`
|
|
68
82
|
);
|
|
69
83
|
await write(
|
|
70
|
-
`<
|
|
84
|
+
`<svg class="pdf-visual-text" xmlns="http://www.w3.org/2000/svg" width="${number(page.width)}pt" height="${number(page.height)}pt" viewBox="0 0 ${number(page.width)} ${number(page.height)}">`
|
|
71
85
|
);
|
|
72
|
-
|
|
86
|
+
if (reflectedOverlay) {
|
|
87
|
+
for (const image of page.images ?? []) await write(visualImage(image, page.height));
|
|
88
|
+
}
|
|
89
|
+
for (const fill of page.fills ?? []) {
|
|
90
|
+
const points = fill.points.map(([x, y]) => `${number(x)},${number(page.height - y)}`).join(" ");
|
|
91
|
+
if (isCssHexColor(fill.color)) {
|
|
92
|
+
const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity="${number(fill.opacity)}"` : "";
|
|
93
|
+
await write(`<polygon points="${points}" fill="${fill.color}"${opacity}/>`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (page.paths?.length) {
|
|
97
|
+
await write(`<g transform="translate(0 ${number(page.height)}) scale(1 -1)">`);
|
|
98
|
+
for (const path of page.paths) {
|
|
99
|
+
if (!isSvgPath(path.d)) continue;
|
|
100
|
+
const fill = isCssHexColor(path.fill) ? path.fill : "none";
|
|
101
|
+
const stroke = isCssHexColor(path.stroke) ? path.stroke : "none";
|
|
102
|
+
const strokeWidth = path.strokeWidth !== void 0 && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0 ? ` stroke-width="${number(path.strokeWidth)}"` : "";
|
|
103
|
+
const fillRule = path.fillRule ? ` fill-rule="${path.fillRule}"` : "";
|
|
104
|
+
const fillOpacity = isUnitInterval(path.fillOpacity) ? ` fill-opacity="${number(path.fillOpacity)}"` : "";
|
|
105
|
+
const strokeOpacity = isUnitInterval(path.strokeOpacity) ? ` stroke-opacity="${number(path.strokeOpacity)}"` : "";
|
|
106
|
+
const dasharray = path.strokeDasharray?.every((value) => Number.isFinite(value) && value >= 0) ? ` stroke-dasharray="${path.strokeDasharray.map(number).join(" ")}"` : "";
|
|
107
|
+
const dashoffset = Number.isFinite(path.strokeDashoffset) ? ` stroke-dashoffset="${number(path.strokeDashoffset ?? 0)}"` : "";
|
|
108
|
+
const linecap = path.strokeLinecap ? ` stroke-linecap="${path.strokeLinecap}"` : "";
|
|
109
|
+
const linejoin = path.strokeLinejoin ? ` stroke-linejoin="${path.strokeLinejoin}"` : "";
|
|
110
|
+
await write(
|
|
111
|
+
`<path d="${path.d}" fill="${fill}" stroke="${stroke}"${strokeWidth}${fillOpacity}${strokeOpacity}${dasharray}${dashoffset}${linecap}${linejoin}${fillRule}/>`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
await write("</g>");
|
|
115
|
+
}
|
|
116
|
+
if (!reflectedOverlay) {
|
|
117
|
+
for (const image of page.images ?? []) await write(visualImage(image, page.height));
|
|
118
|
+
}
|
|
119
|
+
for (const span of visualSpans) {
|
|
120
|
+
if (!usesPositionedSpan(span)) {
|
|
121
|
+
const type3 = span.fontAssetId ? type3Fonts.get(span.fontAssetId) : void 0;
|
|
122
|
+
await write(
|
|
123
|
+
type3 ? visualType3Text(span, type3, page.height) : visualText(span, page.height, fontAliases, reflectedOverlay && page.rotate === 180)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
await write("</svg>");
|
|
128
|
+
for (const span of visualSpans) {
|
|
129
|
+
if (usesPositionedSpan(span)) await write(positionedSpan(span, fontAliases));
|
|
130
|
+
}
|
|
73
131
|
await write("</div></section>");
|
|
74
132
|
}
|
|
133
|
+
function usesReflectedVisualOverlay(page, spans) {
|
|
134
|
+
return Boolean(page.images?.length) && Boolean(page.paths?.length || page.fills?.length) && spans.length > 0 && spans.every(
|
|
135
|
+
(span) => span.transform !== void 0 && Math.abs(span.transform[0] + 1) < 1e-6 && Math.abs(span.transform[1]) < 1e-6 && Math.abs(span.transform[2]) < 1e-6 && Math.abs(span.transform[3] - 1) < 1e-6
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function visualImage(image, pageHeight) {
|
|
139
|
+
const [a, b, c, d, e, f] = image.transform;
|
|
140
|
+
const transform = [a, -b, -c, d, c + e, pageHeight - d - f].map(number).join(" ");
|
|
141
|
+
const opacity = isUnitInterval(image.opacity) ? ` opacity="${number(image.opacity)}"` : "";
|
|
142
|
+
const mime = image.format === "jpeg" ? "image/jpeg" : "image/bmp";
|
|
143
|
+
const data = image.format === "jpeg" ? image.data : rgbBmp(image);
|
|
144
|
+
return `<image width="1" height="1" preserveAspectRatio="none" transform="matrix(${transform})" href="data:${mime};base64,${base64(data)}"${opacity}/>`;
|
|
145
|
+
}
|
|
146
|
+
function rgbBmp(image) {
|
|
147
|
+
const stride = Math.ceil(image.width * 3 / 4) * 4;
|
|
148
|
+
const output = new Uint8Array(54 + stride * image.height);
|
|
149
|
+
const view = new DataView(output.buffer);
|
|
150
|
+
output[0] = 66;
|
|
151
|
+
output[1] = 77;
|
|
152
|
+
view.setUint32(2, output.length, true);
|
|
153
|
+
view.setUint32(10, 54, true);
|
|
154
|
+
view.setUint32(14, 40, true);
|
|
155
|
+
view.setInt32(18, image.width, true);
|
|
156
|
+
view.setInt32(22, -image.height, true);
|
|
157
|
+
view.setUint16(26, 1, true);
|
|
158
|
+
view.setUint16(28, 24, true);
|
|
159
|
+
view.setUint32(34, stride * image.height, true);
|
|
160
|
+
for (let row = 0; row < image.height; row += 1) {
|
|
161
|
+
for (let column = 0; column < image.width; column += 1) {
|
|
162
|
+
const source = (row * image.width + column) * 3;
|
|
163
|
+
const target = 54 + row * stride + column * 3;
|
|
164
|
+
output[target] = image.data[source + 2] ?? 0;
|
|
165
|
+
output[target + 1] = image.data[source + 1] ?? 0;
|
|
166
|
+
output[target + 2] = image.data[source] ?? 0;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return output;
|
|
170
|
+
}
|
|
171
|
+
function rotationTransform(page) {
|
|
172
|
+
switch (page.rotate) {
|
|
173
|
+
case 90:
|
|
174
|
+
return `;transform:translate(${number(page.height)}pt,0) rotate(90deg)`;
|
|
175
|
+
case 180:
|
|
176
|
+
return `;transform:translate(${number(page.width)}pt,${number(page.height)}pt) rotate(180deg)`;
|
|
177
|
+
case 270:
|
|
178
|
+
return `;transform:translate(0,${number(page.width)}pt) rotate(270deg)`;
|
|
179
|
+
default:
|
|
180
|
+
return "";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function positionedSpan(span, fontAliases) {
|
|
184
|
+
const direction = directionAttribute([span]);
|
|
185
|
+
const style = [
|
|
186
|
+
`left:${number(span.bounds.x)}pt`,
|
|
187
|
+
`bottom:${number(span.bounds.y)}pt`,
|
|
188
|
+
`width:${number(span.bounds.width)}pt`,
|
|
189
|
+
`height:${number(span.bounds.height)}pt`,
|
|
190
|
+
`font-size:${number(span.fontSize)}pt`,
|
|
191
|
+
...isCssHexColor(span.color) ? [`color:${span.color}`] : [],
|
|
192
|
+
...isUnitInterval(span.fillOpacity) ? [`opacity:${number(span.fillOpacity)}`] : [],
|
|
193
|
+
...fontStyles(
|
|
194
|
+
span.fontFamily,
|
|
195
|
+
span.fontAssetId ? fontAliases.get(span.fontAssetId) : void 0
|
|
196
|
+
)
|
|
197
|
+
].join(";");
|
|
198
|
+
return `<span class="pdf-span"${direction} style="${style}">${escapeHtml(span.text)}</span>`;
|
|
199
|
+
}
|
|
75
200
|
async function writeFlowPage(page, write) {
|
|
76
201
|
const structured = (0, import_structure.structurePage)(page);
|
|
77
202
|
const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);
|
|
78
203
|
const emittedTables = /* @__PURE__ */ new Set();
|
|
79
|
-
await write(
|
|
204
|
+
await write(
|
|
205
|
+
`<section class="pdf-page pdf-page--semantic pdf-page--flow" data-page="${page.number}">`
|
|
206
|
+
);
|
|
80
207
|
for (const line of structured.lines) {
|
|
81
208
|
const table = tables.find((candidate) => containsY(candidate, line.bounds.y));
|
|
82
209
|
if (table) {
|
|
@@ -93,16 +220,150 @@ async function writeFlowPage(page, write) {
|
|
|
93
220
|
}
|
|
94
221
|
await write("</section>");
|
|
95
222
|
}
|
|
96
|
-
function
|
|
223
|
+
function visualText(span, pageHeight, fontAliases, counterRotateReflectedText = false) {
|
|
224
|
+
if (span.renderingMode === 3 || span.renderingMode === 7) return "";
|
|
225
|
+
if (!span.fontAssetId && isAdobeCjkFont(span.fontFamily)) return "";
|
|
97
226
|
const direction = directionAttribute([span]);
|
|
227
|
+
const font = fontStyles(
|
|
228
|
+
span.fontFamily,
|
|
229
|
+
span.fontAssetId ? fontAliases.get(span.fontAssetId) : void 0
|
|
230
|
+
).join(";");
|
|
231
|
+
const stroke = isCssHexColor(span.strokeColor) ? `stroke:${span.strokeColor}` : "";
|
|
232
|
+
const strokeWidth = stroke && Number.isFinite(span.strokeWidth) && (span.strokeWidth ?? -1) >= 0 ? `stroke-width:${number(span.strokeWidth ?? 0)}` : "";
|
|
233
|
+
const strokeOnly = span.renderingMode === 1 || span.renderingMode === 5;
|
|
234
|
+
const fillOpacity = isUnitInterval(span.fillOpacity) ? `fill-opacity:${number(span.fillOpacity)}` : "";
|
|
235
|
+
const strokeOpacity = isUnitInterval(span.strokeOpacity) ? `stroke-opacity:${number(span.strokeOpacity)}` : "";
|
|
98
236
|
const style = [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
237
|
+
isHebrewPaintOrder(span) ? "unicode-bidi:bidi-override;direction:ltr" : "",
|
|
238
|
+
span.direction === "ttb" ? "writing-mode:vertical-rl" : "",
|
|
239
|
+
strokeOnly ? "fill:none" : isCssHexColor(span.color) ? `fill:${span.color}` : "",
|
|
240
|
+
stroke,
|
|
241
|
+
strokeWidth,
|
|
242
|
+
fillOpacity,
|
|
243
|
+
strokeOpacity,
|
|
244
|
+
font
|
|
245
|
+
].filter(Boolean).join(";");
|
|
246
|
+
const textExtent = span.direction === "ttb" ? span.bounds.height : span.bounds.width;
|
|
247
|
+
const textLength = textExtent > 0 && !isHebrewPaintOrder(span) ? ` textLength="${number(textExtent)}" lengthAdjust="${span.direction === "ttb" || usesSpacingAdjustment(span) ? "spacing" : "spacingAndGlyphs"}"` : "";
|
|
248
|
+
const transform = counterRotateReflectedText && span.transform ? [
|
|
249
|
+
span.transform[0],
|
|
250
|
+
span.transform[1],
|
|
251
|
+
span.transform[2],
|
|
252
|
+
-span.transform[3]
|
|
253
|
+
] : span.transform;
|
|
254
|
+
const transformed = hasNonIdentityTransform(transform);
|
|
255
|
+
const rtlOffset = span.direction === "rtl" ? span.bounds.width : 0;
|
|
256
|
+
const basisX = transform?.[0] ?? 1;
|
|
257
|
+
const basisY = transform?.[1] ?? 0;
|
|
258
|
+
const anchorX = span.bounds.x + basisX * rtlOffset;
|
|
259
|
+
const anchorY = pageHeight - span.bounds.y + basisY * rtlOffset;
|
|
260
|
+
const position = transformed ? ` x="0" y="0" transform="matrix(${transform?.map(number).join(" ")} ${number(anchorX)} ${number(anchorY)})"` : ` x="${number(anchorX)}" y="${number(anchorY)}"`;
|
|
261
|
+
return `<text${direction}${position} font-size="${number(span.fontSize)}"${textLength}${style ? ` style="${style}"` : ""}>${escapeHtml(span.text)}</text>`;
|
|
262
|
+
}
|
|
263
|
+
function isAdobeCjkFont(fontFamily) {
|
|
264
|
+
return /^Adobe(?:Heiti|Song|Kaiti|Ming|Gothic|Mincho)Std-/i.test(fontFamily ?? "");
|
|
265
|
+
}
|
|
266
|
+
function visualType3Text(span, font, pageHeight) {
|
|
267
|
+
if (span.renderingMode === 3 || span.renderingMode === 7) return "";
|
|
268
|
+
const glyphs = new Map(font.glyphs.map((glyph) => [glyph.code, glyph]));
|
|
269
|
+
const sequence = (span.glyphCodes ?? []).map((code) => glyphs.get(code));
|
|
270
|
+
const totalAdvance = sequence.reduce((total, glyph) => total + (glyph?.advance ?? 0), 0);
|
|
271
|
+
if (totalAdvance <= 0 || span.bounds.width <= 0 || span.fontSize <= 0) return "";
|
|
272
|
+
const transform = span.transform ?? [1, 0, 0, 1];
|
|
273
|
+
const outer = `matrix(${transform.map(number).join(" ")} ${number(span.bounds.x)} ${number(pageHeight - span.bounds.y)})`;
|
|
274
|
+
const xScale = span.bounds.width / totalAdvance;
|
|
275
|
+
let offset = 0;
|
|
276
|
+
let content = "";
|
|
277
|
+
for (const glyph of sequence) {
|
|
278
|
+
if (!glyph) continue;
|
|
279
|
+
content += `<g transform="translate(${number(offset)} 0)">${type3Glyph(glyph)}</g>`;
|
|
280
|
+
offset += glyph.advance;
|
|
281
|
+
}
|
|
282
|
+
return `<g transform="${outer}"><g transform="scale(${number(xScale)} ${number(-span.fontSize)})">${content}</g></g>`;
|
|
283
|
+
}
|
|
284
|
+
function isHebrewPaintOrder(span) {
|
|
285
|
+
return span.direction === "ltr" && /[\u0590-\u05ff]/u.test(span.text);
|
|
286
|
+
}
|
|
287
|
+
function usesSpacingAdjustment(span) {
|
|
288
|
+
return !span.fontAssetId && /arial/i.test(span.fontFamily ?? "");
|
|
289
|
+
}
|
|
290
|
+
function type3Glyph(glyph) {
|
|
291
|
+
let output = "";
|
|
292
|
+
for (const fill of glyph.fills ?? []) {
|
|
293
|
+
if (!isCssHexColor(fill.color)) continue;
|
|
294
|
+
const points = fill.points.map(([x, y]) => `${number(x)},${number(y)}`).join(" ");
|
|
295
|
+
const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity="${number(fill.opacity)}"` : "";
|
|
296
|
+
output += `<polygon points="${points}" fill="${fill.color}"${opacity}/>`;
|
|
297
|
+
}
|
|
298
|
+
for (const path of glyph.paths ?? []) {
|
|
299
|
+
if (!isSvgPath(path.d)) continue;
|
|
300
|
+
const fill = isCssHexColor(path.fill) ? path.fill : "none";
|
|
301
|
+
const stroke = isCssHexColor(path.stroke) ? path.stroke : "none";
|
|
302
|
+
const width = path.strokeWidth !== void 0 && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0 ? ` stroke-width="${number(path.strokeWidth)}"` : "";
|
|
303
|
+
output += `<path d="${path.d}" fill="${fill}" stroke="${stroke}"${width}/>`;
|
|
304
|
+
}
|
|
305
|
+
return (glyph.fills?.length ?? 0) > 64 && glyph.advance > 2 ? `<g shape-rendering="crispEdges">${output}</g>` : output;
|
|
306
|
+
}
|
|
307
|
+
function isCssHexColor(value) {
|
|
308
|
+
return /^#[\da-f]{6}$/i.test(value ?? "");
|
|
309
|
+
}
|
|
310
|
+
function isUnitInterval(value) {
|
|
311
|
+
return Number.isFinite(value) && (value ?? -1) >= 0 && (value ?? 2) <= 1;
|
|
312
|
+
}
|
|
313
|
+
function isSvgPath(value) {
|
|
314
|
+
return value.length <= 1e6 && /^[\d\s.,+\-eEMmLlCcZz]+$/.test(value);
|
|
315
|
+
}
|
|
316
|
+
function fontStyles(fontFamily, alias) {
|
|
317
|
+
const normalized = fontFamily?.toLowerCase() ?? "";
|
|
318
|
+
const styles2 = [];
|
|
319
|
+
let fallback;
|
|
320
|
+
if (/courier|mono|nimbusmono|^cmtt/.test(normalized)) {
|
|
321
|
+
fallback = "Courier New,Courier,monospace";
|
|
322
|
+
} else if (/times|minion|serif|baskerville|georgia|nimbusrom|guardian.*egyp|^cm[rs]y?\d/.test(normalized)) {
|
|
323
|
+
fallback = "Times New Roman,Times,serif";
|
|
324
|
+
} else if (/helvetica|arial|sans|nimbussan|calibre|myriad|panton|^tte/.test(normalized)) {
|
|
325
|
+
fallback = "Arial,Helvetica,sans-serif";
|
|
326
|
+
} else if (/^mstt/.test(normalized)) {
|
|
327
|
+
fallback = "Arial,Helvetica,sans-serif";
|
|
328
|
+
}
|
|
329
|
+
if (alias || fallback) styles2.push(`font-family:${[alias, fallback].filter(Boolean).join(",")}`);
|
|
330
|
+
if (/bold|black|semibold|demi|medi|^tte/.test(normalized)) styles2.push("font-weight:700");
|
|
331
|
+
if (/italic|oblique|slant|ital(?:$|[_-])/.test(normalized)) styles2.push("font-style:italic");
|
|
332
|
+
return styles2;
|
|
333
|
+
}
|
|
334
|
+
function isMonospace(fontFamily) {
|
|
335
|
+
return /courier|mono/i.test(fontFamily ?? "");
|
|
336
|
+
}
|
|
337
|
+
function usesPositionedSpan(span) {
|
|
338
|
+
return !span.glyphCodes && isMonospace(span.fontFamily) && !hasNonIdentityTransform(span.transform);
|
|
339
|
+
}
|
|
340
|
+
function hasNonIdentityTransform(transform) {
|
|
341
|
+
if (!transform) return false;
|
|
342
|
+
const identity = [1, 0, 0, 1];
|
|
343
|
+
return transform.some((value, index) => Math.abs(value - (identity[index] ?? 0)) > 1e-6);
|
|
344
|
+
}
|
|
345
|
+
function fontFace(font, aliases) {
|
|
346
|
+
if (font.format !== "truetype") return "";
|
|
347
|
+
const alias = aliases.get(font.id);
|
|
348
|
+
if (!alias) return "";
|
|
349
|
+
const styles2 = fontStyles(font.family, alias).filter(
|
|
350
|
+
(style) => !style.startsWith("font-family:")
|
|
351
|
+
);
|
|
352
|
+
return `@font-face{font-family:${alias};src:url(data:font/ttf;base64,${base64(font.data)}) format("truetype");${styles2.join(";")}}`;
|
|
353
|
+
}
|
|
354
|
+
function base64(bytes) {
|
|
355
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
356
|
+
let output = "";
|
|
357
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
358
|
+
const first = bytes[index] ?? 0;
|
|
359
|
+
const second = bytes[index + 1] ?? 0;
|
|
360
|
+
const third = bytes[index + 2] ?? 0;
|
|
361
|
+
output += alphabet[first >> 2];
|
|
362
|
+
output += alphabet[(first & 3) << 4 | second >> 4];
|
|
363
|
+
output += index + 1 < bytes.length ? alphabet[(second & 15) << 2 | third >> 6] : "=";
|
|
364
|
+
output += index + 2 < bytes.length ? alphabet[third & 63] : "=";
|
|
365
|
+
}
|
|
366
|
+
return output;
|
|
106
367
|
}
|
|
107
368
|
function directionAttribute(spans) {
|
|
108
369
|
const rtl = spans.filter((span) => span.direction === "rtl").length;
|
|
@@ -129,6 +390,15 @@ function escapeHtml(value) {
|
|
|
129
390
|
function isForbiddenControl(codePoint) {
|
|
130
391
|
return codePoint <= 8 || codePoint === 11 || codePoint === 12 || codePoint >= 14 && codePoint <= 31 || codePoint === 127;
|
|
131
392
|
}
|
|
393
|
+
function resolveProfile(options) {
|
|
394
|
+
const legacyProfile = options.layout === "flow" ? "semantic" : "visual";
|
|
395
|
+
if (options.profile && options.layout && options.profile !== legacyProfile) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
`conflicting HTML output options: profile "${options.profile}" does not match layout "${options.layout}"`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
return options.profile ?? legacyProfile;
|
|
401
|
+
}
|
|
132
402
|
// Annotate the CommonJS export names for ESM import in node:
|
|
133
403
|
0 && (module.exports = {
|
|
134
404
|
pageToHtml,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { ExtractedPage, TextSpan } from \"@boxpdf/reader\";\nimport { structurePage, type Table, tableToHtml } from \"@boxpdf/reader/structure\";\n\nexport type HtmlLayout = \"positioned\" | \"flow\";\nexport type HtmlWrite = (chunk: string) => void | Promise<void>;\n\nexport interface HtmlWriterOptions {\n layout?: HtmlLayout;\n title?: string;\n language?: string;\n includeDocument?: boolean;\n includeStyles?: boolean;\n}\n\nconst styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-page-content--90{transform:translateX(100%) rotate(90deg)}.pdf-page-content--180{transform:translate(100%,100%) rotate(180deg)}.pdf-page-content--270{transform:translateY(100%) rotate(270deg)}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;\n\nexport async function writeHtmlDocument(\n pages: AsyncIterable<ExtractedPage> | Iterable<ExtractedPage>,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n const includeDocument = options.includeDocument ?? true;\n if (includeDocument) {\n await write(\"<!doctype html><html\");\n await write(\n ` lang=\"${escapeAttribute(options.language ?? \"en\")}\"><head><meta charset=\"utf-8\">`,\n );\n await write('<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">');\n await write(`<title>${escapeHtml(options.title ?? \"PDF document\")}</title>`);\n if (options.includeStyles ?? true) await write(`<style>${styles}</style>`);\n await write(\"</head><body>\");\n }\n await write('<main class=\"pdf-document\">');\n for await (const page of pages) await writePage(page, write, options);\n await write(\"</main>\");\n if (includeDocument) await write(\"</body></html>\");\n}\n\nexport async function writePage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n if ((options.layout ?? \"positioned\") === \"flow\") await writeFlowPage(page, write);\n else await writePositionedPage(page, write);\n}\n\nexport async function pageToHtml(\n page: ExtractedPage,\n options: HtmlWriterOptions = {},\n): Promise<string> {\n let output = \"\";\n await writePage(\n page,\n (chunk) => {\n output += chunk;\n },\n options,\n );\n return output;\n}\n\nasync function writePositionedPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const quarterTurn = page.rotate === 90 || page.rotate === 270;\n const displayWidth = quarterTurn ? page.height : page.width;\n const displayHeight = quarterTurn ? page.width : page.height;\n await write(\n `<section class=\"pdf-page pdf-page--positioned\" data-page=\"${page.number}\" data-rotate=\"${page.rotate}\" style=\"width:${number(displayWidth)}pt;height:${number(displayHeight)}pt\">`,\n );\n await write(\n `<div class=\"pdf-page-content pdf-page-content--${page.rotate}\" style=\"width:${number(page.width)}pt;height:${number(page.height)}pt\">`,\n );\n for (const span of page.spans) await write(positionedSpan(span));\n await write(\"</div></section>\");\n}\n\nasync function writeFlowPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const structured = structurePage(page);\n const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);\n const emittedTables = new Set<Table>();\n await write(`<section class=\"pdf-page pdf-page--flow\" data-page=\"${page.number}\">`);\n for (const line of structured.lines) {\n const table = tables.find((candidate) => containsY(candidate, line.bounds.y));\n if (table) {\n if (!emittedTables.has(table)) {\n await write(tableToHtml(table));\n emittedTables.add(table);\n }\n continue;\n }\n await write(`<p${directionAttribute(line.spans)}>${escapeHtml(line.text)}</p>`);\n }\n for (const table of tables) {\n if (!emittedTables.has(table)) await write(tableToHtml(table));\n }\n await write(\"</section>\");\n}\n\nfunction positionedSpan(span: TextSpan): string {\n const direction = directionAttribute([span]);\n const style = [\n `left:${number(span.bounds.x)}pt`,\n `bottom:${number(span.bounds.y)}pt`,\n `width:${number(span.bounds.width)}pt`,\n `height:${number(span.bounds.height)}pt`,\n `font-size:${number(span.fontSize)}pt`,\n ].join(\";\");\n return `<span class=\"pdf-span\"${direction} style=\"${style}\">${escapeHtml(span.text)}</span>`;\n}\n\nfunction directionAttribute(spans: TextSpan[]): string {\n const rtl = spans.filter((span) => span.direction === \"rtl\").length;\n const vertical = spans.filter((span) => span.direction === \"ttb\").length;\n if (vertical > rtl && vertical * 2 >= spans.length) return ' data-direction=\"ttb\"';\n return rtl * 2 >= spans.length && spans.length > 0 ? ' dir=\"rtl\"' : \"\";\n}\n\nfunction containsY(table: Table, y: number): boolean {\n return y >= table.bounds.y && y <= table.bounds.y + table.bounds.height;\n}\n\nfunction number(value: number): string {\n return Number.isFinite(value) ? String(Math.round(value * 1000) / 1000) : \"0\";\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll(\"`\", \"`\");\n}\n\nfunction escapeHtml(value: string): string {\n return [...value]\n .map((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (codePoint === 13) return \"\\n\";\n return isForbiddenControl(codePoint) ? \"�\" : character;\n })\n .join(\"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nfunction isForbiddenControl(codePoint: number): boolean {\n return (\n codePoint <= 8 ||\n codePoint === 11 ||\n codePoint === 12 ||\n (codePoint >= 14 && codePoint <= 31) ||\n codePoint === 127\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n EmbeddedFont,\n EmbeddedType3Font,\n ExtractedPage,\n RasterImage,\n TextSpan,\n Type3Glyph,\n} from \"@boxpdf/reader\";\nimport { structurePage, type Table, tableToHtml } from \"@boxpdf/reader/structure\";\n\nexport type HtmlLayout = \"positioned\" | \"flow\";\nexport type HtmlProfile = \"visual\" | \"semantic\";\nexport type HtmlWrite = (chunk: string) => void | Promise<void>;\n\nexport interface HtmlWriterOptions {\n /** Output intent. Visual preserves page presentation; semantic prioritizes reading order. */\n profile?: HtmlProfile;\n /** @deprecated Use `profile: \"visual\"` or `profile: \"semantic\"`. */\n layout?: HtmlLayout;\n title?: string;\n language?: string;\n includeDocument?: boolean;\n includeStyles?: boolean;\n}\n\nconst styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--visual,.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--semantic,.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--semantic p,.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;\n\nexport async function writeHtmlDocument(\n pages: AsyncIterable<ExtractedPage> | Iterable<ExtractedPage>,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n const includeDocument = options.includeDocument ?? true;\n if (includeDocument) {\n await write(\"<!doctype html><html\");\n await write(\n ` lang=\"${escapeAttribute(options.language ?? \"en\")}\"><head><meta charset=\"utf-8\">`,\n );\n await write('<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">');\n await write(`<title>${escapeHtml(options.title ?? \"PDF document\")}</title>`);\n if (options.includeStyles ?? true) await write(`<style>${styles}</style>`);\n await write(\"</head><body>\");\n }\n await write('<main class=\"pdf-document\">');\n for await (const page of pages) await writePage(page, write, options);\n await write(\"</main>\");\n if (includeDocument) await write(\"</body></html>\");\n}\n\nexport async function writePage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n if (resolveProfile(options) === \"semantic\") await writeFlowPage(page, write);\n else await writePositionedPage(page, write, options);\n}\n\nexport async function pageToHtml(\n page: ExtractedPage,\n options: HtmlWriterOptions = {},\n): Promise<string> {\n let output = \"\";\n await writePage(\n page,\n (chunk) => {\n output += chunk;\n },\n options,\n );\n return output;\n}\n\nasync function writePositionedPage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions,\n): Promise<void> {\n const visualSpans = page.visualSpans ?? page.spans;\n const reflectedOverlay = usesReflectedVisualOverlay(page, visualSpans);\n const quarterTurn = page.rotate === 90 || page.rotate === 270;\n const displayWidth = quarterTurn ? page.height : page.width;\n const displayHeight = quarterTurn ? page.width : page.height;\n await write(\n `<section class=\"pdf-page pdf-page--visual pdf-page--positioned\" data-page=\"${page.number}\" data-rotate=\"${page.rotate}\" style=\"width:${number(displayWidth)}pt;height:${number(displayHeight)}pt\">`,\n );\n const fontAliases = new Map(\n (page.fonts ?? [])\n .filter((font) => font.format === \"truetype\" && !/(?:courier|^TTE)/i.test(font.family ?? \"\"))\n .map((font) => [font.id, `boxpdf-${page.number}-${font.id}`]),\n );\n const type3Fonts = new Map(\n (page.fonts ?? [])\n .filter((font): font is EmbeddedType3Font => font.format === \"type3\")\n .map((font) => [font.id, font]),\n );\n if ((options.includeStyles ?? true) && page.fonts?.length) {\n await write(`<style>${page.fonts.map((font) => fontFace(font, fontAliases)).join(\"\")}</style>`);\n }\n await write(\n `<div class=\"pdf-page-content pdf-page-content--${page.rotate}\" style=\"width:${number(page.width)}pt;height:${number(page.height)}pt${rotationTransform(page)}\">`,\n );\n await write(\n `<svg class=\"pdf-visual-text\" xmlns=\"http://www.w3.org/2000/svg\" width=\"${number(page.width)}pt\" height=\"${number(page.height)}pt\" viewBox=\"0 0 ${number(page.width)} ${number(page.height)}\">`,\n );\n if (reflectedOverlay) {\n for (const image of page.images ?? []) await write(visualImage(image, page.height));\n }\n for (const fill of page.fills ?? []) {\n const points = fill.points.map(([x, y]) => `${number(x)},${number(page.height - y)}`).join(\" \");\n if (isCssHexColor(fill.color)) {\n const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity=\"${number(fill.opacity)}\"` : \"\";\n await write(`<polygon points=\"${points}\" fill=\"${fill.color}\"${opacity}/>`);\n }\n }\n if (page.paths?.length) {\n await write(`<g transform=\"translate(0 ${number(page.height)}) scale(1 -1)\">`);\n for (const path of page.paths) {\n if (!isSvgPath(path.d)) continue;\n const fill = isCssHexColor(path.fill) ? path.fill : \"none\";\n const stroke = isCssHexColor(path.stroke) ? path.stroke : \"none\";\n const strokeWidth =\n path.strokeWidth !== undefined && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0\n ? ` stroke-width=\"${number(path.strokeWidth)}\"`\n : \"\";\n const fillRule = path.fillRule ? ` fill-rule=\"${path.fillRule}\"` : \"\";\n const fillOpacity = isUnitInterval(path.fillOpacity)\n ? ` fill-opacity=\"${number(path.fillOpacity)}\"`\n : \"\";\n const strokeOpacity = isUnitInterval(path.strokeOpacity)\n ? ` stroke-opacity=\"${number(path.strokeOpacity)}\"`\n : \"\";\n const dasharray = path.strokeDasharray?.every((value) => Number.isFinite(value) && value >= 0)\n ? ` stroke-dasharray=\"${path.strokeDasharray.map(number).join(\" \")}\"`\n : \"\";\n const dashoffset = Number.isFinite(path.strokeDashoffset)\n ? ` stroke-dashoffset=\"${number(path.strokeDashoffset ?? 0)}\"`\n : \"\";\n const linecap = path.strokeLinecap ? ` stroke-linecap=\"${path.strokeLinecap}\"` : \"\";\n const linejoin = path.strokeLinejoin ? ` stroke-linejoin=\"${path.strokeLinejoin}\"` : \"\";\n await write(\n `<path d=\"${path.d}\" fill=\"${fill}\" stroke=\"${stroke}\"${strokeWidth}${fillOpacity}${strokeOpacity}${dasharray}${dashoffset}${linecap}${linejoin}${fillRule}/>`,\n );\n }\n await write(\"</g>\");\n }\n if (!reflectedOverlay) {\n for (const image of page.images ?? []) await write(visualImage(image, page.height));\n }\n for (const span of visualSpans) {\n if (!usesPositionedSpan(span)) {\n const type3 = span.fontAssetId ? type3Fonts.get(span.fontAssetId) : undefined;\n await write(\n type3\n ? visualType3Text(span, type3, page.height)\n : visualText(span, page.height, fontAliases, reflectedOverlay && page.rotate === 180),\n );\n }\n }\n await write(\"</svg>\");\n for (const span of visualSpans) {\n if (usesPositionedSpan(span)) await write(positionedSpan(span, fontAliases));\n }\n await write(\"</div></section>\");\n}\n\nfunction usesReflectedVisualOverlay(page: ExtractedPage, spans: TextSpan[]): boolean {\n return (\n Boolean(page.images?.length) &&\n Boolean(page.paths?.length || page.fills?.length) &&\n spans.length > 0 &&\n spans.every(\n (span) =>\n span.transform !== undefined &&\n Math.abs(span.transform[0] + 1) < 0.000_001 &&\n Math.abs(span.transform[1]) < 0.000_001 &&\n Math.abs(span.transform[2]) < 0.000_001 &&\n Math.abs(span.transform[3] - 1) < 0.000_001,\n )\n );\n}\n\nfunction visualImage(image: RasterImage, pageHeight: number): string {\n const [a, b, c, d, e, f] = image.transform;\n const transform = [a, -b, -c, d, c + e, pageHeight - d - f].map(number).join(\" \");\n const opacity = isUnitInterval(image.opacity) ? ` opacity=\"${number(image.opacity)}\"` : \"\";\n const mime = image.format === \"jpeg\" ? \"image/jpeg\" : \"image/bmp\";\n const data = image.format === \"jpeg\" ? image.data : rgbBmp(image);\n return `<image width=\"1\" height=\"1\" preserveAspectRatio=\"none\" transform=\"matrix(${transform})\" href=\"data:${mime};base64,${base64(data)}\"${opacity}/>`;\n}\n\nfunction rgbBmp(image: RasterImage): Uint8Array {\n const stride = Math.ceil((image.width * 3) / 4) * 4;\n const output = new Uint8Array(54 + stride * image.height);\n const view = new DataView(output.buffer);\n output[0] = 0x42;\n output[1] = 0x4d;\n view.setUint32(2, output.length, true);\n view.setUint32(10, 54, true);\n view.setUint32(14, 40, true);\n view.setInt32(18, image.width, true);\n view.setInt32(22, -image.height, true);\n view.setUint16(26, 1, true);\n view.setUint16(28, 24, true);\n view.setUint32(34, stride * image.height, true);\n for (let row = 0; row < image.height; row += 1) {\n for (let column = 0; column < image.width; column += 1) {\n const source = (row * image.width + column) * 3;\n const target = 54 + row * stride + column * 3;\n output[target] = image.data[source + 2] ?? 0;\n output[target + 1] = image.data[source + 1] ?? 0;\n output[target + 2] = image.data[source] ?? 0;\n }\n }\n return output;\n}\n\nfunction rotationTransform(page: ExtractedPage): string {\n switch (page.rotate) {\n case 90:\n return `;transform:translate(${number(page.height)}pt,0) rotate(90deg)`;\n case 180:\n return `;transform:translate(${number(page.width)}pt,${number(page.height)}pt) rotate(180deg)`;\n case 270:\n return `;transform:translate(0,${number(page.width)}pt) rotate(270deg)`;\n default:\n return \"\";\n }\n}\n\nfunction positionedSpan(span: TextSpan, fontAliases: Map<string, string>): string {\n const direction = directionAttribute([span]);\n const style = [\n `left:${number(span.bounds.x)}pt`,\n `bottom:${number(span.bounds.y)}pt`,\n `width:${number(span.bounds.width)}pt`,\n `height:${number(span.bounds.height)}pt`,\n `font-size:${number(span.fontSize)}pt`,\n ...(isCssHexColor(span.color) ? [`color:${span.color}`] : []),\n ...(isUnitInterval(span.fillOpacity) ? [`opacity:${number(span.fillOpacity)}`] : []),\n ...fontStyles(\n span.fontFamily,\n span.fontAssetId ? fontAliases.get(span.fontAssetId) : undefined,\n ),\n ].join(\";\");\n return `<span class=\"pdf-span\"${direction} style=\"${style}\">${escapeHtml(span.text)}</span>`;\n}\n\nasync function writeFlowPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const structured = structurePage(page);\n const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);\n const emittedTables = new Set<Table>();\n await write(\n `<section class=\"pdf-page pdf-page--semantic pdf-page--flow\" data-page=\"${page.number}\">`,\n );\n for (const line of structured.lines) {\n const table = tables.find((candidate) => containsY(candidate, line.bounds.y));\n if (table) {\n if (!emittedTables.has(table)) {\n await write(tableToHtml(table));\n emittedTables.add(table);\n }\n continue;\n }\n await write(`<p${directionAttribute(line.spans)}>${escapeHtml(line.text)}</p>`);\n }\n for (const table of tables) {\n if (!emittedTables.has(table)) await write(tableToHtml(table));\n }\n await write(\"</section>\");\n}\n\nfunction visualText(\n span: TextSpan,\n pageHeight: number,\n fontAliases: Map<string, string>,\n counterRotateReflectedText = false,\n): string {\n if (span.renderingMode === 3 || span.renderingMode === 7) return \"\";\n if (!span.fontAssetId && isAdobeCjkFont(span.fontFamily)) return \"\";\n const direction = directionAttribute([span]);\n const font = fontStyles(\n span.fontFamily,\n span.fontAssetId ? fontAliases.get(span.fontAssetId) : undefined,\n ).join(\";\");\n const stroke = isCssHexColor(span.strokeColor) ? `stroke:${span.strokeColor}` : \"\";\n const strokeWidth =\n stroke && Number.isFinite(span.strokeWidth) && (span.strokeWidth ?? -1) >= 0\n ? `stroke-width:${number(span.strokeWidth ?? 0)}`\n : \"\";\n const strokeOnly = span.renderingMode === 1 || span.renderingMode === 5;\n const fillOpacity = isUnitInterval(span.fillOpacity)\n ? `fill-opacity:${number(span.fillOpacity)}`\n : \"\";\n const strokeOpacity = isUnitInterval(span.strokeOpacity)\n ? `stroke-opacity:${number(span.strokeOpacity)}`\n : \"\";\n const style = [\n isHebrewPaintOrder(span) ? \"unicode-bidi:bidi-override;direction:ltr\" : \"\",\n span.direction === \"ttb\" ? \"writing-mode:vertical-rl\" : \"\",\n strokeOnly ? \"fill:none\" : isCssHexColor(span.color) ? `fill:${span.color}` : \"\",\n stroke,\n strokeWidth,\n fillOpacity,\n strokeOpacity,\n font,\n ]\n .filter(Boolean)\n .join(\";\");\n const textExtent = span.direction === \"ttb\" ? span.bounds.height : span.bounds.width;\n const textLength =\n textExtent > 0 && !isHebrewPaintOrder(span)\n ? ` textLength=\"${number(textExtent)}\" lengthAdjust=\"${span.direction === \"ttb\" || usesSpacingAdjustment(span) ? \"spacing\" : \"spacingAndGlyphs\"}\"`\n : \"\";\n const transform =\n counterRotateReflectedText && span.transform\n ? ([\n span.transform[0],\n span.transform[1],\n span.transform[2],\n -span.transform[3],\n ] as TextSpan[\"transform\"])\n : span.transform;\n const transformed = hasNonIdentityTransform(transform);\n const rtlOffset = span.direction === \"rtl\" ? span.bounds.width : 0;\n const basisX = transform?.[0] ?? 1;\n const basisY = transform?.[1] ?? 0;\n const anchorX = span.bounds.x + basisX * rtlOffset;\n const anchorY = pageHeight - span.bounds.y + basisY * rtlOffset;\n const position = transformed\n ? ` x=\"0\" y=\"0\" transform=\"matrix(${transform?.map(number).join(\" \")} ${number(anchorX)} ${number(anchorY)})\"`\n : ` x=\"${number(anchorX)}\" y=\"${number(anchorY)}\"`;\n return `<text${direction}${position} font-size=\"${number(span.fontSize)}\"${textLength}${style ? ` style=\"${style}\"` : \"\"}>${escapeHtml(span.text)}</text>`;\n}\n\nfunction isAdobeCjkFont(fontFamily: string | undefined): boolean {\n return /^Adobe(?:Heiti|Song|Kaiti|Ming|Gothic|Mincho)Std-/i.test(fontFamily ?? \"\");\n}\n\nfunction visualType3Text(span: TextSpan, font: EmbeddedType3Font, pageHeight: number): string {\n if (span.renderingMode === 3 || span.renderingMode === 7) return \"\";\n const glyphs = new Map(font.glyphs.map((glyph) => [glyph.code, glyph]));\n const sequence = (span.glyphCodes ?? []).map((code) => glyphs.get(code));\n const totalAdvance = sequence.reduce((total, glyph) => total + (glyph?.advance ?? 0), 0);\n if (totalAdvance <= 0 || span.bounds.width <= 0 || span.fontSize <= 0) return \"\";\n const transform = span.transform ?? [1, 0, 0, 1];\n const outer = `matrix(${transform.map(number).join(\" \")} ${number(span.bounds.x)} ${number(pageHeight - span.bounds.y)})`;\n const xScale = span.bounds.width / totalAdvance;\n let offset = 0;\n let content = \"\";\n for (const glyph of sequence) {\n if (!glyph) continue;\n content += `<g transform=\"translate(${number(offset)} 0)\">${type3Glyph(glyph)}</g>`;\n offset += glyph.advance;\n }\n return `<g transform=\"${outer}\"><g transform=\"scale(${number(xScale)} ${number(-span.fontSize)})\">${content}</g></g>`;\n}\n\nfunction isHebrewPaintOrder(span: TextSpan): boolean {\n return span.direction === \"ltr\" && /[\\u0590-\\u05ff]/u.test(span.text);\n}\n\nfunction usesSpacingAdjustment(span: TextSpan): boolean {\n return !span.fontAssetId && /arial/i.test(span.fontFamily ?? \"\");\n}\n\nfunction type3Glyph(glyph: Type3Glyph): string {\n let output = \"\";\n for (const fill of glyph.fills ?? []) {\n if (!isCssHexColor(fill.color)) continue;\n const points = fill.points.map(([x, y]) => `${number(x)},${number(y)}`).join(\" \");\n const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity=\"${number(fill.opacity)}\"` : \"\";\n output += `<polygon points=\"${points}\" fill=\"${fill.color}\"${opacity}/>`;\n }\n for (const path of glyph.paths ?? []) {\n if (!isSvgPath(path.d)) continue;\n const fill = isCssHexColor(path.fill) ? path.fill : \"none\";\n const stroke = isCssHexColor(path.stroke) ? path.stroke : \"none\";\n const width =\n path.strokeWidth !== undefined && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0\n ? ` stroke-width=\"${number(path.strokeWidth)}\"`\n : \"\";\n output += `<path d=\"${path.d}\" fill=\"${fill}\" stroke=\"${stroke}\"${width}/>`;\n }\n return (glyph.fills?.length ?? 0) > 64 && glyph.advance > 2\n ? `<g shape-rendering=\"crispEdges\">${output}</g>`\n : output;\n}\n\nfunction isCssHexColor(value: string | undefined): value is string {\n return /^#[\\da-f]{6}$/i.test(value ?? \"\");\n}\n\nfunction isUnitInterval(value: number | undefined): value is number {\n return Number.isFinite(value) && (value ?? -1) >= 0 && (value ?? 2) <= 1;\n}\n\nfunction isSvgPath(value: string): boolean {\n return value.length <= 1_000_000 && /^[\\d\\s.,+\\-eEMmLlCcZz]+$/.test(value);\n}\n\nfunction fontStyles(fontFamily: string | undefined, alias?: string): string[] {\n const normalized = fontFamily?.toLowerCase() ?? \"\";\n const styles: string[] = [];\n let fallback: string | undefined;\n if (/courier|mono|nimbusmono|^cmtt/.test(normalized)) {\n fallback = \"Courier New,Courier,monospace\";\n } else if (\n /times|minion|serif|baskerville|georgia|nimbusrom|guardian.*egyp|^cm[rs]y?\\d/.test(normalized)\n ) {\n fallback = \"Times New Roman,Times,serif\";\n } else if (/helvetica|arial|sans|nimbussan|calibre|myriad|panton|^tte/.test(normalized)) {\n fallback = \"Arial,Helvetica,sans-serif\";\n } else if (/^mstt/.test(normalized)) {\n fallback = \"Arial,Helvetica,sans-serif\";\n }\n if (alias || fallback) styles.push(`font-family:${[alias, fallback].filter(Boolean).join(\",\")}`);\n if (/bold|black|semibold|demi|medi|^tte/.test(normalized)) styles.push(\"font-weight:700\");\n if (/italic|oblique|slant|ital(?:$|[_-])/.test(normalized)) styles.push(\"font-style:italic\");\n return styles;\n}\n\nfunction isMonospace(fontFamily: string | undefined): boolean {\n return /courier|mono/i.test(fontFamily ?? \"\");\n}\n\nfunction usesPositionedSpan(span: TextSpan): boolean {\n return (\n !span.glyphCodes && isMonospace(span.fontFamily) && !hasNonIdentityTransform(span.transform)\n );\n}\n\nfunction hasNonIdentityTransform(transform: TextSpan[\"transform\"]): boolean {\n if (!transform) return false;\n const identity: [number, number, number, number] = [1, 0, 0, 1];\n return transform.some((value, index) => Math.abs(value - (identity[index] ?? 0)) > 0.000_001);\n}\n\nfunction fontFace(font: EmbeddedFont, aliases: Map<string, string>): string {\n if (font.format !== \"truetype\") return \"\";\n const alias = aliases.get(font.id);\n if (!alias) return \"\";\n const styles = fontStyles(font.family, alias).filter(\n (style) => !style.startsWith(\"font-family:\"),\n );\n return `@font-face{font-family:${alias};src:url(data:font/ttf;base64,${base64(font.data)}) format(\"truetype\");${styles.join(\";\")}}`;\n}\n\nfunction base64(bytes: Uint8Array): string {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n let output = \"\";\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0;\n const second = bytes[index + 1] ?? 0;\n const third = bytes[index + 2] ?? 0;\n output += alphabet[first >> 2];\n output += alphabet[((first & 3) << 4) | (second >> 4)];\n output += index + 1 < bytes.length ? alphabet[((second & 15) << 2) | (third >> 6)] : \"=\";\n output += index + 2 < bytes.length ? alphabet[third & 63] : \"=\";\n }\n return output;\n}\n\nfunction directionAttribute(spans: TextSpan[]): string {\n const rtl = spans.filter((span) => span.direction === \"rtl\").length;\n const vertical = spans.filter((span) => span.direction === \"ttb\").length;\n if (vertical > rtl && vertical * 2 >= spans.length) return ' data-direction=\"ttb\"';\n return rtl * 2 >= spans.length && spans.length > 0 ? ' dir=\"rtl\"' : \"\";\n}\n\nfunction containsY(table: Table, y: number): boolean {\n return y >= table.bounds.y && y <= table.bounds.y + table.bounds.height;\n}\n\nfunction number(value: number): string {\n return Number.isFinite(value) ? String(Math.round(value * 1000) / 1000) : \"0\";\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll(\"`\", \"`\");\n}\n\nfunction escapeHtml(value: string): string {\n return [...value]\n .map((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (codePoint === 13) return \"\\n\";\n return isForbiddenControl(codePoint) ? \"�\" : character;\n })\n .join(\"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nfunction isForbiddenControl(codePoint: number): boolean {\n return (\n codePoint <= 8 ||\n codePoint === 11 ||\n codePoint === 12 ||\n (codePoint >= 14 && codePoint <= 31) ||\n codePoint === 127\n );\n}\n\nfunction resolveProfile(options: HtmlWriterOptions): HtmlProfile {\n const legacyProfile = options.layout === \"flow\" ? \"semantic\" : \"visual\";\n if (options.profile && options.layout && options.profile !== legacyProfile) {\n throw new Error(\n `conflicting HTML output options: profile \"${options.profile}\" does not match layout \"${options.layout}\"`,\n );\n }\n return options.profile ?? legacyProfile;\n}\n"],"mappings":"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","names":["styles"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { ExtractedPage } from '@boxpdf/reader';
|
|
2
2
|
|
|
3
3
|
type HtmlLayout = "positioned" | "flow";
|
|
4
|
+
type HtmlProfile = "visual" | "semantic";
|
|
4
5
|
type HtmlWrite = (chunk: string) => void | Promise<void>;
|
|
5
6
|
interface HtmlWriterOptions {
|
|
7
|
+
/** Output intent. Visual preserves page presentation; semantic prioritizes reading order. */
|
|
8
|
+
profile?: HtmlProfile;
|
|
9
|
+
/** @deprecated Use `profile: "visual"` or `profile: "semantic"`. */
|
|
6
10
|
layout?: HtmlLayout;
|
|
7
11
|
title?: string;
|
|
8
12
|
language?: string;
|
|
@@ -13,4 +17,4 @@ declare function writeHtmlDocument(pages: AsyncIterable<ExtractedPage> | Iterabl
|
|
|
13
17
|
declare function writePage(page: ExtractedPage, write: HtmlWrite, options?: HtmlWriterOptions): Promise<void>;
|
|
14
18
|
declare function pageToHtml(page: ExtractedPage, options?: HtmlWriterOptions): Promise<string>;
|
|
15
19
|
|
|
16
|
-
export { type HtmlLayout, type HtmlWrite, type HtmlWriterOptions, pageToHtml, writeHtmlDocument, writePage };
|
|
20
|
+
export { type HtmlLayout, type HtmlProfile, type HtmlWrite, type HtmlWriterOptions, pageToHtml, writeHtmlDocument, writePage };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { ExtractedPage } from '@boxpdf/reader';
|
|
2
2
|
|
|
3
3
|
type HtmlLayout = "positioned" | "flow";
|
|
4
|
+
type HtmlProfile = "visual" | "semantic";
|
|
4
5
|
type HtmlWrite = (chunk: string) => void | Promise<void>;
|
|
5
6
|
interface HtmlWriterOptions {
|
|
7
|
+
/** Output intent. Visual preserves page presentation; semantic prioritizes reading order. */
|
|
8
|
+
profile?: HtmlProfile;
|
|
9
|
+
/** @deprecated Use `profile: "visual"` or `profile: "semantic"`. */
|
|
6
10
|
layout?: HtmlLayout;
|
|
7
11
|
title?: string;
|
|
8
12
|
language?: string;
|
|
@@ -13,4 +17,4 @@ declare function writeHtmlDocument(pages: AsyncIterable<ExtractedPage> | Iterabl
|
|
|
13
17
|
declare function writePage(page: ExtractedPage, write: HtmlWrite, options?: HtmlWriterOptions): Promise<void>;
|
|
14
18
|
declare function pageToHtml(page: ExtractedPage, options?: HtmlWriterOptions): Promise<string>;
|
|
15
19
|
|
|
16
|
-
export { type HtmlLayout, type HtmlWrite, type HtmlWriterOptions, pageToHtml, writeHtmlDocument, writePage };
|
|
20
|
+
export { type HtmlLayout, type HtmlProfile, type HtmlWrite, type HtmlWriterOptions, pageToHtml, writeHtmlDocument, writePage };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { structurePage, tableToHtml } from "@boxpdf/reader/structure";
|
|
3
|
-
var styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-
|
|
3
|
+
var styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--visual,.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--semantic,.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--semantic p,.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;
|
|
4
4
|
async function writeHtmlDocument(pages, write, options = {}) {
|
|
5
5
|
const includeDocument = options.includeDocument ?? true;
|
|
6
6
|
if (includeDocument) {
|
|
@@ -19,8 +19,8 @@ async function writeHtmlDocument(pages, write, options = {}) {
|
|
|
19
19
|
if (includeDocument) await write("</body></html>");
|
|
20
20
|
}
|
|
21
21
|
async function writePage(page, write, options = {}) {
|
|
22
|
-
if ((options
|
|
23
|
-
else await writePositionedPage(page, write);
|
|
22
|
+
if (resolveProfile(options) === "semantic") await writeFlowPage(page, write);
|
|
23
|
+
else await writePositionedPage(page, write, options);
|
|
24
24
|
}
|
|
25
25
|
async function pageToHtml(page, options = {}) {
|
|
26
26
|
let output = "";
|
|
@@ -33,24 +33,151 @@ async function pageToHtml(page, options = {}) {
|
|
|
33
33
|
);
|
|
34
34
|
return output;
|
|
35
35
|
}
|
|
36
|
-
async function writePositionedPage(page, write) {
|
|
36
|
+
async function writePositionedPage(page, write, options) {
|
|
37
|
+
const visualSpans = page.visualSpans ?? page.spans;
|
|
38
|
+
const reflectedOverlay = usesReflectedVisualOverlay(page, visualSpans);
|
|
37
39
|
const quarterTurn = page.rotate === 90 || page.rotate === 270;
|
|
38
40
|
const displayWidth = quarterTurn ? page.height : page.width;
|
|
39
41
|
const displayHeight = quarterTurn ? page.width : page.height;
|
|
40
42
|
await write(
|
|
41
|
-
`<section class="pdf-page pdf-page--positioned" data-page="${page.number}" data-rotate="${page.rotate}" style="width:${number(displayWidth)}pt;height:${number(displayHeight)}pt">`
|
|
43
|
+
`<section class="pdf-page pdf-page--visual pdf-page--positioned" data-page="${page.number}" data-rotate="${page.rotate}" style="width:${number(displayWidth)}pt;height:${number(displayHeight)}pt">`
|
|
44
|
+
);
|
|
45
|
+
const fontAliases = new Map(
|
|
46
|
+
(page.fonts ?? []).filter((font) => font.format === "truetype" && !/(?:courier|^TTE)/i.test(font.family ?? "")).map((font) => [font.id, `boxpdf-${page.number}-${font.id}`])
|
|
47
|
+
);
|
|
48
|
+
const type3Fonts = new Map(
|
|
49
|
+
(page.fonts ?? []).filter((font) => font.format === "type3").map((font) => [font.id, font])
|
|
50
|
+
);
|
|
51
|
+
if ((options.includeStyles ?? true) && page.fonts?.length) {
|
|
52
|
+
await write(`<style>${page.fonts.map((font) => fontFace(font, fontAliases)).join("")}</style>`);
|
|
53
|
+
}
|
|
54
|
+
await write(
|
|
55
|
+
`<div class="pdf-page-content pdf-page-content--${page.rotate}" style="width:${number(page.width)}pt;height:${number(page.height)}pt${rotationTransform(page)}">`
|
|
42
56
|
);
|
|
43
57
|
await write(
|
|
44
|
-
`<
|
|
58
|
+
`<svg class="pdf-visual-text" xmlns="http://www.w3.org/2000/svg" width="${number(page.width)}pt" height="${number(page.height)}pt" viewBox="0 0 ${number(page.width)} ${number(page.height)}">`
|
|
45
59
|
);
|
|
46
|
-
|
|
60
|
+
if (reflectedOverlay) {
|
|
61
|
+
for (const image of page.images ?? []) await write(visualImage(image, page.height));
|
|
62
|
+
}
|
|
63
|
+
for (const fill of page.fills ?? []) {
|
|
64
|
+
const points = fill.points.map(([x, y]) => `${number(x)},${number(page.height - y)}`).join(" ");
|
|
65
|
+
if (isCssHexColor(fill.color)) {
|
|
66
|
+
const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity="${number(fill.opacity)}"` : "";
|
|
67
|
+
await write(`<polygon points="${points}" fill="${fill.color}"${opacity}/>`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (page.paths?.length) {
|
|
71
|
+
await write(`<g transform="translate(0 ${number(page.height)}) scale(1 -1)">`);
|
|
72
|
+
for (const path of page.paths) {
|
|
73
|
+
if (!isSvgPath(path.d)) continue;
|
|
74
|
+
const fill = isCssHexColor(path.fill) ? path.fill : "none";
|
|
75
|
+
const stroke = isCssHexColor(path.stroke) ? path.stroke : "none";
|
|
76
|
+
const strokeWidth = path.strokeWidth !== void 0 && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0 ? ` stroke-width="${number(path.strokeWidth)}"` : "";
|
|
77
|
+
const fillRule = path.fillRule ? ` fill-rule="${path.fillRule}"` : "";
|
|
78
|
+
const fillOpacity = isUnitInterval(path.fillOpacity) ? ` fill-opacity="${number(path.fillOpacity)}"` : "";
|
|
79
|
+
const strokeOpacity = isUnitInterval(path.strokeOpacity) ? ` stroke-opacity="${number(path.strokeOpacity)}"` : "";
|
|
80
|
+
const dasharray = path.strokeDasharray?.every((value) => Number.isFinite(value) && value >= 0) ? ` stroke-dasharray="${path.strokeDasharray.map(number).join(" ")}"` : "";
|
|
81
|
+
const dashoffset = Number.isFinite(path.strokeDashoffset) ? ` stroke-dashoffset="${number(path.strokeDashoffset ?? 0)}"` : "";
|
|
82
|
+
const linecap = path.strokeLinecap ? ` stroke-linecap="${path.strokeLinecap}"` : "";
|
|
83
|
+
const linejoin = path.strokeLinejoin ? ` stroke-linejoin="${path.strokeLinejoin}"` : "";
|
|
84
|
+
await write(
|
|
85
|
+
`<path d="${path.d}" fill="${fill}" stroke="${stroke}"${strokeWidth}${fillOpacity}${strokeOpacity}${dasharray}${dashoffset}${linecap}${linejoin}${fillRule}/>`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
await write("</g>");
|
|
89
|
+
}
|
|
90
|
+
if (!reflectedOverlay) {
|
|
91
|
+
for (const image of page.images ?? []) await write(visualImage(image, page.height));
|
|
92
|
+
}
|
|
93
|
+
for (const span of visualSpans) {
|
|
94
|
+
if (!usesPositionedSpan(span)) {
|
|
95
|
+
const type3 = span.fontAssetId ? type3Fonts.get(span.fontAssetId) : void 0;
|
|
96
|
+
await write(
|
|
97
|
+
type3 ? visualType3Text(span, type3, page.height) : visualText(span, page.height, fontAliases, reflectedOverlay && page.rotate === 180)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
await write("</svg>");
|
|
102
|
+
for (const span of visualSpans) {
|
|
103
|
+
if (usesPositionedSpan(span)) await write(positionedSpan(span, fontAliases));
|
|
104
|
+
}
|
|
47
105
|
await write("</div></section>");
|
|
48
106
|
}
|
|
107
|
+
function usesReflectedVisualOverlay(page, spans) {
|
|
108
|
+
return Boolean(page.images?.length) && Boolean(page.paths?.length || page.fills?.length) && spans.length > 0 && spans.every(
|
|
109
|
+
(span) => span.transform !== void 0 && Math.abs(span.transform[0] + 1) < 1e-6 && Math.abs(span.transform[1]) < 1e-6 && Math.abs(span.transform[2]) < 1e-6 && Math.abs(span.transform[3] - 1) < 1e-6
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function visualImage(image, pageHeight) {
|
|
113
|
+
const [a, b, c, d, e, f] = image.transform;
|
|
114
|
+
const transform = [a, -b, -c, d, c + e, pageHeight - d - f].map(number).join(" ");
|
|
115
|
+
const opacity = isUnitInterval(image.opacity) ? ` opacity="${number(image.opacity)}"` : "";
|
|
116
|
+
const mime = image.format === "jpeg" ? "image/jpeg" : "image/bmp";
|
|
117
|
+
const data = image.format === "jpeg" ? image.data : rgbBmp(image);
|
|
118
|
+
return `<image width="1" height="1" preserveAspectRatio="none" transform="matrix(${transform})" href="data:${mime};base64,${base64(data)}"${opacity}/>`;
|
|
119
|
+
}
|
|
120
|
+
function rgbBmp(image) {
|
|
121
|
+
const stride = Math.ceil(image.width * 3 / 4) * 4;
|
|
122
|
+
const output = new Uint8Array(54 + stride * image.height);
|
|
123
|
+
const view = new DataView(output.buffer);
|
|
124
|
+
output[0] = 66;
|
|
125
|
+
output[1] = 77;
|
|
126
|
+
view.setUint32(2, output.length, true);
|
|
127
|
+
view.setUint32(10, 54, true);
|
|
128
|
+
view.setUint32(14, 40, true);
|
|
129
|
+
view.setInt32(18, image.width, true);
|
|
130
|
+
view.setInt32(22, -image.height, true);
|
|
131
|
+
view.setUint16(26, 1, true);
|
|
132
|
+
view.setUint16(28, 24, true);
|
|
133
|
+
view.setUint32(34, stride * image.height, true);
|
|
134
|
+
for (let row = 0; row < image.height; row += 1) {
|
|
135
|
+
for (let column = 0; column < image.width; column += 1) {
|
|
136
|
+
const source = (row * image.width + column) * 3;
|
|
137
|
+
const target = 54 + row * stride + column * 3;
|
|
138
|
+
output[target] = image.data[source + 2] ?? 0;
|
|
139
|
+
output[target + 1] = image.data[source + 1] ?? 0;
|
|
140
|
+
output[target + 2] = image.data[source] ?? 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return output;
|
|
144
|
+
}
|
|
145
|
+
function rotationTransform(page) {
|
|
146
|
+
switch (page.rotate) {
|
|
147
|
+
case 90:
|
|
148
|
+
return `;transform:translate(${number(page.height)}pt,0) rotate(90deg)`;
|
|
149
|
+
case 180:
|
|
150
|
+
return `;transform:translate(${number(page.width)}pt,${number(page.height)}pt) rotate(180deg)`;
|
|
151
|
+
case 270:
|
|
152
|
+
return `;transform:translate(0,${number(page.width)}pt) rotate(270deg)`;
|
|
153
|
+
default:
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function positionedSpan(span, fontAliases) {
|
|
158
|
+
const direction = directionAttribute([span]);
|
|
159
|
+
const style = [
|
|
160
|
+
`left:${number(span.bounds.x)}pt`,
|
|
161
|
+
`bottom:${number(span.bounds.y)}pt`,
|
|
162
|
+
`width:${number(span.bounds.width)}pt`,
|
|
163
|
+
`height:${number(span.bounds.height)}pt`,
|
|
164
|
+
`font-size:${number(span.fontSize)}pt`,
|
|
165
|
+
...isCssHexColor(span.color) ? [`color:${span.color}`] : [],
|
|
166
|
+
...isUnitInterval(span.fillOpacity) ? [`opacity:${number(span.fillOpacity)}`] : [],
|
|
167
|
+
...fontStyles(
|
|
168
|
+
span.fontFamily,
|
|
169
|
+
span.fontAssetId ? fontAliases.get(span.fontAssetId) : void 0
|
|
170
|
+
)
|
|
171
|
+
].join(";");
|
|
172
|
+
return `<span class="pdf-span"${direction} style="${style}">${escapeHtml(span.text)}</span>`;
|
|
173
|
+
}
|
|
49
174
|
async function writeFlowPage(page, write) {
|
|
50
175
|
const structured = structurePage(page);
|
|
51
176
|
const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);
|
|
52
177
|
const emittedTables = /* @__PURE__ */ new Set();
|
|
53
|
-
await write(
|
|
178
|
+
await write(
|
|
179
|
+
`<section class="pdf-page pdf-page--semantic pdf-page--flow" data-page="${page.number}">`
|
|
180
|
+
);
|
|
54
181
|
for (const line of structured.lines) {
|
|
55
182
|
const table = tables.find((candidate) => containsY(candidate, line.bounds.y));
|
|
56
183
|
if (table) {
|
|
@@ -67,16 +194,150 @@ async function writeFlowPage(page, write) {
|
|
|
67
194
|
}
|
|
68
195
|
await write("</section>");
|
|
69
196
|
}
|
|
70
|
-
function
|
|
197
|
+
function visualText(span, pageHeight, fontAliases, counterRotateReflectedText = false) {
|
|
198
|
+
if (span.renderingMode === 3 || span.renderingMode === 7) return "";
|
|
199
|
+
if (!span.fontAssetId && isAdobeCjkFont(span.fontFamily)) return "";
|
|
71
200
|
const direction = directionAttribute([span]);
|
|
201
|
+
const font = fontStyles(
|
|
202
|
+
span.fontFamily,
|
|
203
|
+
span.fontAssetId ? fontAliases.get(span.fontAssetId) : void 0
|
|
204
|
+
).join(";");
|
|
205
|
+
const stroke = isCssHexColor(span.strokeColor) ? `stroke:${span.strokeColor}` : "";
|
|
206
|
+
const strokeWidth = stroke && Number.isFinite(span.strokeWidth) && (span.strokeWidth ?? -1) >= 0 ? `stroke-width:${number(span.strokeWidth ?? 0)}` : "";
|
|
207
|
+
const strokeOnly = span.renderingMode === 1 || span.renderingMode === 5;
|
|
208
|
+
const fillOpacity = isUnitInterval(span.fillOpacity) ? `fill-opacity:${number(span.fillOpacity)}` : "";
|
|
209
|
+
const strokeOpacity = isUnitInterval(span.strokeOpacity) ? `stroke-opacity:${number(span.strokeOpacity)}` : "";
|
|
72
210
|
const style = [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
211
|
+
isHebrewPaintOrder(span) ? "unicode-bidi:bidi-override;direction:ltr" : "",
|
|
212
|
+
span.direction === "ttb" ? "writing-mode:vertical-rl" : "",
|
|
213
|
+
strokeOnly ? "fill:none" : isCssHexColor(span.color) ? `fill:${span.color}` : "",
|
|
214
|
+
stroke,
|
|
215
|
+
strokeWidth,
|
|
216
|
+
fillOpacity,
|
|
217
|
+
strokeOpacity,
|
|
218
|
+
font
|
|
219
|
+
].filter(Boolean).join(";");
|
|
220
|
+
const textExtent = span.direction === "ttb" ? span.bounds.height : span.bounds.width;
|
|
221
|
+
const textLength = textExtent > 0 && !isHebrewPaintOrder(span) ? ` textLength="${number(textExtent)}" lengthAdjust="${span.direction === "ttb" || usesSpacingAdjustment(span) ? "spacing" : "spacingAndGlyphs"}"` : "";
|
|
222
|
+
const transform = counterRotateReflectedText && span.transform ? [
|
|
223
|
+
span.transform[0],
|
|
224
|
+
span.transform[1],
|
|
225
|
+
span.transform[2],
|
|
226
|
+
-span.transform[3]
|
|
227
|
+
] : span.transform;
|
|
228
|
+
const transformed = hasNonIdentityTransform(transform);
|
|
229
|
+
const rtlOffset = span.direction === "rtl" ? span.bounds.width : 0;
|
|
230
|
+
const basisX = transform?.[0] ?? 1;
|
|
231
|
+
const basisY = transform?.[1] ?? 0;
|
|
232
|
+
const anchorX = span.bounds.x + basisX * rtlOffset;
|
|
233
|
+
const anchorY = pageHeight - span.bounds.y + basisY * rtlOffset;
|
|
234
|
+
const position = transformed ? ` x="0" y="0" transform="matrix(${transform?.map(number).join(" ")} ${number(anchorX)} ${number(anchorY)})"` : ` x="${number(anchorX)}" y="${number(anchorY)}"`;
|
|
235
|
+
return `<text${direction}${position} font-size="${number(span.fontSize)}"${textLength}${style ? ` style="${style}"` : ""}>${escapeHtml(span.text)}</text>`;
|
|
236
|
+
}
|
|
237
|
+
function isAdobeCjkFont(fontFamily) {
|
|
238
|
+
return /^Adobe(?:Heiti|Song|Kaiti|Ming|Gothic|Mincho)Std-/i.test(fontFamily ?? "");
|
|
239
|
+
}
|
|
240
|
+
function visualType3Text(span, font, pageHeight) {
|
|
241
|
+
if (span.renderingMode === 3 || span.renderingMode === 7) return "";
|
|
242
|
+
const glyphs = new Map(font.glyphs.map((glyph) => [glyph.code, glyph]));
|
|
243
|
+
const sequence = (span.glyphCodes ?? []).map((code) => glyphs.get(code));
|
|
244
|
+
const totalAdvance = sequence.reduce((total, glyph) => total + (glyph?.advance ?? 0), 0);
|
|
245
|
+
if (totalAdvance <= 0 || span.bounds.width <= 0 || span.fontSize <= 0) return "";
|
|
246
|
+
const transform = span.transform ?? [1, 0, 0, 1];
|
|
247
|
+
const outer = `matrix(${transform.map(number).join(" ")} ${number(span.bounds.x)} ${number(pageHeight - span.bounds.y)})`;
|
|
248
|
+
const xScale = span.bounds.width / totalAdvance;
|
|
249
|
+
let offset = 0;
|
|
250
|
+
let content = "";
|
|
251
|
+
for (const glyph of sequence) {
|
|
252
|
+
if (!glyph) continue;
|
|
253
|
+
content += `<g transform="translate(${number(offset)} 0)">${type3Glyph(glyph)}</g>`;
|
|
254
|
+
offset += glyph.advance;
|
|
255
|
+
}
|
|
256
|
+
return `<g transform="${outer}"><g transform="scale(${number(xScale)} ${number(-span.fontSize)})">${content}</g></g>`;
|
|
257
|
+
}
|
|
258
|
+
function isHebrewPaintOrder(span) {
|
|
259
|
+
return span.direction === "ltr" && /[\u0590-\u05ff]/u.test(span.text);
|
|
260
|
+
}
|
|
261
|
+
function usesSpacingAdjustment(span) {
|
|
262
|
+
return !span.fontAssetId && /arial/i.test(span.fontFamily ?? "");
|
|
263
|
+
}
|
|
264
|
+
function type3Glyph(glyph) {
|
|
265
|
+
let output = "";
|
|
266
|
+
for (const fill of glyph.fills ?? []) {
|
|
267
|
+
if (!isCssHexColor(fill.color)) continue;
|
|
268
|
+
const points = fill.points.map(([x, y]) => `${number(x)},${number(y)}`).join(" ");
|
|
269
|
+
const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity="${number(fill.opacity)}"` : "";
|
|
270
|
+
output += `<polygon points="${points}" fill="${fill.color}"${opacity}/>`;
|
|
271
|
+
}
|
|
272
|
+
for (const path of glyph.paths ?? []) {
|
|
273
|
+
if (!isSvgPath(path.d)) continue;
|
|
274
|
+
const fill = isCssHexColor(path.fill) ? path.fill : "none";
|
|
275
|
+
const stroke = isCssHexColor(path.stroke) ? path.stroke : "none";
|
|
276
|
+
const width = path.strokeWidth !== void 0 && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0 ? ` stroke-width="${number(path.strokeWidth)}"` : "";
|
|
277
|
+
output += `<path d="${path.d}" fill="${fill}" stroke="${stroke}"${width}/>`;
|
|
278
|
+
}
|
|
279
|
+
return (glyph.fills?.length ?? 0) > 64 && glyph.advance > 2 ? `<g shape-rendering="crispEdges">${output}</g>` : output;
|
|
280
|
+
}
|
|
281
|
+
function isCssHexColor(value) {
|
|
282
|
+
return /^#[\da-f]{6}$/i.test(value ?? "");
|
|
283
|
+
}
|
|
284
|
+
function isUnitInterval(value) {
|
|
285
|
+
return Number.isFinite(value) && (value ?? -1) >= 0 && (value ?? 2) <= 1;
|
|
286
|
+
}
|
|
287
|
+
function isSvgPath(value) {
|
|
288
|
+
return value.length <= 1e6 && /^[\d\s.,+\-eEMmLlCcZz]+$/.test(value);
|
|
289
|
+
}
|
|
290
|
+
function fontStyles(fontFamily, alias) {
|
|
291
|
+
const normalized = fontFamily?.toLowerCase() ?? "";
|
|
292
|
+
const styles2 = [];
|
|
293
|
+
let fallback;
|
|
294
|
+
if (/courier|mono|nimbusmono|^cmtt/.test(normalized)) {
|
|
295
|
+
fallback = "Courier New,Courier,monospace";
|
|
296
|
+
} else if (/times|minion|serif|baskerville|georgia|nimbusrom|guardian.*egyp|^cm[rs]y?\d/.test(normalized)) {
|
|
297
|
+
fallback = "Times New Roman,Times,serif";
|
|
298
|
+
} else if (/helvetica|arial|sans|nimbussan|calibre|myriad|panton|^tte/.test(normalized)) {
|
|
299
|
+
fallback = "Arial,Helvetica,sans-serif";
|
|
300
|
+
} else if (/^mstt/.test(normalized)) {
|
|
301
|
+
fallback = "Arial,Helvetica,sans-serif";
|
|
302
|
+
}
|
|
303
|
+
if (alias || fallback) styles2.push(`font-family:${[alias, fallback].filter(Boolean).join(",")}`);
|
|
304
|
+
if (/bold|black|semibold|demi|medi|^tte/.test(normalized)) styles2.push("font-weight:700");
|
|
305
|
+
if (/italic|oblique|slant|ital(?:$|[_-])/.test(normalized)) styles2.push("font-style:italic");
|
|
306
|
+
return styles2;
|
|
307
|
+
}
|
|
308
|
+
function isMonospace(fontFamily) {
|
|
309
|
+
return /courier|mono/i.test(fontFamily ?? "");
|
|
310
|
+
}
|
|
311
|
+
function usesPositionedSpan(span) {
|
|
312
|
+
return !span.glyphCodes && isMonospace(span.fontFamily) && !hasNonIdentityTransform(span.transform);
|
|
313
|
+
}
|
|
314
|
+
function hasNonIdentityTransform(transform) {
|
|
315
|
+
if (!transform) return false;
|
|
316
|
+
const identity = [1, 0, 0, 1];
|
|
317
|
+
return transform.some((value, index) => Math.abs(value - (identity[index] ?? 0)) > 1e-6);
|
|
318
|
+
}
|
|
319
|
+
function fontFace(font, aliases) {
|
|
320
|
+
if (font.format !== "truetype") return "";
|
|
321
|
+
const alias = aliases.get(font.id);
|
|
322
|
+
if (!alias) return "";
|
|
323
|
+
const styles2 = fontStyles(font.family, alias).filter(
|
|
324
|
+
(style) => !style.startsWith("font-family:")
|
|
325
|
+
);
|
|
326
|
+
return `@font-face{font-family:${alias};src:url(data:font/ttf;base64,${base64(font.data)}) format("truetype");${styles2.join(";")}}`;
|
|
327
|
+
}
|
|
328
|
+
function base64(bytes) {
|
|
329
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
330
|
+
let output = "";
|
|
331
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
332
|
+
const first = bytes[index] ?? 0;
|
|
333
|
+
const second = bytes[index + 1] ?? 0;
|
|
334
|
+
const third = bytes[index + 2] ?? 0;
|
|
335
|
+
output += alphabet[first >> 2];
|
|
336
|
+
output += alphabet[(first & 3) << 4 | second >> 4];
|
|
337
|
+
output += index + 1 < bytes.length ? alphabet[(second & 15) << 2 | third >> 6] : "=";
|
|
338
|
+
output += index + 2 < bytes.length ? alphabet[third & 63] : "=";
|
|
339
|
+
}
|
|
340
|
+
return output;
|
|
80
341
|
}
|
|
81
342
|
function directionAttribute(spans) {
|
|
82
343
|
const rtl = spans.filter((span) => span.direction === "rtl").length;
|
|
@@ -103,6 +364,15 @@ function escapeHtml(value) {
|
|
|
103
364
|
function isForbiddenControl(codePoint) {
|
|
104
365
|
return codePoint <= 8 || codePoint === 11 || codePoint === 12 || codePoint >= 14 && codePoint <= 31 || codePoint === 127;
|
|
105
366
|
}
|
|
367
|
+
function resolveProfile(options) {
|
|
368
|
+
const legacyProfile = options.layout === "flow" ? "semantic" : "visual";
|
|
369
|
+
if (options.profile && options.layout && options.profile !== legacyProfile) {
|
|
370
|
+
throw new Error(
|
|
371
|
+
`conflicting HTML output options: profile "${options.profile}" does not match layout "${options.layout}"`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
return options.profile ?? legacyProfile;
|
|
375
|
+
}
|
|
106
376
|
export {
|
|
107
377
|
pageToHtml,
|
|
108
378
|
writeHtmlDocument,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { ExtractedPage, TextSpan } from \"@boxpdf/reader\";\nimport { structurePage, type Table, tableToHtml } from \"@boxpdf/reader/structure\";\n\nexport type HtmlLayout = \"positioned\" | \"flow\";\nexport type HtmlWrite = (chunk: string) => void | Promise<void>;\n\nexport interface HtmlWriterOptions {\n layout?: HtmlLayout;\n title?: string;\n language?: string;\n includeDocument?: boolean;\n includeStyles?: boolean;\n}\n\nconst styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-page-content--90{transform:translateX(100%) rotate(90deg)}.pdf-page-content--180{transform:translate(100%,100%) rotate(180deg)}.pdf-page-content--270{transform:translateY(100%) rotate(270deg)}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;\n\nexport async function writeHtmlDocument(\n pages: AsyncIterable<ExtractedPage> | Iterable<ExtractedPage>,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n const includeDocument = options.includeDocument ?? true;\n if (includeDocument) {\n await write(\"<!doctype html><html\");\n await write(\n ` lang=\"${escapeAttribute(options.language ?? \"en\")}\"><head><meta charset=\"utf-8\">`,\n );\n await write('<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">');\n await write(`<title>${escapeHtml(options.title ?? \"PDF document\")}</title>`);\n if (options.includeStyles ?? true) await write(`<style>${styles}</style>`);\n await write(\"</head><body>\");\n }\n await write('<main class=\"pdf-document\">');\n for await (const page of pages) await writePage(page, write, options);\n await write(\"</main>\");\n if (includeDocument) await write(\"</body></html>\");\n}\n\nexport async function writePage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n if ((options.layout ?? \"positioned\") === \"flow\") await writeFlowPage(page, write);\n else await writePositionedPage(page, write);\n}\n\nexport async function pageToHtml(\n page: ExtractedPage,\n options: HtmlWriterOptions = {},\n): Promise<string> {\n let output = \"\";\n await writePage(\n page,\n (chunk) => {\n output += chunk;\n },\n options,\n );\n return output;\n}\n\nasync function writePositionedPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const quarterTurn = page.rotate === 90 || page.rotate === 270;\n const displayWidth = quarterTurn ? page.height : page.width;\n const displayHeight = quarterTurn ? page.width : page.height;\n await write(\n `<section class=\"pdf-page pdf-page--positioned\" data-page=\"${page.number}\" data-rotate=\"${page.rotate}\" style=\"width:${number(displayWidth)}pt;height:${number(displayHeight)}pt\">`,\n );\n await write(\n `<div class=\"pdf-page-content pdf-page-content--${page.rotate}\" style=\"width:${number(page.width)}pt;height:${number(page.height)}pt\">`,\n );\n for (const span of page.spans) await write(positionedSpan(span));\n await write(\"</div></section>\");\n}\n\nasync function writeFlowPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const structured = structurePage(page);\n const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);\n const emittedTables = new Set<Table>();\n await write(`<section class=\"pdf-page pdf-page--flow\" data-page=\"${page.number}\">`);\n for (const line of structured.lines) {\n const table = tables.find((candidate) => containsY(candidate, line.bounds.y));\n if (table) {\n if (!emittedTables.has(table)) {\n await write(tableToHtml(table));\n emittedTables.add(table);\n }\n continue;\n }\n await write(`<p${directionAttribute(line.spans)}>${escapeHtml(line.text)}</p>`);\n }\n for (const table of tables) {\n if (!emittedTables.has(table)) await write(tableToHtml(table));\n }\n await write(\"</section>\");\n}\n\nfunction positionedSpan(span: TextSpan): string {\n const direction = directionAttribute([span]);\n const style = [\n `left:${number(span.bounds.x)}pt`,\n `bottom:${number(span.bounds.y)}pt`,\n `width:${number(span.bounds.width)}pt`,\n `height:${number(span.bounds.height)}pt`,\n `font-size:${number(span.fontSize)}pt`,\n ].join(\";\");\n return `<span class=\"pdf-span\"${direction} style=\"${style}\">${escapeHtml(span.text)}</span>`;\n}\n\nfunction directionAttribute(spans: TextSpan[]): string {\n const rtl = spans.filter((span) => span.direction === \"rtl\").length;\n const vertical = spans.filter((span) => span.direction === \"ttb\").length;\n if (vertical > rtl && vertical * 2 >= spans.length) return ' data-direction=\"ttb\"';\n return rtl * 2 >= spans.length && spans.length > 0 ? ' dir=\"rtl\"' : \"\";\n}\n\nfunction containsY(table: Table, y: number): boolean {\n return y >= table.bounds.y && y <= table.bounds.y + table.bounds.height;\n}\n\nfunction number(value: number): string {\n return Number.isFinite(value) ? String(Math.round(value * 1000) / 1000) : \"0\";\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll(\"`\", \"`\");\n}\n\nfunction escapeHtml(value: string): string {\n return [...value]\n .map((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (codePoint === 13) return \"\\n\";\n return isForbiddenControl(codePoint) ? \"�\" : character;\n })\n .join(\"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nfunction isForbiddenControl(codePoint: number): boolean {\n return (\n codePoint <= 8 ||\n codePoint === 11 ||\n codePoint === 12 ||\n (codePoint >= 14 && codePoint <= 31) ||\n codePoint === 127\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n EmbeddedFont,\n EmbeddedType3Font,\n ExtractedPage,\n RasterImage,\n TextSpan,\n Type3Glyph,\n} from \"@boxpdf/reader\";\nimport { structurePage, type Table, tableToHtml } from \"@boxpdf/reader/structure\";\n\nexport type HtmlLayout = \"positioned\" | \"flow\";\nexport type HtmlProfile = \"visual\" | \"semantic\";\nexport type HtmlWrite = (chunk: string) => void | Promise<void>;\n\nexport interface HtmlWriterOptions {\n /** Output intent. Visual preserves page presentation; semantic prioritizes reading order. */\n profile?: HtmlProfile;\n /** @deprecated Use `profile: \"visual\"` or `profile: \"semantic\"`. */\n layout?: HtmlLayout;\n title?: string;\n language?: string;\n includeDocument?: boolean;\n includeStyles?: boolean;\n}\n\nconst styles = `.pdf-document{margin:0 auto}.pdf-page{box-sizing:border-box;margin:1rem auto;background:#fff;color:#000}.pdf-page--visual,.pdf-page--positioned{position:relative;overflow:hidden}.pdf-page-content{position:absolute;transform-origin:0 0}.pdf-span{position:absolute;white-space:pre;transform-origin:left bottom;unicode-bidi:isolate}.pdf-span[data-direction=ttb]{writing-mode:vertical-rl}.pdf-page--semantic,.pdf-page--flow{max-width:60rem;padding:1rem}.pdf-page--semantic p,.pdf-page--flow p{white-space:pre-wrap;unicode-bidi:plaintext}.pdf-page table{border-collapse:collapse}.pdf-page td{padding:.15rem .4rem;vertical-align:top}`;\n\nexport async function writeHtmlDocument(\n pages: AsyncIterable<ExtractedPage> | Iterable<ExtractedPage>,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n const includeDocument = options.includeDocument ?? true;\n if (includeDocument) {\n await write(\"<!doctype html><html\");\n await write(\n ` lang=\"${escapeAttribute(options.language ?? \"en\")}\"><head><meta charset=\"utf-8\">`,\n );\n await write('<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">');\n await write(`<title>${escapeHtml(options.title ?? \"PDF document\")}</title>`);\n if (options.includeStyles ?? true) await write(`<style>${styles}</style>`);\n await write(\"</head><body>\");\n }\n await write('<main class=\"pdf-document\">');\n for await (const page of pages) await writePage(page, write, options);\n await write(\"</main>\");\n if (includeDocument) await write(\"</body></html>\");\n}\n\nexport async function writePage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions = {},\n): Promise<void> {\n if (resolveProfile(options) === \"semantic\") await writeFlowPage(page, write);\n else await writePositionedPage(page, write, options);\n}\n\nexport async function pageToHtml(\n page: ExtractedPage,\n options: HtmlWriterOptions = {},\n): Promise<string> {\n let output = \"\";\n await writePage(\n page,\n (chunk) => {\n output += chunk;\n },\n options,\n );\n return output;\n}\n\nasync function writePositionedPage(\n page: ExtractedPage,\n write: HtmlWrite,\n options: HtmlWriterOptions,\n): Promise<void> {\n const visualSpans = page.visualSpans ?? page.spans;\n const reflectedOverlay = usesReflectedVisualOverlay(page, visualSpans);\n const quarterTurn = page.rotate === 90 || page.rotate === 270;\n const displayWidth = quarterTurn ? page.height : page.width;\n const displayHeight = quarterTurn ? page.width : page.height;\n await write(\n `<section class=\"pdf-page pdf-page--visual pdf-page--positioned\" data-page=\"${page.number}\" data-rotate=\"${page.rotate}\" style=\"width:${number(displayWidth)}pt;height:${number(displayHeight)}pt\">`,\n );\n const fontAliases = new Map(\n (page.fonts ?? [])\n .filter((font) => font.format === \"truetype\" && !/(?:courier|^TTE)/i.test(font.family ?? \"\"))\n .map((font) => [font.id, `boxpdf-${page.number}-${font.id}`]),\n );\n const type3Fonts = new Map(\n (page.fonts ?? [])\n .filter((font): font is EmbeddedType3Font => font.format === \"type3\")\n .map((font) => [font.id, font]),\n );\n if ((options.includeStyles ?? true) && page.fonts?.length) {\n await write(`<style>${page.fonts.map((font) => fontFace(font, fontAliases)).join(\"\")}</style>`);\n }\n await write(\n `<div class=\"pdf-page-content pdf-page-content--${page.rotate}\" style=\"width:${number(page.width)}pt;height:${number(page.height)}pt${rotationTransform(page)}\">`,\n );\n await write(\n `<svg class=\"pdf-visual-text\" xmlns=\"http://www.w3.org/2000/svg\" width=\"${number(page.width)}pt\" height=\"${number(page.height)}pt\" viewBox=\"0 0 ${number(page.width)} ${number(page.height)}\">`,\n );\n if (reflectedOverlay) {\n for (const image of page.images ?? []) await write(visualImage(image, page.height));\n }\n for (const fill of page.fills ?? []) {\n const points = fill.points.map(([x, y]) => `${number(x)},${number(page.height - y)}`).join(\" \");\n if (isCssHexColor(fill.color)) {\n const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity=\"${number(fill.opacity)}\"` : \"\";\n await write(`<polygon points=\"${points}\" fill=\"${fill.color}\"${opacity}/>`);\n }\n }\n if (page.paths?.length) {\n await write(`<g transform=\"translate(0 ${number(page.height)}) scale(1 -1)\">`);\n for (const path of page.paths) {\n if (!isSvgPath(path.d)) continue;\n const fill = isCssHexColor(path.fill) ? path.fill : \"none\";\n const stroke = isCssHexColor(path.stroke) ? path.stroke : \"none\";\n const strokeWidth =\n path.strokeWidth !== undefined && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0\n ? ` stroke-width=\"${number(path.strokeWidth)}\"`\n : \"\";\n const fillRule = path.fillRule ? ` fill-rule=\"${path.fillRule}\"` : \"\";\n const fillOpacity = isUnitInterval(path.fillOpacity)\n ? ` fill-opacity=\"${number(path.fillOpacity)}\"`\n : \"\";\n const strokeOpacity = isUnitInterval(path.strokeOpacity)\n ? ` stroke-opacity=\"${number(path.strokeOpacity)}\"`\n : \"\";\n const dasharray = path.strokeDasharray?.every((value) => Number.isFinite(value) && value >= 0)\n ? ` stroke-dasharray=\"${path.strokeDasharray.map(number).join(\" \")}\"`\n : \"\";\n const dashoffset = Number.isFinite(path.strokeDashoffset)\n ? ` stroke-dashoffset=\"${number(path.strokeDashoffset ?? 0)}\"`\n : \"\";\n const linecap = path.strokeLinecap ? ` stroke-linecap=\"${path.strokeLinecap}\"` : \"\";\n const linejoin = path.strokeLinejoin ? ` stroke-linejoin=\"${path.strokeLinejoin}\"` : \"\";\n await write(\n `<path d=\"${path.d}\" fill=\"${fill}\" stroke=\"${stroke}\"${strokeWidth}${fillOpacity}${strokeOpacity}${dasharray}${dashoffset}${linecap}${linejoin}${fillRule}/>`,\n );\n }\n await write(\"</g>\");\n }\n if (!reflectedOverlay) {\n for (const image of page.images ?? []) await write(visualImage(image, page.height));\n }\n for (const span of visualSpans) {\n if (!usesPositionedSpan(span)) {\n const type3 = span.fontAssetId ? type3Fonts.get(span.fontAssetId) : undefined;\n await write(\n type3\n ? visualType3Text(span, type3, page.height)\n : visualText(span, page.height, fontAliases, reflectedOverlay && page.rotate === 180),\n );\n }\n }\n await write(\"</svg>\");\n for (const span of visualSpans) {\n if (usesPositionedSpan(span)) await write(positionedSpan(span, fontAliases));\n }\n await write(\"</div></section>\");\n}\n\nfunction usesReflectedVisualOverlay(page: ExtractedPage, spans: TextSpan[]): boolean {\n return (\n Boolean(page.images?.length) &&\n Boolean(page.paths?.length || page.fills?.length) &&\n spans.length > 0 &&\n spans.every(\n (span) =>\n span.transform !== undefined &&\n Math.abs(span.transform[0] + 1) < 0.000_001 &&\n Math.abs(span.transform[1]) < 0.000_001 &&\n Math.abs(span.transform[2]) < 0.000_001 &&\n Math.abs(span.transform[3] - 1) < 0.000_001,\n )\n );\n}\n\nfunction visualImage(image: RasterImage, pageHeight: number): string {\n const [a, b, c, d, e, f] = image.transform;\n const transform = [a, -b, -c, d, c + e, pageHeight - d - f].map(number).join(\" \");\n const opacity = isUnitInterval(image.opacity) ? ` opacity=\"${number(image.opacity)}\"` : \"\";\n const mime = image.format === \"jpeg\" ? \"image/jpeg\" : \"image/bmp\";\n const data = image.format === \"jpeg\" ? image.data : rgbBmp(image);\n return `<image width=\"1\" height=\"1\" preserveAspectRatio=\"none\" transform=\"matrix(${transform})\" href=\"data:${mime};base64,${base64(data)}\"${opacity}/>`;\n}\n\nfunction rgbBmp(image: RasterImage): Uint8Array {\n const stride = Math.ceil((image.width * 3) / 4) * 4;\n const output = new Uint8Array(54 + stride * image.height);\n const view = new DataView(output.buffer);\n output[0] = 0x42;\n output[1] = 0x4d;\n view.setUint32(2, output.length, true);\n view.setUint32(10, 54, true);\n view.setUint32(14, 40, true);\n view.setInt32(18, image.width, true);\n view.setInt32(22, -image.height, true);\n view.setUint16(26, 1, true);\n view.setUint16(28, 24, true);\n view.setUint32(34, stride * image.height, true);\n for (let row = 0; row < image.height; row += 1) {\n for (let column = 0; column < image.width; column += 1) {\n const source = (row * image.width + column) * 3;\n const target = 54 + row * stride + column * 3;\n output[target] = image.data[source + 2] ?? 0;\n output[target + 1] = image.data[source + 1] ?? 0;\n output[target + 2] = image.data[source] ?? 0;\n }\n }\n return output;\n}\n\nfunction rotationTransform(page: ExtractedPage): string {\n switch (page.rotate) {\n case 90:\n return `;transform:translate(${number(page.height)}pt,0) rotate(90deg)`;\n case 180:\n return `;transform:translate(${number(page.width)}pt,${number(page.height)}pt) rotate(180deg)`;\n case 270:\n return `;transform:translate(0,${number(page.width)}pt) rotate(270deg)`;\n default:\n return \"\";\n }\n}\n\nfunction positionedSpan(span: TextSpan, fontAliases: Map<string, string>): string {\n const direction = directionAttribute([span]);\n const style = [\n `left:${number(span.bounds.x)}pt`,\n `bottom:${number(span.bounds.y)}pt`,\n `width:${number(span.bounds.width)}pt`,\n `height:${number(span.bounds.height)}pt`,\n `font-size:${number(span.fontSize)}pt`,\n ...(isCssHexColor(span.color) ? [`color:${span.color}`] : []),\n ...(isUnitInterval(span.fillOpacity) ? [`opacity:${number(span.fillOpacity)}`] : []),\n ...fontStyles(\n span.fontFamily,\n span.fontAssetId ? fontAliases.get(span.fontAssetId) : undefined,\n ),\n ].join(\";\");\n return `<span class=\"pdf-span\"${direction} style=\"${style}\">${escapeHtml(span.text)}</span>`;\n}\n\nasync function writeFlowPage(page: ExtractedPage, write: HtmlWrite): Promise<void> {\n const structured = structurePage(page);\n const tables = [...structured.tables].sort((left, right) => right.bounds.y - left.bounds.y);\n const emittedTables = new Set<Table>();\n await write(\n `<section class=\"pdf-page pdf-page--semantic pdf-page--flow\" data-page=\"${page.number}\">`,\n );\n for (const line of structured.lines) {\n const table = tables.find((candidate) => containsY(candidate, line.bounds.y));\n if (table) {\n if (!emittedTables.has(table)) {\n await write(tableToHtml(table));\n emittedTables.add(table);\n }\n continue;\n }\n await write(`<p${directionAttribute(line.spans)}>${escapeHtml(line.text)}</p>`);\n }\n for (const table of tables) {\n if (!emittedTables.has(table)) await write(tableToHtml(table));\n }\n await write(\"</section>\");\n}\n\nfunction visualText(\n span: TextSpan,\n pageHeight: number,\n fontAliases: Map<string, string>,\n counterRotateReflectedText = false,\n): string {\n if (span.renderingMode === 3 || span.renderingMode === 7) return \"\";\n if (!span.fontAssetId && isAdobeCjkFont(span.fontFamily)) return \"\";\n const direction = directionAttribute([span]);\n const font = fontStyles(\n span.fontFamily,\n span.fontAssetId ? fontAliases.get(span.fontAssetId) : undefined,\n ).join(\";\");\n const stroke = isCssHexColor(span.strokeColor) ? `stroke:${span.strokeColor}` : \"\";\n const strokeWidth =\n stroke && Number.isFinite(span.strokeWidth) && (span.strokeWidth ?? -1) >= 0\n ? `stroke-width:${number(span.strokeWidth ?? 0)}`\n : \"\";\n const strokeOnly = span.renderingMode === 1 || span.renderingMode === 5;\n const fillOpacity = isUnitInterval(span.fillOpacity)\n ? `fill-opacity:${number(span.fillOpacity)}`\n : \"\";\n const strokeOpacity = isUnitInterval(span.strokeOpacity)\n ? `stroke-opacity:${number(span.strokeOpacity)}`\n : \"\";\n const style = [\n isHebrewPaintOrder(span) ? \"unicode-bidi:bidi-override;direction:ltr\" : \"\",\n span.direction === \"ttb\" ? \"writing-mode:vertical-rl\" : \"\",\n strokeOnly ? \"fill:none\" : isCssHexColor(span.color) ? `fill:${span.color}` : \"\",\n stroke,\n strokeWidth,\n fillOpacity,\n strokeOpacity,\n font,\n ]\n .filter(Boolean)\n .join(\";\");\n const textExtent = span.direction === \"ttb\" ? span.bounds.height : span.bounds.width;\n const textLength =\n textExtent > 0 && !isHebrewPaintOrder(span)\n ? ` textLength=\"${number(textExtent)}\" lengthAdjust=\"${span.direction === \"ttb\" || usesSpacingAdjustment(span) ? \"spacing\" : \"spacingAndGlyphs\"}\"`\n : \"\";\n const transform =\n counterRotateReflectedText && span.transform\n ? ([\n span.transform[0],\n span.transform[1],\n span.transform[2],\n -span.transform[3],\n ] as TextSpan[\"transform\"])\n : span.transform;\n const transformed = hasNonIdentityTransform(transform);\n const rtlOffset = span.direction === \"rtl\" ? span.bounds.width : 0;\n const basisX = transform?.[0] ?? 1;\n const basisY = transform?.[1] ?? 0;\n const anchorX = span.bounds.x + basisX * rtlOffset;\n const anchorY = pageHeight - span.bounds.y + basisY * rtlOffset;\n const position = transformed\n ? ` x=\"0\" y=\"0\" transform=\"matrix(${transform?.map(number).join(\" \")} ${number(anchorX)} ${number(anchorY)})\"`\n : ` x=\"${number(anchorX)}\" y=\"${number(anchorY)}\"`;\n return `<text${direction}${position} font-size=\"${number(span.fontSize)}\"${textLength}${style ? ` style=\"${style}\"` : \"\"}>${escapeHtml(span.text)}</text>`;\n}\n\nfunction isAdobeCjkFont(fontFamily: string | undefined): boolean {\n return /^Adobe(?:Heiti|Song|Kaiti|Ming|Gothic|Mincho)Std-/i.test(fontFamily ?? \"\");\n}\n\nfunction visualType3Text(span: TextSpan, font: EmbeddedType3Font, pageHeight: number): string {\n if (span.renderingMode === 3 || span.renderingMode === 7) return \"\";\n const glyphs = new Map(font.glyphs.map((glyph) => [glyph.code, glyph]));\n const sequence = (span.glyphCodes ?? []).map((code) => glyphs.get(code));\n const totalAdvance = sequence.reduce((total, glyph) => total + (glyph?.advance ?? 0), 0);\n if (totalAdvance <= 0 || span.bounds.width <= 0 || span.fontSize <= 0) return \"\";\n const transform = span.transform ?? [1, 0, 0, 1];\n const outer = `matrix(${transform.map(number).join(\" \")} ${number(span.bounds.x)} ${number(pageHeight - span.bounds.y)})`;\n const xScale = span.bounds.width / totalAdvance;\n let offset = 0;\n let content = \"\";\n for (const glyph of sequence) {\n if (!glyph) continue;\n content += `<g transform=\"translate(${number(offset)} 0)\">${type3Glyph(glyph)}</g>`;\n offset += glyph.advance;\n }\n return `<g transform=\"${outer}\"><g transform=\"scale(${number(xScale)} ${number(-span.fontSize)})\">${content}</g></g>`;\n}\n\nfunction isHebrewPaintOrder(span: TextSpan): boolean {\n return span.direction === \"ltr\" && /[\\u0590-\\u05ff]/u.test(span.text);\n}\n\nfunction usesSpacingAdjustment(span: TextSpan): boolean {\n return !span.fontAssetId && /arial/i.test(span.fontFamily ?? \"\");\n}\n\nfunction type3Glyph(glyph: Type3Glyph): string {\n let output = \"\";\n for (const fill of glyph.fills ?? []) {\n if (!isCssHexColor(fill.color)) continue;\n const points = fill.points.map(([x, y]) => `${number(x)},${number(y)}`).join(\" \");\n const opacity = isUnitInterval(fill.opacity) ? ` fill-opacity=\"${number(fill.opacity)}\"` : \"\";\n output += `<polygon points=\"${points}\" fill=\"${fill.color}\"${opacity}/>`;\n }\n for (const path of glyph.paths ?? []) {\n if (!isSvgPath(path.d)) continue;\n const fill = isCssHexColor(path.fill) ? path.fill : \"none\";\n const stroke = isCssHexColor(path.stroke) ? path.stroke : \"none\";\n const width =\n path.strokeWidth !== undefined && Number.isFinite(path.strokeWidth) && path.strokeWidth >= 0\n ? ` stroke-width=\"${number(path.strokeWidth)}\"`\n : \"\";\n output += `<path d=\"${path.d}\" fill=\"${fill}\" stroke=\"${stroke}\"${width}/>`;\n }\n return (glyph.fills?.length ?? 0) > 64 && glyph.advance > 2\n ? `<g shape-rendering=\"crispEdges\">${output}</g>`\n : output;\n}\n\nfunction isCssHexColor(value: string | undefined): value is string {\n return /^#[\\da-f]{6}$/i.test(value ?? \"\");\n}\n\nfunction isUnitInterval(value: number | undefined): value is number {\n return Number.isFinite(value) && (value ?? -1) >= 0 && (value ?? 2) <= 1;\n}\n\nfunction isSvgPath(value: string): boolean {\n return value.length <= 1_000_000 && /^[\\d\\s.,+\\-eEMmLlCcZz]+$/.test(value);\n}\n\nfunction fontStyles(fontFamily: string | undefined, alias?: string): string[] {\n const normalized = fontFamily?.toLowerCase() ?? \"\";\n const styles: string[] = [];\n let fallback: string | undefined;\n if (/courier|mono|nimbusmono|^cmtt/.test(normalized)) {\n fallback = \"Courier New,Courier,monospace\";\n } else if (\n /times|minion|serif|baskerville|georgia|nimbusrom|guardian.*egyp|^cm[rs]y?\\d/.test(normalized)\n ) {\n fallback = \"Times New Roman,Times,serif\";\n } else if (/helvetica|arial|sans|nimbussan|calibre|myriad|panton|^tte/.test(normalized)) {\n fallback = \"Arial,Helvetica,sans-serif\";\n } else if (/^mstt/.test(normalized)) {\n fallback = \"Arial,Helvetica,sans-serif\";\n }\n if (alias || fallback) styles.push(`font-family:${[alias, fallback].filter(Boolean).join(\",\")}`);\n if (/bold|black|semibold|demi|medi|^tte/.test(normalized)) styles.push(\"font-weight:700\");\n if (/italic|oblique|slant|ital(?:$|[_-])/.test(normalized)) styles.push(\"font-style:italic\");\n return styles;\n}\n\nfunction isMonospace(fontFamily: string | undefined): boolean {\n return /courier|mono/i.test(fontFamily ?? \"\");\n}\n\nfunction usesPositionedSpan(span: TextSpan): boolean {\n return (\n !span.glyphCodes && isMonospace(span.fontFamily) && !hasNonIdentityTransform(span.transform)\n );\n}\n\nfunction hasNonIdentityTransform(transform: TextSpan[\"transform\"]): boolean {\n if (!transform) return false;\n const identity: [number, number, number, number] = [1, 0, 0, 1];\n return transform.some((value, index) => Math.abs(value - (identity[index] ?? 0)) > 0.000_001);\n}\n\nfunction fontFace(font: EmbeddedFont, aliases: Map<string, string>): string {\n if (font.format !== \"truetype\") return \"\";\n const alias = aliases.get(font.id);\n if (!alias) return \"\";\n const styles = fontStyles(font.family, alias).filter(\n (style) => !style.startsWith(\"font-family:\"),\n );\n return `@font-face{font-family:${alias};src:url(data:font/ttf;base64,${base64(font.data)}) format(\"truetype\");${styles.join(\";\")}}`;\n}\n\nfunction base64(bytes: Uint8Array): string {\n const alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n let output = \"\";\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0;\n const second = bytes[index + 1] ?? 0;\n const third = bytes[index + 2] ?? 0;\n output += alphabet[first >> 2];\n output += alphabet[((first & 3) << 4) | (second >> 4)];\n output += index + 1 < bytes.length ? alphabet[((second & 15) << 2) | (third >> 6)] : \"=\";\n output += index + 2 < bytes.length ? alphabet[third & 63] : \"=\";\n }\n return output;\n}\n\nfunction directionAttribute(spans: TextSpan[]): string {\n const rtl = spans.filter((span) => span.direction === \"rtl\").length;\n const vertical = spans.filter((span) => span.direction === \"ttb\").length;\n if (vertical > rtl && vertical * 2 >= spans.length) return ' data-direction=\"ttb\"';\n return rtl * 2 >= spans.length && spans.length > 0 ? ' dir=\"rtl\"' : \"\";\n}\n\nfunction containsY(table: Table, y: number): boolean {\n return y >= table.bounds.y && y <= table.bounds.y + table.bounds.height;\n}\n\nfunction number(value: number): string {\n return Number.isFinite(value) ? String(Math.round(value * 1000) / 1000) : \"0\";\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll(\"`\", \"`\");\n}\n\nfunction escapeHtml(value: string): string {\n return [...value]\n .map((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (codePoint === 13) return \"\\n\";\n return isForbiddenControl(codePoint) ? \"�\" : character;\n })\n .join(\"\")\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n\nfunction isForbiddenControl(codePoint: number): boolean {\n return (\n codePoint <= 8 ||\n codePoint === 11 ||\n codePoint === 12 ||\n (codePoint >= 14 && codePoint <= 31) ||\n codePoint === 127\n );\n}\n\nfunction resolveProfile(options: HtmlWriterOptions): HtmlProfile {\n const legacyProfile = options.layout === \"flow\" ? \"semantic\" : \"visual\";\n if (options.profile && options.layout && options.profile !== legacyProfile) {\n throw new Error(\n `conflicting HTML output options: profile \"${options.profile}\" does not match layout \"${options.layout}\"`,\n );\n }\n return options.profile ?? legacyProfile;\n}\n"],"mappings":"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","names":["styles"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boxpdf/html-writer",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Stream PDF pages from @boxpdf/reader to
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Stream PDF pages from @boxpdf/reader to visual or semantic HTML.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pdf",
|
|
7
7
|
"pdf-to-html",
|