Skip to content

Instantly share code, notes, and snippets.

@wakaba
Last active February 21, 2024 05:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wakaba/f91282ad9f6a4538b46e1b8a1493addb to your computer and use it in GitHub Desktop.
Save wakaba/f91282ad9f6a4538b46e1b8a1493addb to your computer and use it in GitHub Desktop.
async function _capture (e) {
const stream = await navigator.mediaDevices.getDisplayMedia ({
video: {
cursor: "never",
},
audio: false,
displaySurface: "browser",
preferCurrentTab: true,
selfBrowserSurface: "include",
});
const v = document.createElement ('video');
v.srcObject = stream;
v.autoplay = true;
await new Promise (_ => v.onloadedmetadata = _);
await new Promise (ok => setTimeout (ok, 200));
let snapshot = (e) => {
let canvas = document.createElement ('canvas');
canvas.width = e.videoWidth;
canvas.height = e.videoHeight;
let ctx = canvas.getContext ('2d');
ctx.drawImage (e, 0, 0);
return canvas;
};
let cols = [];
let h = e.scrollHeight;
let w = e.scrollWidth;
let d = e.clientHeight;
let c = e.clientWidth;
let lastWidth;
for (let u = 0; u < w; ) {
e.scrollLeft = u;
let canvases = [];
let lastHeight;
for (let t = 0; t < h; ) {
e.scrollTop = t;
await new Promise (ok => setTimeout (ok, 200));
canvases.push (snapshot (v));
lastHeight = h - t;
t += d;
}
{
let canvas = canvases.at (-1);
let ratio = canvas.height / d;
let xHeight = lastHeight * ratio;
let canvas2 = document.createElement ('canvas');
canvas2.width = canvas.width;
canvas2.height = xHeight;
let ctx2 = canvas2.getContext ('2d');
ctx2.drawImage
(canvas, 0, canvas.height - xHeight, canvas.width, xHeight,
0, 0, canvas.width, xHeight);
canvases.pop ();
canvases.push (canvas2);
}
cols.push (canvases);
lastWidth = w - u;
u += c;
} // u
if (cols.length > 1) {
let canvas = cols.at (-1)[0];
let ratio = canvas.width / c;
let xWidth = lastWidth * ratio;
let canvases = [];
cols.at (-1).forEach (canvas => {
let canvas2 = document.createElement ('canvas');
canvas2.width = xWidth;
canvas2.height = canvas.height;
let ctx2 = canvas2.getContext ('2d');
ctx2.drawImage
(canvas, canvas.width - xWidth, 0, xWidth, canvas.height,
0, 0, xWidth, canvas.height);
canvases.push (canvas2);
});
cols.pop ();
cols.push (canvases);
}
stream.getTracks().forEach (track => track.stop());
let allWidth = 0;
let allHeight = 0;
cols.forEach (canvases => {
allWidth += canvases[0].width;
allHeight = 0;
canvases.forEach (canvas => {
allHeight += canvas.height;
});
});
{
let canvas = document.createElement ('canvas');
canvas.width = allWidth;
canvas.height = allHeight;
let ctx = canvas.getContext ('2d');
let x = 0;
cols.forEach (canvases => {
let y = 0;
canvases.forEach (canvas => {
ctx.drawImage (canvas, 0, 0, canvas.width, canvas.height,
x, y, canvas.width, canvas.height);
y += canvas.height;
});
x += canvases[0].width;
});
return canvas;
}
} // _capture
function captureByURL (url) {
let createIframe = url => new Promise ((ok, ng) => {
let iframe = document.createElement ('iframe');
iframe.src = url;
iframe.onload = () => ok (iframe);
iframe.onerror = ng;
document.body.appendChild (iframe);
});
let initIframe = async iframe => {
iframe.style.position = "fixed";
iframe.style.zIndex = 100000;
iframe.style.top = 0;
iframe.style.left = 0;
iframe.style.width = "100vw";
iframe.style.height = "100vh";
iframe.style.border = "none";
iframe.style.overflow = "hidden";
iframe.style.background = "white";
iframe.contentDocument.documentElement.style.overflow = "hidden";
document.documentElement.style.overflow = "hidden";
return iframe;
};
let discardIframe = iframe => {
document.documentElement.style.overflow = "auto";
//iframe.style.position = "static";
iframe.remove ();
return iframe;
};
return createIframe (url).then (initIframe).then (async iframe => {
let canvas = await _capture (iframe.contentDocument.documentElement);
console.log (canvas);
let img = document.createElement ('img');
img.src = canvas.toDataURL ();
img.style.border = "green solid 1px";
document.body.appendChild (img);
img.scrollIntoView ();
return iframe;
}).then (discardIframe);
} // captureByURL
window.captureByURL = captureByURL;
/*
Usage:
await fetch("https://gist.githubusercontent.com/wakaba/f91282ad9f6a4538b46e1b8a1493addb/raw/ss.js").then(res=>res.text()).then(text=>eval(text));
captureByURL (new URL ("path/to/page.html", location));
*/
/*
Copyright 2024 Wakaba <wakaba@suikawiki.org>.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You does not have received a copy of the GNU Affero General Public
License along with this program, see <https://www.gnu.org/licenses/>.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment