kill-e-book

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

当前为 2024-10-08 提交的版本,查看 最新版本

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