mnfst 0.5.74 → 0.5.75
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/lib/manifest.export.js +46 -2
- package/package.json +1 -1
package/lib/manifest.export.js
CHANGED
|
@@ -242,10 +242,30 @@ function initializeExportPlugin() {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
// Chromium and Safari reject SVG-image decoding past roughly 16,000px on
|
|
246
|
+
// either axis. A long article at pixelRatio: 2 easily exceeds that. When
|
|
247
|
+
// the target is the whole body we cap dimensions so the assembled SVG
|
|
248
|
+
// stays decodable; explicit targets keep their natural size.
|
|
249
|
+
const SAFE_MAX_DIMENSION = 14000;
|
|
250
|
+
|
|
251
|
+
function applySafeDimensions(target, so) {
|
|
252
|
+
const isWholeBody = target === document.body || target === document.documentElement;
|
|
253
|
+
if (!isWholeBody) return so;
|
|
254
|
+
const rect = target.getBoundingClientRect();
|
|
255
|
+
const width = Math.max(rect.width, target.scrollWidth || 0);
|
|
256
|
+
const height = Math.max(rect.height, target.scrollHeight || 0);
|
|
257
|
+
const ratio = so.pixelRatio || 2;
|
|
258
|
+
const limit = SAFE_MAX_DIMENSION / ratio;
|
|
259
|
+
const out = { ...so };
|
|
260
|
+
if (width > limit) out.canvasWidth = Math.floor(limit);
|
|
261
|
+
if (height > limit) out.canvasHeight = Math.floor(limit);
|
|
262
|
+
return out;
|
|
263
|
+
}
|
|
264
|
+
|
|
245
265
|
async function exportImage(opts, filename, ext) {
|
|
246
266
|
const lib = await loadHtmlToImage();
|
|
247
267
|
const target = resolveTarget(opts);
|
|
248
|
-
const so = snapshotOptions(opts);
|
|
268
|
+
const so = applySafeDimensions(target, snapshotOptions(opts));
|
|
249
269
|
let dataUrl;
|
|
250
270
|
if (ext === 'png') dataUrl = await snapshotWithFallback(lib, 'toPng', target, so);
|
|
251
271
|
else if (ext === 'jpeg') {
|
|
@@ -262,10 +282,20 @@ function initializeExportPlugin() {
|
|
|
262
282
|
triggerDownload(dataUrl, filename);
|
|
263
283
|
}
|
|
264
284
|
|
|
285
|
+
// Whole-page PDF: route through the browser's native print pipeline.
|
|
286
|
+
// It handles multi-page layout, page breaks, vector text, and the page's
|
|
287
|
+
// own @media print CSS — far more reliable than rasterizing a long page
|
|
288
|
+
// and embedding it as a single image. The user sees the print dialog and
|
|
289
|
+
// picks "Save as PDF" (or any installed PDF printer). Element-scoped PDFs
|
|
290
|
+
// continue to use html-to-image + jsPDF, which is well-behaved at small
|
|
291
|
+
// target sizes.
|
|
265
292
|
async function exportPdf(opts, filename) {
|
|
293
|
+
if (!opts.target) {
|
|
294
|
+
return printToPdf(filename);
|
|
295
|
+
}
|
|
266
296
|
const [imgLib, jsPDFCtor] = await Promise.all([loadHtmlToImage(), loadJsPDF()]);
|
|
267
297
|
const target = resolveTarget(opts);
|
|
268
|
-
const so = snapshotOptions(opts);
|
|
298
|
+
const so = applySafeDimensions(target, snapshotOptions(opts));
|
|
269
299
|
if (!so.backgroundColor) so.backgroundColor = effectivePageBackground();
|
|
270
300
|
const dataUrl = await snapshotWithFallback(imgLib, 'toPng', target, so);
|
|
271
301
|
const img = await loadImage(dataUrl);
|
|
@@ -282,6 +312,20 @@ function initializeExportPlugin() {
|
|
|
282
312
|
pdf.save(filename);
|
|
283
313
|
}
|
|
284
314
|
|
|
315
|
+
function printToPdf(filename) {
|
|
316
|
+
// The browser's "Save as PDF" dialog seeds its default filename from
|
|
317
|
+
// document.title. Swap it briefly so the suggested name matches the
|
|
318
|
+
// user's intent, then restore after the dialog closes.
|
|
319
|
+
const original = document.title;
|
|
320
|
+
const cleaned = String(filename || '').replace(/\.pdf$/i, '') || original;
|
|
321
|
+
document.title = cleaned;
|
|
322
|
+
try { window.print(); }
|
|
323
|
+
finally {
|
|
324
|
+
// Wait one frame so the print dialog reads the swapped title first.
|
|
325
|
+
setTimeout(() => { document.title = original; }, 0);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
285
329
|
function effectivePageBackground() {
|
|
286
330
|
let el = document.body;
|
|
287
331
|
while (el && el !== document.documentElement.parentElement) {
|