-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoffscreen.js
More file actions
75 lines (69 loc) · 2.28 KB
/
Copy pathoffscreen.js
File metadata and controls
75 lines (69 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// offscreen.js - a hidden document that owns the big canvas.
// Service workers cannot make blob URLs, so the stitching happens here.
// Tiles arrive one at a time and are drawn immediately, so only one
// screenshot sits in memory at a time no matter how long the page is.
let canvas = null;
let ctx = null;
let urls = [];
function release() {
for (const url of urls) URL.revokeObjectURL(url);
urls = [];
}
function begin(msg) {
release();
canvas = new OffscreenCanvas(msg.width, msg.height);
ctx = canvas.getContext('2d', { alpha: false, willReadFrequently: false });
if (!ctx) throw new Error('The page is too large for one image. Lower the image scale and try again.');
ctx.imageSmoothingQuality = 'high';
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, msg.width, msg.height);
return { ok: true };
}
async function draw(msg) {
if (!ctx) throw new Error('No capture in progress.');
const blob = await (await fetch(msg.dataUrl)).blob();
const bitmap = await createImageBitmap(blob);
ctx.drawImage(bitmap, msg.sx, msg.sy, msg.sw, msg.sh, msg.dx, msg.dy, msg.dw, msg.dh);
bitmap.close();
return { ok: true };
}
async function finish() {
if (!canvas) throw new Error('No capture in progress.');
let blob;
try {
blob = await canvas.convertToBlob({ type: 'image/png' });
} catch (err) {
throw new Error('This page is too tall to save as a single image.');
}
if (!blob || !blob.size) throw new Error('The image came out empty. Try again.');
const url = URL.createObjectURL(blob);
urls.push(url);
const bytes = blob.size;
canvas = null;
ctx = null;
return { ok: true, url, bytes };
}
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (!msg || msg.target !== 'offscreen') return;
const run = async () => {
switch (msg.type) {
case 'pp-ping':
return { ok: true };
case 'pp-begin':
return begin(msg);
case 'pp-draw':
return draw(msg);
case 'pp-finish':
return finish();
case 'pp-release':
release();
return { ok: true };
default:
return { ok: false, error: 'Unknown request.' };
}
};
run()
.then(sendResponse)
.catch((err) => sendResponse({ ok: false, error: String(err && err.message ? err.message : err) }));
return true;
});