// ==UserScript== // @name 微信公众号 PDF 导出脚本 // @namespace mem.ac/weixin-print-to-pdf // @version 1.1.2 // @description 方便地导出公众号文章中以图片形式上传的试卷,让您一键开卷! // @author memset0 // @license AGPL-v3.0 // @match https://mp.weixin.qq.com/s* // @updateUrl https://cdn.jsdelivr.net/gh/memset0/weixin-print-to-pdf/index.js // @downloadUrl https://cdn.jsdelivr.net/gh/memset0/weixin-print-to-pdf/index.js // @run-at document-start // @downloadURL none // ==/UserScript== const scrollSpeed = 50; function log(...args) { console.log('[@memset0/weixin-print-to-pdf]', ...args); } function transferHtmlToPdf(htmlSource) { // const document = unsafeWindow.document; const blob = new Blob([htmlSource], { type: 'text/html;charset=utf-8' }); const blobUrl = URL.createObjectURL(blob); log(blobUrl); const $iframe = document.createElement('iframe'); $iframe.style.display = 'none'; $iframe.src = blobUrl; document.body.appendChild($iframe); $iframe.onload = () => { setTimeout(() => { $iframe.focus(); $iframe.contentWindow.print(); }, 1); }; } function scrollTo(type) { if (type !== 'top' && type !== 'bottom') { throw new Error('type error!'); } const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; let promiseResolve = null; let lastTimestamp = null; let scrollRecords = []; function scrollAnimated(timestamp) { // log('scroll animated', timestamp); const currentScroll = document.documentElement.scrollTop || document.body.scrollTop; scrollRecords.push(currentScroll); if (scrollRecords.length > 5) { scrollRecords.shift(); let finishedFlag = true; for (let i = 1; i < scrollRecords.length; i++) { // log('!!!', i, scrollRecords[i], scrollRecords[i - 1], scrollRecords[i] !== scrollRecords[i - 1]); if (scrollRecords[i] !== scrollRecords[i - 1]) { finishedFlag = false; break; } } if (finishedFlag) { // log('finish', scrollRecords, finishedFlag); return promiseResolve(type); } } if (lastTimestamp === null) { lastTimestamp = timestamp; } else { const deltaTimestamp = timestamp - lastTimestamp; lastTimestamp = timestamp; window.scrollTo(0, currentScroll + scrollSpeed * (type === 'top' ? -deltaTimestamp : +deltaTimestamp)); log(type, currentScroll, scrollHeight, deltaTimestamp); } window.requestAnimationFrame(scrollAnimated); } return new Promise((resolve) => { promiseResolve = resolve; window.requestAnimationFrame(scrollAnimated); }); } async function printToPdf() { const width = 210; const height = 297; const margin = 0; // await scrollTo('top'); // await scrollTo('bottom'); let html = ''; // normalize browser html += '' // style of page containers html += ''; // page settings html += ''; html += '' console.log(html); for (const $image of document.getElementById('js_content').querySelectorAll('img')) { const imageSrc = $image.getAttribute('data-src'); if (!imageSrc) { continue; } html += '