-
Notifications
You must be signed in to change notification settings - Fork 57
Open
Description
I'm downloading a PDF and all the pages are different sizes. You code uses the first page size for all pages.
This code fixes it for me.
(async function () {
console.log("Loading script ...");
const load = (url) =>
new Promise((res, rej) => {
const s = document.createElement("script");
s.onload = () => res();
s.onerror = rej;
// Trusted Types safe-ish path
if (window.trustedTypes && trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy("jspdfPolicy", {
createScriptURL: (input) => input,
});
s.src = policy.createScriptURL(url);
} else {
s.src = url;
}
document.body.appendChild(s);
});
await load("https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js");
const { jsPDF } = window.jspdf;
// Collect blob: images (e.g., Google Drive preview)
const imgs = Array.from(document.getElementsByTagName("img"))
.filter((img) => img.src.startsWith("blob:"))
// Ensure the image actually decoded so naturalWidth/Height are valid
.filter((img) => {
// Some browsers support decode(); guard and fallback
return typeof img.decode === "function"
? true
: img.naturalWidth > 0 && img.naturalHeight > 0;
});
console.log(`Scanning content ... found ${imgs.length} images`);
// Ensure all images are decoded to get correct natural sizes
for (const img of imgs) {
if (typeof img.decode === "function") {
try { await img.decode(); } catch {} // ignore decode errors; we'll try anyway
}
}
if (imgs.length === 0) {
console.warn("No blob: images found.");
return;
}
// Helper: image -> dataURL at native size
async function imgToDataURL(img) {
const c = document.createElement("canvas");
c.width = img.naturalWidth;
c.height = img.naturalHeight;
const ctx = c.getContext("2d");
ctx.drawImage(img, 0, 0, c.width, c.height);
// PNG preserves exact pixels (no JPEG artifacts)
const url = c.toDataURL("image/png");
// help GC
c.width = c.height = 0;
return url;
}
// Build page descriptors (orientation + size in px)
const pages = [];
for (let i = 0; i < imgs.length; i++) {
const img = imgs[i];
const w = img.naturalWidth || 1;
const h = img.naturalHeight || 1;
const orientation = w >= h ? "l" : "p";
const dataURL = await imgToDataURL(img);
pages.push({ dataURL, w, h, orientation });
console.log(`Prepared page ${i + 1}/${imgs.length} (${w}×${h}px)`);
}
console.log("Generating PDF ...");
// Use px units so we can pass native pixel dimensions as format
const first = pages[0];
const pdf = new jsPDF({
orientation: first.orientation,
unit: "px",
format: [first.w, first.h],
compress: true,
putOnlyUsedFonts: true,
});
// Draw first page
pdf.addImage(first.dataURL, "PNG", 0, 0, first.w, first.h, undefined, "SLOW");
// Remaining pages: set size BEFORE drawing
for (let i = 1; i < pages.length; i++) {
const p = pages[i];
// Add a page with the exact size/orientation
pdf.addPage([p.w, p.h], p.orientation);
pdf.addImage(p.dataURL, "PNG", 0, 0, p.w, p.h, undefined, "SLOW");
console.log(`Placed page ${i + 1}/${pages.length}`);
}
// Title fallback logic
let title = "download.pdf";
try {
const meta = document.querySelector('meta[itemprop="name"]');
const candidate = (meta?.content || document.title || "download").trim();
title = candidate.toLowerCase().endsWith(".pdf") ? candidate : candidate + ".pdf";
} catch {}
console.log("Downloading PDF file ...");
await pdf.save(title, { returnPromise: true });
console.log("PDF downloaded!");
})();Metadata
Metadata
Assignees
Labels
No labels