wasm-html-to-image 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-orchestrate.d.ts +1 -0
- package/dist/core-orchestrate.js +6 -1
- package/dist/core-resources.js +26 -2
- package/dist/core.d.ts +22 -0
- package/dist/html-to-image-wasm.js +3 -3
- package/dist/html-to-image.wasm +0 -0
- package/dist/loader.d.ts +2 -0
- package/dist/single.d.ts +1 -1
- package/dist/web-workers.js +24 -4
- package/package.json +1 -1
|
@@ -42,6 +42,7 @@ export interface Orchestration {
|
|
|
42
42
|
onLog: HtmlToImageOptions["onLog"];
|
|
43
43
|
diagnostics: boolean;
|
|
44
44
|
onDiagnostics: HtmlToImageOptions["onDiagnostics"];
|
|
45
|
+
onLayout: HtmlToImageOptions["onLayout"];
|
|
45
46
|
resolveResource: ResolveResourceHook | undefined;
|
|
46
47
|
mediaType: "screen" | "print";
|
|
47
48
|
textToPaths: boolean | undefined;
|
package/dist/core-orchestrate.js
CHANGED
|
@@ -34,7 +34,7 @@ export function defaultSpeed(format) {
|
|
|
34
34
|
}
|
|
35
35
|
/** Build per-call orchestration state (log gate, timings, diag, resolve ctx). */
|
|
36
36
|
export function createOrchestration(module, options) {
|
|
37
|
-
const { format = "png", quality = 85, speed: speedOption, width, height, crop, fit, value, url, baseUrl, fontMap, userAgent, fallbackFonts, logLevel = LogLevel.None, onLog, diagnostics = false, onDiagnostics, resolveResource, mediaType = "screen", textToPaths, css, fonts: preloadFonts, limits = {}, pdfTitle, pdfAuthor, pdfSubject, pdfKeywords, pdfCreator, pdfProducer, pdfMargin, pdfHeader, pdfFooter, } = options;
|
|
37
|
+
const { format = "png", quality = 85, speed: speedOption, width, height, crop, fit, value, url, baseUrl, fontMap, userAgent, fallbackFonts, logLevel = LogLevel.None, onLog, diagnostics = false, onDiagnostics, onLayout, resolveResource, mediaType = "screen", textToPaths, css, fonts: preloadFonts, limits = {}, pdfTitle, pdfAuthor, pdfSubject, pdfKeywords, pdfCreator, pdfProducer, pdfMargin, pdfHeader, pdfFooter, } = options;
|
|
38
38
|
// `animation` accepts a boolean (image input: keep frames) or, for HTML
|
|
39
39
|
// input, an object requesting keyframe sampling. The object form turns on
|
|
40
40
|
// the boolean flag for the encode stage and enables the frame path.
|
|
@@ -167,6 +167,7 @@ export function createOrchestration(module, options) {
|
|
|
167
167
|
onLog,
|
|
168
168
|
diagnostics,
|
|
169
169
|
onDiagnostics,
|
|
170
|
+
onLayout,
|
|
170
171
|
resolveResource,
|
|
171
172
|
mediaType,
|
|
172
173
|
textToPaths,
|
|
@@ -407,6 +408,10 @@ export async function tryRunHtmlInstance(module, htmls, satoruOpts, defaultFontM
|
|
|
407
408
|
await resolveHtmlResources(module, sInst, htmls, width, height, baseUrl, fontMap ?? defaultFontMap, userAgent ?? DEFAULT_USER_AGENT, fallbackFonts, resolveCtx);
|
|
408
409
|
addTime("resolveResources", now() - resolveStart);
|
|
409
410
|
emitLog(LogLevel.Info, "resources resolved");
|
|
411
|
+
if (orch.onLayout && typeof module.satoru_layout_json === "function") {
|
|
412
|
+
const page = Array.isArray(htmls) ? htmls[0] : htmls;
|
|
413
|
+
orch.onLayout(JSON.parse(module.satoru_layout_json(sInst, page, width, height ?? 0, orch.mediaTypeInt)));
|
|
414
|
+
}
|
|
410
415
|
if (format === "svg" || format === "pdf") {
|
|
411
416
|
const renderStart = now();
|
|
412
417
|
const out = (await renderBinding(sInst, htmls, width, height ?? 0, fmtInt, satoruOpts));
|
package/dist/core-resources.js
CHANGED
|
@@ -108,7 +108,8 @@ async function fetchResourceBytesInner(url, baseUrl, userAgent, timeoutMs, confi
|
|
|
108
108
|
const headers = userAgent && isNodeRuntime() ? { "User-Agent": userAgent } : undefined;
|
|
109
109
|
// Abort hung connections so one stalled server cannot outlive `timeoutMs`.
|
|
110
110
|
const signal = timeoutMs !== undefined
|
|
111
|
-
?
|
|
111
|
+
? // Node >= 24 requires an integer delay; the remaining budget is fractional.
|
|
112
|
+
AbortSignal.timeout(Math.max(1, Math.ceil(timeoutMs)))
|
|
112
113
|
: undefined;
|
|
113
114
|
const fetchBytes = async (target) => {
|
|
114
115
|
// Servers may vary the body by User-Agent (e.g. woff2 vs ttf CSS).
|
|
@@ -440,7 +441,17 @@ export async function resolveHtmlResources(module, satoruInst, htmls, width, hei
|
|
|
440
441
|
// later sheet must not land before (and so lose to) a large earlier one. They are
|
|
441
442
|
// buffered here and injected in discovery order once the whole round has settled.
|
|
442
443
|
const loadedCss = [];
|
|
443
|
-
|
|
444
|
+
// When maxResourceCount cuts a round short, what is dropped should be the least harmful: a missing
|
|
445
|
+
// image leaves a hole, a missing font turns the whole text into tofu. Stylesheets go first (they
|
|
446
|
+
// cascade by document order and may reveal more), then fonts, then images; discovery order is
|
|
447
|
+
// kept within each kind.
|
|
448
|
+
const rank = (t) => (t === "css" ? 0 : t === "font" ? 1 : 2);
|
|
449
|
+
const ordered = pending
|
|
450
|
+
.map((r, i) => ({ r, i }))
|
|
451
|
+
.sort((a, b) => rank(a.r.type) - rank(b.r.type) || a.i - b.i)
|
|
452
|
+
.map((e) => e.r);
|
|
453
|
+
let fontsSkippedByCount = 0;
|
|
454
|
+
await mapWithLimit(ordered, FETCH_CONCURRENCY, async (r) => {
|
|
444
455
|
const diag = ctx.diag;
|
|
445
456
|
const entry = diag
|
|
446
457
|
? {
|
|
@@ -482,6 +493,8 @@ export async function resolveHtmlResources(module, satoruInst, htmls, width, hei
|
|
|
482
493
|
if (ctx.limits.maxResourceCount !== undefined &&
|
|
483
494
|
ctx.usage.resourceCount >= ctx.limits.maxResourceCount) {
|
|
484
495
|
const message = `Maximum resource count (${ctx.limits.maxResourceCount}) exceeded`;
|
|
496
|
+
if (r.type === "font")
|
|
497
|
+
fontsSkippedByCount++;
|
|
485
498
|
skipWithError(DIAGNOSTIC_CODES.LIMIT_RESOURCE_COUNT, message);
|
|
486
499
|
return;
|
|
487
500
|
}
|
|
@@ -538,6 +551,17 @@ export async function resolveHtmlResources(module, satoruInst, htmls, width, hei
|
|
|
538
551
|
diag?.warnings.push(d);
|
|
539
552
|
}
|
|
540
553
|
});
|
|
554
|
+
if (fontsSkippedByCount > 0) {
|
|
555
|
+
// Text in those fonts renders as tofu: say what to change instead of leaving a silent bad image.
|
|
556
|
+
const message = `${fontsSkippedByCount} font file(s) were not loaded because maxResourceCount ` +
|
|
557
|
+
`(${ctx.limits.maxResourceCount}) was reached; text using them may render as missing glyphs. ` +
|
|
558
|
+
"Raise limits.maxResourceCount (a Google Fonts stylesheet alone can reference over a hundred files).";
|
|
559
|
+
ctx.diag?.warnings.push({
|
|
560
|
+
code: DIAGNOSTIC_CODES.LIMIT_RESOURCE_COUNT,
|
|
561
|
+
message,
|
|
562
|
+
});
|
|
563
|
+
ctx.emitLog(LogLevel.Warning, message);
|
|
564
|
+
}
|
|
541
565
|
loadedCss.sort((a, b) => a.index - b.index);
|
|
542
566
|
for (const css of loadedCss) {
|
|
543
567
|
const text = new TextDecoder().decode(css.bytes);
|
package/dist/core.d.ts
CHANGED
|
@@ -60,6 +60,21 @@ export interface RenderOptions {
|
|
|
60
60
|
* - Image input: render stage is skipped; `width`/`height`/`crop`/`fit`
|
|
61
61
|
* are applied as output resize on the encode stage.
|
|
62
62
|
*/
|
|
63
|
+
/** One element's border box from `onLayout` (page coordinates, CSS px). */
|
|
64
|
+
export interface LayoutBox {
|
|
65
|
+
/** Path of element-child indexes from the root, e.g. "0.1.3". */
|
|
66
|
+
p: string;
|
|
67
|
+
/** Lower-case tag name. */
|
|
68
|
+
t: string;
|
|
69
|
+
/** `id` attribute ("" when absent). */
|
|
70
|
+
i: string;
|
|
71
|
+
/** `class` attribute, truncated ("" when absent). */
|
|
72
|
+
c: string;
|
|
73
|
+
x: number;
|
|
74
|
+
y: number;
|
|
75
|
+
w: number;
|
|
76
|
+
h: number;
|
|
77
|
+
}
|
|
63
78
|
export interface HtmlToImageOptions extends RenderOptions {
|
|
64
79
|
/** Encode quality 0-100 (encode stage only, default 85; ignored for svg/pdf). */
|
|
65
80
|
quality?: number;
|
|
@@ -127,6 +142,13 @@ export interface HtmlToImageOptions extends RenderOptions {
|
|
|
127
142
|
diagnostics?: boolean;
|
|
128
143
|
/** Receives the diagnostics report when `diagnostics` is enabled. */
|
|
129
144
|
onDiagnostics?: (report: RenderDiagnostics) => void;
|
|
145
|
+
/**
|
|
146
|
+
* Debug aid for comparing against a reference browser: receives every laid-out element's border
|
|
147
|
+
* box in page coordinates (HTML input only; `html-to-image` instance pipeline). `p` is the
|
|
148
|
+
* element's path among element children of the shadow-flattened tree ("0.1.3"), so a browser
|
|
149
|
+
* walk produces the same keys. Inline boxes are omitted except replaced ones (img, svg, ...).
|
|
150
|
+
*/
|
|
151
|
+
onLayout?: (boxes: LayoutBox[]) => void;
|
|
130
152
|
/**
|
|
131
153
|
* Override hook for resource resolution, applied to every fetch path
|
|
132
154
|
* (discovery fetches, fallback-font URLs, HTML `url` fetch). Return
|