kill-e-book

文泉|文泉(scau)|文泉(bit)|高教书苑|中教经典|可知|先晓书院|工程科技(校)|悦读(校)|社会科学文库|畅想之星|书递等公开免费电子书下载

目前为 2025-02-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name kill-e-book
  3. // @namespace http://tampermonkey.net/
  4. // @homepage https://github.com/systemmin/kill-doc
  5. // @version 1.2.1
  6. // @description 文泉|文泉(scau)|文泉(bit)|高教书苑|中教经典|可知|先晓书院|工程科技(校)|悦读(校)|社会科学文库|畅想之星|书递等公开免费电子书下载
  7. // @author Mr.Fang
  8. // @match https://*.wqxuetang.com/deep/read/pdf*
  9. // @match https://lib--scau-wqxuetang-com-s.vpn.scau.edu.cn/deep/read/*
  10. // @match https://nlibvpn.bit.edu.cn/*/*/deep/read/pdf?bid=*
  11. // @match https://xwfw.hut.edu.cn/*/*/deep/read/pdf?bid=*
  12. // @match https://ebook.hep.com.cn/index.html*
  13. // @match https://www.zjjd.cn/read-book*
  14. // @match https://www.keledge.com/pdfReader*
  15. // @match https://xianxiao.ssap.com.cn/readerpdf/static/pdf/web/*
  16. // @match https://ersp.lib.whu.edu.cn/*
  17. // @match https://dcd.cmpkgs.com/*
  18. // @match https://sso.zslib.cn/*
  19. // @match https://www.sklib.cn/sk_reader/reader.html*
  20. // @match https://www.cxstar.com/onlineepub*
  21. // @match https://www.elib.link/pdf/*
  22. // @match https://libresource.bit.edu.cn/https/443/cn/51zhy/yd/yitlink/ebook/reader/*
  23. // @require https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jspdf/2.4.0/jspdf.umd.min.js
  24. // @require https://unpkg.com/@zip.js/zip.js@2.7.34/dist/zip.min.js
  25. // @require https://unpkg.com/html2canvas@1.4.1/dist/html2canvas.js
  26. // @icon https://dtking.cn/favicon.ico
  27. // @run-at document-idle
  28. // @grant none
  29. // @license Apache-2.0
  30. // ==/UserScript==
  31.  
  32. (function() {
  33. 'use strict';
  34. let MF =
  35. '#MF_fixed{position:fixed;top:50%;transform:translateY(-50%);right:58px;gap:10px;flex-direction:column;z-index:2147483647;display:flex}';
  36. MF +=
  37. '.MF_box{padding:10px;cursor:pointer;border-color:rgb(0,102,255);border-radius:5px;background-color:white;color:rgb(0,102,255);}.MF_active{color: green}#MF_k_page_no,#MF_k_page_size{color: red;}';
  38. const prefix = "MF_";
  39. // canvas 禁止重写 drawImage
  40. const canvasRenderingContext2DPrototype = CanvasRenderingContext2D.prototype;
  41. const originalDrawImage = canvasRenderingContext2DPrototype.drawImage;
  42. Object.defineProperty(canvasRenderingContext2DPrototype, 'drawImage', {
  43. value: originalDrawImage,
  44. writable: false,
  45. configurable: false
  46. });
  47.  
  48. class Box {
  49. id = ""; // id
  50. label = ""; // 按钮文本
  51. title = "";
  52. fun = ""; // 执行方法
  53. constructor(id, label, fun) {
  54. this.id = id;
  55. this.label = label;
  56. this.fun = fun;
  57. }
  58.  
  59. setTitle(title) {
  60. this.title = title;
  61. return this;
  62. }
  63. }
  64.  
  65. class Utility {
  66. debug = true;
  67.  
  68. /**
  69. * 添加 css 样式
  70. * @param e 节点
  71. * @param data JSON 格式样式
  72. */
  73. style(e, data) {
  74. Object.keys(data).forEach(key => {
  75. e.style[key] = data[key]
  76. })
  77. }
  78.  
  79. attr(e, key, val) {
  80. if (!val) {
  81. return e.getAttribute(key);
  82. } else {
  83. e.setAttribute(key, val);
  84. }
  85.  
  86. }
  87.  
  88. /**
  89. * 追加样式
  90. * @param css 格式样式
  91. */
  92. appendStyle(css) {
  93. let style = this.createEl('', 'style');
  94. style.textContent = css;
  95. style.type = 'text/css';
  96. let dom = document.head || document.documentElement;
  97. dom.appendChild(style);
  98. }
  99.  
  100. /**
  101. * @description 创建 dom
  102. * @param id 必填
  103. * @param elType
  104. * @param data
  105. */
  106. createEl(id, elType, data) {
  107. const el = document.createElement(elType);
  108. el.id = id || '';
  109. if (data) {
  110. this.style(el, data);
  111. }
  112. return el;
  113. }
  114.  
  115. query(el) {
  116. return document.querySelector(el);
  117. }
  118.  
  119. queryAll(el) {
  120. return document.querySelectorAll(el);
  121. }
  122.  
  123. update(el, text) {
  124. const elNode = this.query(el);
  125. if (!elNode) {
  126. console.log('节点不存在');
  127. } else {
  128. elNode.innerHTML = text;
  129. }
  130. }
  131.  
  132. /**
  133. * 进度
  134. * @param current 当前数量 -1预览结束
  135. * @param total 总数量
  136. * @param content 内容
  137. */
  138. preview(current, total, content) {
  139. return new Promise(async (resolve, reject) => {
  140. if (current === -1) {
  141. this.update('#' + prefix + 'text', content ? content : "已完成");
  142. } else {
  143. let p = (current / total) * 100;
  144. let ps = p.toFixed(0) > 100 ? 100 : p.toFixed(0);
  145. console.log('当前进度', ps)
  146. this.update('#' + prefix + 'text', '进度' + ps + '%');
  147. await this.sleep(500);
  148. resolve();
  149. }
  150. })
  151.  
  152. }
  153.  
  154. preText(content) {
  155. this.update('#' + prefix + 'text', content);
  156. }
  157.  
  158. gui(boxs) {
  159. const box = this.createEl(prefix + "fixed", 'div');
  160. for (let x in boxs) {
  161. let item = boxs[x];
  162. if (!item.id) continue;
  163. let el = this.createEl(prefix + item.id, 'button');
  164. if (item.title) {
  165. el.title = item.title;
  166. }
  167. el.append(new Text(item.label));
  168. if (x === '0') {
  169. el.classList = prefix + 'box ' + prefix + "active";
  170. } else {
  171. el.className = prefix + "box";
  172. }
  173. if (item.fun) {
  174. el.onclick = function() {
  175. eval(item.fun);
  176. }
  177. }
  178. if (item.id === 'k_page_no') {
  179. this.attr(el, 'contenteditable', true)
  180. }
  181. if (item.id === 'k_speed') {
  182. this.attr(el, 'contenteditable', true)
  183. }
  184. if (item.id === 'k_page_size') {
  185. this.attr(el, 'contenteditable', true)
  186. }
  187. box.append(el);
  188. }
  189. document.body.append(box);
  190. }
  191.  
  192. sleep(ms) {
  193. return new Promise(resolve => setTimeout(resolve, ms));
  194. }
  195.  
  196. log(msg) {
  197. if (this.debug) {
  198. console.log(msg);
  199. }
  200. }
  201.  
  202. logt(msg) {
  203. if (this.debug) {
  204. console.table(msg);
  205. }
  206. }
  207. }
  208.  
  209. const u = new Utility();
  210. u.appendStyle(MF);
  211.  
  212.  
  213. const btns = [
  214. new Box('text', '状态 0 %'),
  215. new Box('k_speed', '2-5').setTitle('每页预览时间,默认2-5秒直接随机时间'),
  216. new Box('k_page_no', '1').setTitle('指定页码,从第几页开始'),
  217. new Box('k_page_size', '100').setTitle('指定每次下载多少页面'), ,
  218. new Box('handleStart', '开始执行', 'handleStart()'),
  219. new Box('handleClean', '结束执行', 'handleClean()'),
  220. new Box('start', '继续预览', 'autoPreview()'),
  221. new Box('stop', '停止预览', 'stopPreview()'),
  222. new Box('pdf', '下载PDF', 'download()')
  223. ]
  224.  
  225. const domain = {
  226. wqxuetang: 'wqxuetang.com',
  227. scau: "lib--scau-wqxuetang-com-s.vpn.scau.edu.cn",
  228. nlibvpn: 'nlibvpn.bit.edu.cn',
  229. xwfw: 'xwfw.hut.edu.cn',
  230. ebook: 'ebook.hep.com.cn',
  231. zjjd: 'www.zjjd.cn',
  232. keledge: 'www.keledge.com',
  233. elib: 'www.elib.link',
  234. xianxiao: 'xianxiao.ssap.com.cn',
  235. ersp: 'ersp.lib.whu.edu.cn',
  236. cmpkgs: 'dcd.cmpkgs.com',
  237. zslib: 'sso.zslib.cn',
  238. sklib: 'www.sklib.cn',
  239. cxstar: 'www.cxstar.com',
  240. libresource: 'libresource.bit.edu.cn',
  241. };
  242. const {
  243. host,
  244. href,
  245. origin
  246. } = window.location;
  247. const jsPDF = jspdf.jsPDF;
  248.  
  249. const doc = new jsPDF({
  250. orientation: 'p',
  251. unit: 'px',
  252. compress: true,
  253. });
  254. // 794 x 1123 px
  255. let pdf_w = 446,
  256. pdf_h = 631,
  257. loading = 800, // 毫秒
  258. pdf_ratio = 0.56,
  259. title = document.title,
  260. select = null,
  261. selectPages = null,
  262. observeClassName = null,
  263. dom = null,
  264. params = null,
  265. interval = null;
  266.  
  267. // ,页码,几次
  268. let k_page_size = 0, // 页面容量
  269. k_count = 0, // 计次=第几次分页
  270. k_total = 0; // 计数=每次分页预览数量
  271.  
  272. const lastIndex = href.lastIndexOf('?')
  273. if (lastIndex != -1) {
  274. params = new URLSearchParams(href.substring(lastIndex));
  275. }
  276.  
  277.  
  278. /**
  279. * @description 初始化方法
  280. * @author Mr.Fang
  281. * @time 2024年2月2日
  282. */
  283. const MF_init = () => {
  284. console.table({
  285. host,
  286. href,
  287. origin
  288. })
  289. dom = document.documentElement || document.body;
  290. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  291. select = "#pb .plg";
  292. observeClassName = "page-lmg";
  293. dom = u.query('#scroll');
  294. } else if (host.includes(domain.ebook)) {
  295. if (!params)
  296. return;
  297. if (href.includes('detail')) {
  298. setTimeout(() => {
  299. localStorage.setItem('title', u.query('.bookName').innerText)
  300. }, 1000)
  301. return;
  302. }
  303. select = ".pdf-main .pdf-page";
  304. observeClassName = "pdf-reader";
  305. dom = u.query('#viewerContainer');
  306. } else if (host.includes(domain.zjjd)) {
  307. select = "#pdf-render .item";
  308. dom = u.query('#pdf-render > div');
  309. } else if (host.includes(domain.keledge)) {
  310. select = ".pdf-main .pdfViewer";
  311. } else if (host.includes(domain.elib)) {
  312. select = "#virtual [role='listitem']";
  313. dom = u.query('#virtual')
  314. } else if (host.includes(domain.xianxiao)) {
  315. select = "#viewer .page";
  316. dom = u.query('#viewerContainer');
  317. } else if (host.includes(domain.ersp)) {
  318. // 重置链接
  319. const SkuExternalId = params.get('SkuExternalId')
  320. if (SkuExternalId) {
  321. const target = href.replaceAll('ersp.lib.whu.edu.cn/s/com/cmpkgs/dcd/G.https',
  322. 'dcd.cmpkgs.com');
  323. window.location.href = target;
  324. }
  325. return;
  326. } else if (host.includes(domain.cmpkgs)) {
  327. select = ".pdf-main .pdf-page";
  328. } else if (host.includes(domain.zslib)) {
  329. if (!href.includes('pdfReader')) {
  330. return;
  331. }
  332. select = "#canvas_box .pdf_box";
  333. dom = u.query('.pdf_reader');
  334. } else if (host.includes(domain.sklib)) {
  335. select = "#viewer .page";
  336. dom = u.query('#viewerContainer');
  337. } else if (host.includes(domain.cxstar)) {
  338. select = "#epub-area .page-div-wrapper";
  339. } else if (host.includes(domain.libresource)) {
  340. select = "#canvas_box .pdf_box";
  341. dom = u.query('.pdf_reader');
  342. }
  343. u.gui(btns);
  344. console.log('文件名称:', title);
  345. }
  346.  
  347.  
  348. const MF_loginfo = () => {
  349. console.log('k_page_size', localStorage.getItem('k_page_size'))
  350. console.log('k_page_no', localStorage.getItem('k_page_no'))
  351. console.log('k_speed', localStorage.getItem('k_speed'))
  352. console.log('k_count', localStorage.getItem('k_count'))
  353. console.log('k_total', k_total)
  354. }
  355.  
  356.  
  357. // load 事件
  358. (() => {
  359. MF_init()
  360. const k_start = localStorage.getItem('k_start');
  361. k_count = Number(localStorage.getItem('k_count')) || 0;
  362. k_page_size = Number(localStorage.getItem('k_page_size')) || 0;
  363. if (k_start) {
  364. setTimeout(() => {
  365. autoPreview();
  366. }, 2000)
  367. }
  368. MF_loginfo()
  369. })()
  370.  
  371. /**
  372. * @description 随机数方法
  373. * @param {Object} speed
  374. */
  375. function randomMillisecon(speed) {
  376. if (!speed) {
  377. return loading
  378. }
  379.  
  380. // 1、两个参数 正则表达式 匹配 开始时间-结束时间 支持浮点数
  381. const pattern = /^\d+(\.\d+)?-\d+(\.\d+)?$/;
  382. if (pattern.test(speed)) {
  383. const speeds = speed.split("-");
  384. const startTime = parseFloat(speeds[0])
  385. const endTime = parseFloat(speeds[1])
  386. // 计算时间范围的总秒数
  387. const timeRange = endTime - startTime;
  388. const randomSeconds = Math.floor(Math.random() * timeRange);
  389. const randomMilliseconds = startTime * 1000 + randomSeconds * 1000;
  390. return randomMilliseconds;
  391. } else if (/^\d+(\.\d+)?$/.test(speed)) { // 2、一个参数
  392. return parseFloat(speed) * 1000;
  393. }
  394. return loading; // 默认参数
  395. }
  396.  
  397.  
  398. /**
  399. * @description 前置方法
  400. * @author Mr.Fang
  401. * @time 2024年2月2日
  402. */
  403. const before = () => {
  404. console.log('before=============>')
  405. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  406. if (u.query('.reload_image')) {
  407. console.log('重新加载')
  408. u.query('.reload_image').click();
  409. }
  410. } else if (host.includes(domain.elib)) {
  411. title = document.title
  412. }
  413. }
  414.  
  415. /**
  416. * @description 后置方法
  417. * @author Mr.Fang
  418. * @time 2024年2月2日
  419. */
  420. const after = () => {
  421. console.log('after=============>')
  422. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  423. let nodeTitle = u.query('.read-header-title');
  424. if (!nodeTitle) {
  425. nodeTitle = u.query('.read-header-name');
  426. }
  427. if (nodeTitle) {
  428. title = nodeTitle.innerText;
  429. }
  430. } else if (host.includes(domain.ebook)) {
  431. let t = localStorage.getItem('title');
  432. if (t) {
  433. title = t;
  434. }
  435. } else if (host.includes(domain.zjjd)) {
  436. title = u.query('.title').innerText;
  437. } else if (host.includes(domain.libresource)) {
  438. title = document.title;
  439. }
  440. }
  441.  
  442.  
  443. /**
  444. * @description 开始执行
  445. */
  446. const handleStart = () => {
  447. console.log('handleStart=============>')
  448. // 重新设置页码参数
  449. const k_page_no = Number(u.query('#MF_k_page_no').innerText) - 1;
  450. if (k_page_no > 0) {
  451. localStorage.setItem('k_page_no', k_page_no)
  452. } else {
  453. localStorage.setItem('k_page_no', 0)
  454. }
  455.  
  456. // 重新设置页码参数
  457. const k_speed = u.query('#MF_k_speed').innerText;
  458. if (k_speed) {
  459. localStorage.setItem('k_speed', k_speed)
  460. } else {
  461. localStorage.setItem('k_speed', "2-5")
  462. }
  463.  
  464. // 设置页面容量
  465. k_page_size = localStorage.getItem('k_page_size');
  466. const size = Number(u.query('#MF_k_page_size').innerText);
  467. if (size > 0) {
  468. k_page_size = size
  469. }
  470. localStorage.setItem('k_page_size', k_page_size)
  471. u.update('#MF_k_page_size', k_page_size)
  472.  
  473. // 自动预览
  474. autoPreview();
  475. }
  476.  
  477. /**
  478. * @description 清空缓存数据
  479. */
  480. const handleClean = () => {
  481. console.log('handleClean=============>')
  482. stopPreview();
  483. k_total = 0;
  484. k_count = 0;
  485. localStorage.removeItem('k_page_size')
  486. localStorage.removeItem('k_page_no')
  487. localStorage.removeItem('k_speed')
  488. localStorage.removeItem('k_count')
  489. localStorage.removeItem('k_total')
  490. localStorage.removeItem('k_start')
  491. u.preview(-1, null, "已终止");
  492. }
  493.  
  494. /**
  495. * @description 开始方法,自动预览
  496. * @author Mr.Fang
  497. * @time 2024年2月2日
  498. */
  499. const autoPreview = async () => {
  500. // 开始执行标识
  501. localStorage.setItem('k_start', '1');
  502. // 初始化页码
  503. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  504.  
  505. }
  506. // 自动翻页
  507. await autoPager()
  508. }
  509.  
  510. /**
  511. * @description 结束方法,停止预览
  512. * @author Mr.Fang
  513. * @time 2024年2月2日
  514. */
  515. const stopPreview = async () => {
  516. console.log('stopPreview=============>')
  517. if (interval) {
  518. clearInterval(interval);
  519. interval = null;
  520. }
  521. localStorage.removeItem('k_start')
  522. }
  523.  
  524. /**
  525. * 判断 dom 是否在可视范围内
  526. */
  527. const isVisible = (el) => {
  528. const rect = el.getBoundingClientRect();
  529. return (
  530. rect.top >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
  531. );
  532. }
  533. // wq 保存图片
  534. const saveImagePDF = async (els, i) => {
  535. localStorage.setItem('k_page_no', i + 1);
  536. let canvas;
  537. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  538. canvas = await MF_ImageJoinToBlob(els);
  539. } else if (host.includes(domain.ebook)) {
  540. canvas = await MF_ImageToBase64(els.src);
  541. } else if (host.includes(domain.zjjd) || host.includes(domain.elib)) {
  542. canvas = await MF_ImageToCanvas(els);
  543. } else if (host.includes(domain.keledge)) {
  544. canvas = els;
  545. } else if (host.includes(domain.xianxiao)) {
  546. canvas = els;
  547. } else if (host.includes(domain.cmpkgs) || host.includes(domain.zslib) || host.includes(domain
  548. .sklib) || host.includes(domain.cxstar)) {
  549. canvas = els
  550. } else if (host.includes(domain.libresource)) {
  551. canvas = els
  552. }
  553. doc.addPage();
  554. doc.addImage(canvas, 'JPEG', 0, 0, pdf_w, pdf_h, i, 'FAST')
  555. if (doc.internal.pages[1].length === 2) {
  556. doc.deletePage(1); // 删除空白页
  557. }
  558. k_total++;
  559. // 更新dom
  560. u.update('#MF_k_page_size', k_page_size)
  561. u.update('#MF_k_page_no', i + 1)
  562.  
  563. }
  564.  
  565. /**
  566. * @description 自动翻页
  567. */
  568. const autoPager = async () => {
  569. if (!localStorage.getItem("k_start")) {
  570. u.preview(-1, null, "已停止");
  571. return;
  572. }
  573. before()
  574.  
  575. /**
  576. * @description 图片是否加载完成
  577. * @param {HTMLImageElement} img 图片节点
  578. */
  579. const imageComplete = (img) => {
  580. return img.complete && img.naturalWidth > 0 && img.naturalHeight > 0;
  581. }
  582.  
  583. /**
  584. * @description 所有字加载完成
  585. * @param {HTMLElement} nodes 孩子节点
  586. */
  587. const nodeComplete = (nodes) => {
  588. if (!nodes.length) return false;
  589. for (let i = 0; i < nodes.length; i++) {
  590. if (!imageComplete(nodes[i])) return false;
  591. }
  592. return true;
  593. }
  594.  
  595. //======================== 前置条件判断
  596. // 当前页码
  597. const nodes = u.queryAll(select);
  598. let length = nodes.length;
  599. const k_page_no = Number(localStorage.getItem('k_page_no')) || 0;
  600.  
  601. // 多增加一页码,防止缺页
  602. if (k_total % k_page_size === 0 && k_total != 0) { // 满足分页条件
  603. download().then(() => {
  604. localStorage.setItem('k_count', k_count + 1);
  605. setTimeout(() => {
  606. window.location.reload()
  607. }, 2000)
  608. });
  609. return;
  610. }
  611. let conditions = false;
  612. let currentNode = undefined;
  613. try {
  614. let node = nodes[k_page_no];
  615. if (host.includes(domain.wqxuetang) || host.includes(domain.scau) || host.includes(domain.nlibvpn) || host.includes(domain.xwfw)) {
  616. conditions = nodeComplete(node.children);
  617. currentNode = node;
  618. } else if (host.includes(domain.ebook)) {
  619. const img = node.querySelector('img')
  620. conditions = isVisible(node) && img;
  621. currentNode = img;
  622. } else if (host.includes(domain.zjjd)) {
  623. const img = node.querySelector('img')
  624. conditions = isVisible(node) && img && imageComplete(img)
  625. currentNode = img;
  626. } else if (host.includes(domain.elib)) {
  627. // pdf_page_5
  628. length = Number(document.querySelector('.pdf-top-page').lastElementChild.textContent);
  629. node = u.query('#pdf_page_' + k_page_no)
  630. // 等待 2 秒,让页面进行刷新
  631. if (!node) {
  632. await new Promise(resolve => {
  633. setTimeout(() => {
  634. node = u.query('#pdf_page_' + k_page_no);
  635. console.log('等待')
  636. resolve()
  637. }, 2000)
  638. })
  639. }
  640. const img = node.querySelector('img')
  641. conditions = img && imageComplete(img)
  642. currentNode = img;
  643. } else if (host.includes(domain.keledge)) {
  644. const canvas = node.querySelector('canvas')
  645. if (node.style.length && canvas) {
  646. conditions = true;
  647. } else {
  648. conditions = false;
  649. }
  650. currentNode = canvas;
  651. } else if (host.includes(domain.xianxiao)) {
  652. const canvas = node.querySelector('canvas')
  653. conditions = node.getAttribute("data-loaded") === "true" && canvas
  654. currentNode = canvas;
  655. } else if (host.includes(domain.cmpkgs) || host.includes(domain.zslib) || host.includes(domain
  656. .cxstar)) {
  657. const canvas = node.querySelector('canvas')
  658. conditions = isVisible(node) && canvas
  659. currentNode = canvas;
  660. } else if (host.includes(domain.sklib)) {
  661. const canvas = node.querySelector('canvas')
  662. const dataLoaded = u.attr(node, 'data-loaded')
  663. if (dataLoaded && canvas) {
  664. conditions = true
  665. currentNode = canvas;
  666. }
  667.  
  668. } else if (host.includes(domain.libresource)) {
  669. const canvas = node.querySelector('canvas')
  670. const dataLoaded = u.attr(node, 'style')
  671. if (dataLoaded && canvas) {
  672. conditions = true
  673. currentNode = canvas;
  674. }
  675. }
  676. if (conditions && currentNode) {
  677. // 保存
  678. await saveImagePDF(currentNode, k_page_no)
  679. // 滚动到下一个范围
  680. if (k_page_no !== length - 1) {
  681. if (host.includes(domain.elib)) {
  682. const idStr = `#pdf_page_${Number(k_page_no) + 1}`;
  683. const scrollNode = u.query(idStr)
  684. scrollNode.scrollIntoView({
  685. behavior: "smooth"
  686. });
  687. } else {
  688. nodes[k_page_no + 1].scrollIntoView({
  689. behavior: "smooth"
  690. });
  691. }
  692. }
  693.  
  694. } else {
  695. if (host.includes(domain.elib)) {
  696. node.scrollIntoView({
  697. behavior: "smooth"
  698. });
  699. } else {
  700. nodes[k_page_no].scrollIntoView({
  701. behavior: "smooth"
  702. });
  703. }
  704. }
  705. u.preview(k_page_no, length);
  706. } catch (e) {
  707. console.error(e);
  708. u.preview(-1);
  709. download().then(() => {
  710. handleClean();
  711. })
  712. return;
  713. }
  714. MF_loginfo()
  715.  
  716. if (k_page_no !== length) { // 继续执行
  717. let tt = randomMillisecon(localStorage.getItem("k_speed"));
  718. console.log(tt);
  719. setTimeout(async () => {
  720. await autoPager()
  721. console.log(tt, 'ms 后执行');
  722. }, tt)
  723. }
  724. }
  725.  
  726.  
  727. /**
  728. * @description 下载 PDF
  729. * @author Mr.Fang
  730. * @time 2024年2月2日
  731. */
  732. const download = () => {
  733. after()
  734.  
  735. // 下载 PDF 文件
  736. return doc.save(`${title}_${k_count}.pdf`, {
  737. returnPromise: true
  738. });
  739. }
  740.  
  741. /**
  742. * @description 图片拼接转 blob
  743. * @author Mr.Fang
  744. * @time 2024年6月5日
  745. * @param el 节点对象
  746. * @returns {Promise<blob>}
  747. */
  748. const MF_ImageJoinToBlob = (el) => {
  749. return new Promise((resolve, reject) => {
  750. const children = el.children;
  751. const {
  752. naturalWidth,
  753. naturalHeight
  754. } = children[0];
  755. // 1、创建画布
  756. let canvas = u.createEl('', 'canvas');
  757. canvas.width = naturalWidth * 6;
  758. canvas.height = naturalHeight;
  759. const ctx = canvas.getContext('2d');
  760. // 2、获取所有图片节点
  761. const listData = []
  762. for (var i = 0; i < children.length; i++) {
  763. const img = children[i];
  764. const left = img.style.left.replace('px', '')
  765. listData.push({
  766. index: i,
  767. left: Number(left)
  768. })
  769. }
  770. listData.sort((a, b) => a.left - b.left);
  771. // 3、遍历绘制画布
  772. for (var i = 0; i < listData.length; i++) {
  773. const img = children[listData[i].index];
  774. ctx.drawImage(img, i * naturalWidth, 0, naturalWidth, naturalHeight);
  775. }
  776. resolve(canvas)
  777. })
  778. }
  779.  
  780. const MF_NodeToCanvas = (node) => {
  781. return new Promise((resolve) => {
  782. html2canvas(node, {
  783. useCORS: true,
  784. logging: true,
  785. }).then(function(canvas) {
  786. resolve(canvas);
  787. });
  788. })
  789. }
  790. const MF_ImageToCanvas = (image) => {
  791. return new Promise((resolve, reject) => {
  792. const canvas = u.createEl('', 'canvas');
  793. const {
  794. naturalWidth: width,
  795. naturalHeight: height
  796. } = image;
  797. canvas.width = width;
  798. canvas.height = height;
  799. let ctx = canvas.getContext('2d');
  800. ctx.fillStyle = '#FFFFFF';
  801. ctx.fillRect(0, 0, width, height);
  802. ctx.drawImage(image, 0, 0, width, height);
  803. resolve(canvas);
  804. })
  805. }
  806. /**
  807. * @description 加载图片
  808. * @author Mr.Fang
  809. * @time 2024年1月20日18:05:49
  810. * @param src 图片地址
  811. * @returns {Promise<unknown>}
  812. */
  813. const MF_ImageToBase64 = (src) => {
  814. return new Promise((resolve, reject) => {
  815. const image = new Image();
  816. image.onload = function() {
  817. try {
  818. const canvas = u.createEl('', 'canvas');
  819. const {
  820. naturalWidth: width,
  821. naturalHeight: height
  822. } = image;
  823. canvas.width = width;
  824. canvas.height = height;
  825. let ctx = canvas.getContext('2d');
  826. ctx.fillStyle = '#FFFFFF';
  827. ctx.fillRect(0, 0, width, height);
  828. ctx.drawImage(image, 0, 0, width, height);
  829. resolve(canvas);
  830. } catch (e) {
  831. console.error(e);
  832. reject(e);
  833. }
  834. }
  835. image.onerror = reject;
  836. image.src = src;
  837. })
  838. }
  839.  
  840. /**
  841. * @description 将 blob 对象转 uint8Array
  842. * @author Mr.Fang
  843. * @time 2024年5月27日
  844. * @param {Object} blob 图片对象
  845. * @returns {Promise<Uint8Array>}
  846. */
  847. const MF_BlobToUint8Array = (blob) => {
  848. return new Promise((resolve, reject) => {
  849. const fileReader = new FileReader();
  850. fileReader.onload = function() {
  851. resolve(new Uint8Array(this.result));
  852. };
  853. fileReader.onerror = function(error) {
  854. reject(error);
  855. };
  856. fileReader.readAsArrayBuffer(blob);
  857. });
  858. }
  859.  
  860. /**
  861. * @description 画布输出 blob 对象
  862. * @author Mr.Fang
  863. * @time 2024年1月20日18:05:49
  864. * @param src 图片地址
  865. * @returns {Promise<Object>}
  866. */
  867. const MF_CanvasToBase64 = (canvas) => {
  868. return new Promise((resolve, reject) => {
  869. const {
  870. width,
  871. height
  872. } = canvas;
  873. canvas.toBlob(
  874. (blob) => {
  875. resolve({
  876. blob,
  877. width,
  878. height
  879. });
  880. },
  881. "image/png",
  882. 1,
  883. );
  884. })
  885. }
  886. })();