Skip to content

Issue with different sized pages #9

@ccorcos

Description

@ccorcos

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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions