提问人:ExceptionFinder 提问时间:11/6/2023 最后编辑:stmExceptionFinder 更新时间:11/15/2023 访问量:62
如何使用屏幕外文档在自定义 chrome 扩展程序中下载 PDF
How to download a PDF in a custom chrome extension using offscreen document
问:
由于我生成的 PDF 的大小,base64 转换是不可能的,我必须使用屏幕外功能。
基于这个答案 -> https://stackoverflow.com/a/75539867/8016254
我尝试下载一个 PDF 文件,该文件将在我的自定义 chrome 扩展程序中重新定义。
background.js
import './pdf-lib.min.js';
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
(async () => {
if (message.pdfUrls && message.pdfUrls.length > 0) {
// Debug PDF
const urls = ["https://www.africau.edu/images/default/sample.pdf"];
await mergeAllPDFs(urls, "Test");
}
})();
return true;
});
async function mergeAllPDFs(urls, filename) {
const numDocs = urls.length;
const pdfDoc = await PDFLib.PDFDocument.create();
for (let i = 0; i < numDocs; i++) {
console.log(`Fetching ${urls[i]}`)
const donorPdf = await fetch(urls[i]);
const donorPdfBytes = await donorPdf.arrayBuffer();
const donorPdfDoc = await PDFLib.PDFDocument.load(donorPdfBytes);
const copiedPages = await pdfDoc.copyPages(donorPdfDoc, donorPdfDoc.getPageIndices());
copiedPages.forEach((page) => pdfDoc.addPage(page));
}
const pdfDocBytes = await pdfDoc.save();
const waiting = await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['BLOBS'],
justification: 'reason for needing the document',
});
chrome.runtime.sendMessage({
data: pdfDocBytes
}, (response) => {
console.log(response);
const url = response.url;
console.log(url);
chrome.downloads.download({
url: url,
filename: filename + ".pdf"
});
});
}
offscreen.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const blob = new Blob([message.data], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
sendResponse({ url: url });
return true;
});
生成的 PDF 似乎已损坏,并且比预期的要小得多。有什么想法吗?
答:
1赞
wOxxOm
11/6/2023
#1
问题:chrome.runtime.sendMessage 无法在 Chrome 中发送二进制数据。
解决方案:使用标准 Web 消息传递。
背景
await chrome.offscreen.createDocument({url: 'offscreen.html', /*....*/});
const clientUrl = chrome.runtime.getURL('offscreen.html');
const client = (await clients.matchAll({includeUncontrolled: true}))
.find(c => c.url === clientUrl);
const mc = new MessageChannel();
client.postMessage(blob, [mc.port2]);
const {data: blobUrl} = await new Promise(cb => (mc.port1.onmessage = cb));
chrome.downloads.download({
url: blobUrl,
filename: filename + '.pdf',
});
offscreen.js
navigator.serviceWorker.onmessage = e => {
e.ports[0].postMessage(URL.createObjectURL(e.data));
setTimeout(close);
};
评论
0赞
ExceptionFinder
11/7/2023
谢谢你,我没有想到这一点。我尝试使用它,但不会发送任何消息,我错过了什么吗?
0赞
ExceptionFinder
11/10/2023
好吧,我几乎尝试了所有方法。甚至像这里这样一种不同的方法: 链接 感觉要么消息没有发送,要么接收部分不起作用。我认为没有办法调试这个。屏幕外的文档是否允许您拥有“窗口”?
0赞
ExceptionFinder
11/11/2023
是的,我知道,我添加了多个console.logs。我可以看到代码卡在这部分: 并且在离线文档中没有收到任何消息,因此发送部分不工作或接收方不工作。谢谢你的帮助。这个想法很好,但我仍然觉得扩展对 MessageChannels 有一些限制。我的清单中是否缺少某些内容?我需要添加一些特权吗?const {data: blobUrl} = await new Promise(cb => (mc.port1.onmessage = cb));
1赞
wOxxOm
11/11/2023
对不起,我没有测试代码。我现在纠正了这个错误。
1赞
wOxxOm
11/12/2023
我使用 MDN。对 includeUncontrol 的需求似乎是由于 Chrome 中的一个错误,因为它没有列出屏幕外的文档。
评论