Skip to content

Instantly share code, notes, and snippets.

@dpaluy
Last active February 12, 2026 15:41
Show Gist options
  • Select an option

  • Save dpaluy/74258794f7930401cc27262e0ea794dd to your computer and use it in GitHub Desktop.

Select an option

Save dpaluy/74258794f7930401cc27262e0ea794dd to your computer and use it in GitHub Desktop.
Download view only protected PDF from Google Drive

Step by step guide to downloading protected PDF from Google Drive

  1. Open the document in Google Docs
  2. Scroll to the bottom of the document, so all the pages are present
  3. Open Developer Tools on separate window and choose the Console tab
  4. Paste the code
  5. Have fun!
let jspdf = document.createElement("script");
jspdf.onload = function () {
let pdf = new jsPDF();
let elements = document.getElementsByTagName("img");
for (let i in elements) {
let img = elements[i];
console.log("add img ", img);
if (!/^blob:/.test(img.src)) {
console.log("invalid src");
continue;
}
let can = document.createElement('canvas');
let con = can.getContext("2d");
can.width = img.width;
can.height = img.height;
con.drawImage(img, 0, 0);
let imgData = can.toDataURL("image/jpeg", 1.0);
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.addPage();
}
pdf.save("download.pdf");
};
jspdf.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js';
document.body.appendChild(jspdf);
@Hanito666
Copy link

let trustedURL;
if (window.trustedTypes && trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy('myPolicy', {
createScriptURL: (input) => {
return input;
}
});
trustedURL = policy.createScriptURL('https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js');
} else {
trustedURL = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js';
}

// Load the jsPDF library using the trusted URL.
let jspdf = document.createElement("script");
jspdf.onload = function () {
// Generate a PDF from images with "blob:" sources.
let pdf = new jsPDF();
let elements = document.getElementsByTagName("img");
for (let i = 0; i < elements.length; i++) {
let img = elements[i];
if (!/^blob:/.test(img.src)) {
continue;
}
let canvasElement = document.createElement('canvas');
let con = canvasElement.getContext("2d");
canvasElement.width = img.width;
canvasElement.height = img.height;
con.drawImage(img, 0, 0, img.width, img.height);
let imgData = canvasElement.toDataURL("image/jpeg", 1.0);
pdf.addImage(imgData, 'JPEG', 0, 0);
if (i !== elements.length - 1) {
pdf.addPage();
}
}

// Download the generated PDF.
pdf.save("download.pdf");

};
jspdf.src = trustedURL;
document.body.appendChild(jspdf);

This actually works!

@sardarmohsinsaghir
Copy link

Its missing pages why?

@demon19851027
Copy link

Скрипт прикольный, но если в PDF присутствуют ссылки, то они не доступны!

@Jayanth-GitHub
Copy link

Good

@wefluidmedia-prog
Copy link

@Girtti
Copy link

Girtti commented Dec 19, 2025

@positiveque
Copy link

positiveque commented Feb 11, 2026

Script Overview
This script dynamically loads the jsPDF library and generates a PDF document from all elements on the page that use blob: URLs (typically rendered slide images in a viewer).

For each image:

  • It waits until the image is fully loaded.
  • Draws it onto a temporary .
  • Converts the canvas to an image (JPEG/PNG).
  • Inserts the image into a PDF.
  • Adds a new page for each slide.
  • Automatically downloads the generated download.pdf.

Improvements Made

  1. Landscape Orientation Support
    The PDF is now created in landscape mode when the slide width is greater than its height.

  2. Dynamic Page Size Matching
    Each PDF page is generated using the exact dimensions of the slide image, preventing cropping, distortion, or incorrect scaling.

  3. Correct Page Handling
    Page creation is based on the filtered list of relevant images (not all tags in the DOM), ensuring accurate page breaks.

  4. Image Load Safety
    The script now waits for each image to fully load before processing, preventing blank or incomplete pages.

  5. Updated jsPDF Version
    The script uses a modern jsPDF version (2.5.1) instead of the outdated 1.3.2 release.

  6. Optional A4 Landscape Scaling Variant
    An alternative version supports fixed A4 landscape format with proportional scaling to fit slides within standard paper dimensions.

Code

(async () => {
let trustedURL;
if (window.trustedTypes && trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy('myPolicy', { createScriptURL: (input) => input });
trustedURL = policy.createScriptURL('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js');
} else {
trustedURL = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js';
}
const loadScript = (src) =>
new Promise((resolve, reject) => {
const s = document.createElement("script");
s.onload = resolve;
s.onerror = reject;
s.src = src;
document.body.appendChild(s);
});
await loadScript(trustedURL);
const { jsPDF } = window.jspdf;
const imgs = Array.from(document.getElementsByTagName("img"))
.filter(img => /^blob:/.test(img.src));
if (!imgs.length) return;
const pdf = new jsPDF({ orientation: "landscape", unit: "pt", format: "a4", compress: true });
const pageW = pdf.internal.pageSize.getWidth();
const pageH = pdf.internal.pageSize.getHeight();
let pageIndex = 0;
for (const img of imgs) {
if (!img.complete || img.naturalWidth === 0) {
await new Promise((r) => img.addEventListener("load", r, { once: true }));
}
const w = img.naturalWidth || img.width;
const h = img.naturalHeight || img.height;
const canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, w, h);
const imgData = canvas.toDataURL("image/jpeg", 0.92);
if (pageIndex > 0) pdf.addPage();
// Вписываем в A4 landscape без искажений (с полями, если нужно)
const ratio = Math.min(pageW / w, pageH / h);
const drawW = w * ratio;
const drawH = h * ratio;
const x = (pageW - drawW) / 2;
const y = (pageH - drawH) / 2;
pdf.addImage(imgData, "JPEG", x, y, drawW, drawH);
pageIndex++;
}
pdf.save("download.pdf");
})();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment