2021-07-09

pdf.js 前端pdf预览 渲染文本图层支持复制 保证手机端清晰度 双指缩放 alloyfinger(手势)

一、渲染pdf核心代码

首先安装 pdf.js 的 npm 版本:

npm i pdfjs-dist@2.6.347

使用:

import * as PDFJS from "pdfjs-dist"
 
其中,pdf.js 加载pdf文件依赖了 pdf.worker.js ,通过指定 pdf.worker.js 路径让 pdf.js 加载依赖:
  PDFJS.GlobalWorkerOptions.workerSrc ="https://cdn.jsdelivr.net/npm/pdfjs-dist@2.6.347/build/pdf.worker.min.js";


这里使用了一个 CDN 地址,自己选择。也可以引用安装的 npm 包里面的 pdf.worker.js :
window.pdfjsWorker = require("pdfjs-dist/build/pdf.worker.js")
 
 
有两点需要注意:
1. npm 库的使用没有使用最新版。因为最新版的使用了一些JS的新语法,比如  ?. 可选链:
let testObj = { name: '可选链', tips: '防止访问不存在的属性而报错'}console.log(testObj.names?.nickname) // undefinedconsole.log(testObj.names.nickname) // Uncaught TypeError: Cannot read property 'nickname' of undefined

这会导致某些不支持的浏览器显示空白页面。我使用最新版的 pdfjs-dist , vue 打包的demo页面,在  QQ、UC 微信内置浏览器打开都是空白的。

所以使用了 2.6.347 版本,再新的都有用新语法。

2. pdf.worker.js 依赖问题。pdf.js 不是非要用 npm 形式使用, 直接在页面使用 script 标签引用也可以,并且可以只引用 pdf.js 即可(保证 pdf.worker.js 的名字,并且和 pdf.s 同路径)。

pdf.js 源码里有做判断,有 pdf.worker.js 的地址就是使用;没有,就判断全局是否有 pdfjsWorker 对象;再没有,就通过 引用 pdf.js 的地址拼接出来  pdf.worker.js 的地址。

 

使用:

 

const canvasBoxEl = document.getElementById('canvas-box')this.boxWidth = canvasBoxEl.widththis.boxHeight = canvasBoxEl.heightconsole.log(canvasBoxEl)var url = './static/react-native.pdf'PDFJS.getDocument(url) .promise.then(pdf => { // pdf.numPages 总页数 return pdf.getPage(1) }) .then(page => { // 设置展示比例 var scale = 1.5 // 获取pdf尺寸 var viewport = page.getViewport({ scale }) console.log(viewport) // 获取需要渲染的元素 var canvas = document.createElement('canvas') var context = canvas.getContext('2d') canvas.height = viewport.height canvas.width = viewport.width canvasBoxEl.appendChild(canvas) var renderContext = {  canvasContext: context,  viewport: viewport } page.render(renderContext) })

 

 

 如果有多页,看需求渲染。在 PC 这样差不多就可以了,但是在手上打开,可能就很模糊。

 

PS:比较乱,基本功能都实现了,还需要优化。预览地址: https://feiyefeihua.gitee.io/

 

二、保证pdf清晰度

pdf.js 是 mozilla 的开源库(地址:https://mozilla.github.io/pdf.js/),并且有一个完整的web展示页面,在手机上看也清晰。就从它的源码里面去看。

其中渲染pdf有三个地方,一个是渲染的缩略图,一个是打印的样式,剩下的那个才是正文:

主要是在渲染之前做了一些计算,canvas的 标签属性 width、height 和 css属性 width、height。还可以用svg渲染的样子?

计算使用的是一些提前确认的变量和写好的工具函数,提取出来:

const CSS_UNITS = 96.0 / 72.0;// const PRINT_UNITS = 150 / 72.0;let userAgent = (typeof navigator !== "undefined" && navigator.userAgent) || "";let platform = (typeof navigator !== "undefined" && navigator.platform) || "";let maxTouchPoints = (typeof navigator !== "undefined" && navigator.maxTouchPoints) || 1;let maxCanvasPixels = 16777216;let isAndroid = /Android/.test(userAgent);let isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || (platform === "MacIntel" && maxTouchPoints > 1);(function checkCanvasSizeLimitation() { if (isIOS || isAndroid) { maxCanvasPixels = 5242880; }})();function approximateFraction(x) { if (Math.floor(x) === x) { return [x, 1]; } var xinv = 1 / x; var limit = 8; if (xinv > limit) { return [1, limit]; } else if (Math.floor(xinv) === xinv) { return [1, xinv]; } var x_ = x > 1 ? xinv : x; var a = 0, b = 1, c = 1, d = 1; while (q < limit) { var p = a + c,  q = b + d; if (q > limit) {  break; } if (x_ <= p / q) {  c = p;  d = q; } else {  a = p;  b = q; } } var result; if (x_ - a / b < c / d - x_) { result = x_ === x ? [a, b] : [b, a]; } else { result = x_ === x ? [c, d] : [d, c]; } return result;},function roundToDivide(x, div) { var r = x % div; return r === 0 ? x : Math.round(x - r + div);}

 

其中还有个根据 canvas 的 ctx 计算 pixelRatio 的:

let devicePixelRatio = window.devicePixelRatio || 1  let backingStoreRatio =  ctx.webkitBackingStorePixelRatio ||  ctx.mozBackingStorePixelRatio ||  ctx.msBackingStorePixelRatio ||  ctx.oBackingStorePixelRatio ||  ctx.backingStorePixelRatio ||  1 const pixelRatio = devicePixelRatio / backingStoreRatio

 

修改过后的完整代码:

<template> <div > <div :>  <button @click="scaleCanvas(1.5)">1.5</button>  <button @click="scaleCanvas(0.5)">0.5</button>  <button @click="scaleCanvas(1)">还原(1)</button> </div> <div v-show="!loading" :></div> <p v-show="loading">正在加载...</p> </div></template><script>import * as PDFJS from 'pdfjs-dist'// 本地// window.pdfjsWorker = require("pdfjs-dist/build/pdf.worker.js");// cdn 2.8.335 2.6.347 2.5.207PDFJS.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.6.347/build/pdf.worker.min.js'// https://github.com/mozilla/pdf.js/blob/master/examples/node/getinfo.js// Requires single file built version of PDF.js -- please run// `gulp singlefile` before running the example.// const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");const CSS_UNITS = 96.0 / 72.0// const PRINT_UNITS = 150 / 72.0;let userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''let platform = (typeof navigator !== 'undefined' && navigator.platform) || ''let maxTouchPoints = (typeof navigator !== 'undefined' && navigator.maxTouchPoints) || 1let maxCanvasPixels = 16777216// PDF之外占据的宽度 -18 padding -18减去滚动条宽度(不确定)let autoWidth = 36let isAndroid = /Android/.test(userAgent)let isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || (platform === 'MacIntel' && maxTouchPoints > 1);(function checkCanvasSizeLimitation() { if (isIOS || isAndroid) { maxCanvasPixels = 5242880 autoWidth -= 18 }})()export default { data() { return {  src: './static/react-native.pdf',  loading: true,  pdfDoc: null,  boxEl: null,  wrapEl: null,  areaWidth: 0,  btnWidth: 0,  viewWidth: 0,  viewHeight: 0,  pixelRatio: 2,  isFirstTimeRender: true,  viewport: null,  canvasEles: [],  canvasCtxs: [],  totallPage: 1,  pageScale: 1, // pdf 适应窗口产生的 scale  curCanvasCSSWh: null,  transform: null,  pageRendered: false } }, mounted() { this.init() }, methods: { async init() {  this.boxEl = document.querySelector('.pdf-touch-box')  this.wrapEl = document.getElementsByClassName('pdf-canvas-wrap')[0]  this.btnWidth = this.areaWidth = this.boxEl.clientWidth  const loadingState = await this.getPDF()  if (loadingState === 'success') this.initRenderOneByOne()  else this.boxEl.innerText = loadingState }, scaleCanvas(scale) {  if (!this.pageRendered) return  // 改变 viewport 大小  this.viewport = this.viewport.clone({  scale: this.pageScale * scale * CSS_UNITS  })  const { styleWidth, styleHeight } = this.getCanvasCSSWH()  // 先改变CSS canvas 会变模糊  this.canvasEles.forEach((canvas, index) => {  // 不修改 width height 不然会重置 canvas  canvas.style.width = styleWidth + 'px'  canvas.style.height = styleHeight + 'px'  console.log(index)  })  // 重新渲染 变清晰  this.scaleRenderAll() }, // 好像改变也不是很明显 // scaleCanvas(scale) { // // 改变 viewport 大小 // this.viewport = this.viewport.clone({ //  scale: this.pageScale * scale * CSS_UNITS, // }); // // 逐个重新渲染 // this.renderSinglePage(this.canvasEles[0], 1); // }, getPDF() {  let that = this  return new Promise(reslove => {  PDFJS.getDocument(that.src).promise.then(   function (pdfDoc_) {   that.pdfDoc = pdfDoc_   that.totallPage = pdfDoc_.numPages   that.loading = false   reslove('success')   },   function (reason) {   console.log(reason.message)   that.loading = false   reslove(reason.name)   }  )  }) }, initRenderOneByOne() {  for (let pageNum = 1; pageNum <= this.totallPage; pageNum++) {  let canvas = document.createElement('canvas')  canvas.setAttribute('id', `pdf-canvas${pageNum}`)  canvas.setAttribute('class', `pdfcanvas`)  // alpha 设定 canvas 背景总是不透明,可以加快浏览器绘制透明的内容和图片 初始化出来 canvas 为黑色背景  // 实际上 导致 重新渲染的时候 闪黑屏  // let ctx = canvas.getContext("2d", {  // alpha: false,  // });  let ctx = canvas.getContext('2d')  this.canvasCtxs.push(ctx)  this.canvasEles.push(canvas)  this.wrapEl.appendChild(canvas)  }  this.renderSinglePage(this.canvasEles[0], 1) }, renderSinglePage(canvas, pageNum) {  let ctx = this.canvasCtxs[pageNum - 1]  let that = this  this.pdfDoc.getPage(pageNum).then(function (page) {  if (that.isFirstTimeRender) that.initView(page, ctx)  if (pageNum === 1) that.getCanvasCSSWH()  canvas.width = that.curCanvasCSSWh.width  canvas.height = that.curCanvasCSSWh.height  canvas.style.width = that.curCanvasCSSWh.styleWidth + 'px'  canvas.style.height = that.curCanvasCSSWh.styleHeight + 'px'  canvas.style['border'] = '#d6d6d6 solid 1px'  canvas.style.margin = '9px 0 0 0'  let renderContext = {   canvasContext: ctx,   transform: that.transform,   viewport: that.viewport,   enableWebGL: false,   renderInteractiveForms: false  }  let renderTask = page.render(renderContext)  renderTask.promise.then(function () {   if (that.totallPage >= ++pageNum) {   that.renderSinglePage(that.canvasEles[pageNum - 1], pageNum)   } else {   that.pageRendered = true   }  })  }) }, scaleRenderAll() {  const len = this.canvasEles.length  for (let pageNum = 0; pageNum < len; pageNum++) {  let canvas = this.canvasEles[pageNum]  let ctx = this.canvasCtxs[pageNum]  let that = this  this.pdfDoc.getPage(pageNum + 1).then(function (page) {   canvas.width = that.curCanvasCSSWh.width   canvas.height = that.curCanvasCSSWh.height   let renderContext = {   canvasContext: ctx,   transform: that.transform,   viewport: that.viewport,   enableWebGL: false,   renderInteractiveForms: false   }   let renderTask = page.render(renderContext)   renderTask.promise.then(function (context) {   console.log(context)   })  })  } }, getCanvasCSSWH() {  let outputScale = {  sx: this.pixelRatio,  sy: this.pixelRatio,  scaled: this.pixelRatio !== 1  }  let pixelsInViewport = this.viewport.width * this.viewport.height  let maxScale = Math.sqrt(maxCanvasPixels / pixelsInViewport)  if (outputScale.sx > maxScale || outputScale.sy > maxScale) {  outputScale.sx = maxScale  outputScale.sy = maxScale  outputScale.scaled = true  }  let sfx = (0, this.approximateFraction)(outputScale.sx)  let sfy = (0, this.approximateFraction)(outputScale.sy)  const width = (0, this.roundToDivide)(this.viewport.width * outputScale.sx, sfx[0])  const height = (0, this.roundToDivide)(this.viewport.height * outputScale.sy, sfy[0])  const styleWidth = (0, this.roundToDivide)(this.viewport.width, sfx[1])  const styleHeight = (0, this.roundToDivide)(this.viewport.height, sfy[1])  if (this.pixelRatio !== 1) this.transform = [this.pixelRatio, 0, 0, this.pixelRatio, 0, 0]  this.viewWidth = styleWidth + 2  // 12 加上 canvas border margin 误差?2 + 9 + 1  this.viewHeight = this.totallPage * (this.viewport.height + 12) + 9  this.curCanvasCSSWh = { width, height, styleWidth, styleHeight }  return this.curCanvasCSSWh }, approximateFraction(x) {  if (Math.floor(x) === x) {  return [x, 1]  }  var xinv = 1 / x  var limit = 8  if (xinv > limit) {  return [1, limit]  } else if (Math.floor(xinv) === xinv) {  return [1, xinv]  }  var x_ = x > 1 ? xinv : x  var a = 0,  b = 1,  c = 1,  d = 1  while (q < limit) {  var p = a + c,   q = b + d  if (q > limit) {   break  }  if (x_ <= p / q) {   c = p   d = q  } else {   a = p   b = q  }  }  var result  if (x_ - a / b < c / d - x_) {  result = x_ === x ? [a, b] : [b, a]  } else {  result = x_ === x ? [c, d] : [d, c]  }  return result }, roundToDivide(x, div) {  var r = x % div  return r === 0 ? x : Math.round(x - r + div) }, initView(page, ctx) {  let devicePixelRatio = window.devicePixelRatio || 1  let backingStoreRatio =  ctx.webkitBackingStorePixelRatio ||  ctx.mozBackingStorePixelRatio ||  ctx.msBackingStorePixelRatio ||  ctx.oBackingStorePixelRatio ||  ctx.backingStorePixelRatio ||  1  this.pixelRatio = devicePixelRatio / backingStoreRatio  this.viewport = page.getViewport({  scale: CSS_UNITS  })  console.log(this.viewport)  this.pageScale = (this.areaWidth - autoWidth) / this.viewport.width  let curViewport = page.getViewport({  scale: this.pageScale * CSS_UNITS  })  this.viewport = curViewport  this.isFirstTimeRender = false }, drawBorder(canvas, ctx) {  ctx.save()  ctx.fillStyle = 'rgb(255, 255, 255)'  ctx.strokeRect(0, 0, canvas.width, canvas.height)  ctx.restore() } }}</script><style scoped>.pdf-touch-box { padding: 9px; width: calc(100% - 18px); height: calc(100% - 18px); display: flex; flex-direction: column; justify-content: center;}.scale-btn-box { position: fixed; top: 0; left: 0; height: 44px; display: flex; justify-content: space-around;}.scale-btn { width: 25%; height: 100%; display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; color: #606266; -webkit-appearance: none; text-align: center; box-sizing: border-box; outline: none; margin: 0; transition: 0.1s; font-weight: 500; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; padding: 12px 20px; font-size: 14px; border-radius: 4px;}.pdf-canvas-wrap { display: flex; flex-direction: column; align-items: center; overflow: hidden; margin-top: 44px; padding-top: 9px;}.pdf-canvas-tips { margin-top: 44px;}</style>

 

这样手机打开就也清晰了。

 

三、渲染文本图层,支持手势缩放

要渲染文本图层还需要额外的依赖:

import { TextLayerBuilder, EventBus } from "pdfjs-dist/web/pdf_viewer";
import "pdfjs-dist/web/pdf_viewer.css";
 
 只要在渲染的时候添加即可:
let renderContext = { canvasContext: ctx, transform: that.transform, viewport: that.viewport, enableWebGL: false, renderInteractiveForms: false,};let renderTask = page.render(renderContext);renderTask.promise .then(function () { if (that.totallPage >= ++pageNum) {  that.renderSinglePage(that.canvasEles[pageNum - 1], pageNum);  return page.getTextContent(); } else {  that.pageRendered = true; } }) .then((textContent) => { const textLayerDiv = document.createElement("div"); textLayerDiv.setAttribute("class", "textLayer"); textLayerDiv.setAttribute("style", "top: 12px"); canvas.parentElement.appendChild(textLayerDiv); var textLayer = new TextLayerBuilder({  eventBus: new EventBus(),  textLayerDiv: textLayerDiv,  pageIndex: pageNum,  viewport: that.viewport, }); textLayer.setTextContent(textContent); textLayer.render(); });

 



 支持手势缩放使用  alloyfinger.js :

import AlloyFinger from "alloyfinger";//包装一下 不然 eslint 报警告class FingerTouch { constructor(element, options) { Object.assign(this, AlloyFinger.prototype); AlloyFinger.call(this, element, options); }}

alloyfinger 很小,点进去没多少代码,可以学习学习。

 

 

 使用:

this.alloyFinger = new FingerTouch(this.wrapEl, {})this.alloyFinger.on('pinch', e => { let zoom = e.zoom let curScale = this.lastStyleScale * zoom if (curScale <= this.pageScale / 2 || curScale >= 5) return this.scaleEvent(curScale)})this.alloyFinger.on('pressMove', e => { this.viewTop += e.deltaY this.viewLeft += e.deltaX})

 

这里使用了  pressMove 事件,因为 canvas 使用了 absolute 绝对定位,支持 在容器里移动。如果不需要,就让它自适应(通过滚动条移动),就不用 pressMove 事件。

 

完整代码: 

<template> <div > <div :>  <button @click="scaleEvent(3.5)">3.5</button>  <button @click="scaleEvent(2.5)">2.5</button>  <button @click="scaleEvent(1.8)">1.8</button>  <button @click="scaleEvent(1.3)">1.3</button>  <button @click="scaleEvent(1)">1</button>  <button @click="scaleEvent(0.5)">0.5</button> </div> <div  v-show="!loading"  class="pdf-canvas-wrap"  :style="{  top: viewTop + 'px',  left: viewLeft + 'px',  width: viewWidth + 'px',  height: viewHeight + 'px'  }" ></div> <p v-show="loading">正在加载...</p> </div></template><script>import * as PDFJS from 'pdfjs-dist'console.log(PDFJS)import { TextLayerBuilder, EventBus } from 'pdfjs-dist/web/pdf_viewer'import 'pdfjs-dist/web/pdf_viewer.css'console.log(TextLayerBuilder)// 本地// window.pdfjsWorker = require("pdfjs-dist/build/pdf.worker.js");// cdn 2.8.335 2.6.347 2.5.207PDFJS.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.6.347/build/pdf.worker.min.js'// https://github.com/mozilla/pdf.js/blob/master/examples/node/getinfo.js// Requires single file built version of PDF.js -- please run// `gulp singlefile` before running the example.// const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");const CSS_UNITS = 96.0 / 72.0// const PRINT_UNITS = 150 / 72.0;let userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''let platform = (typeof navigator !== 'undefined' && navigator.platform) || ''let maxTouchPoints = (typeof navigator !== 'undefined' && navigator.maxTouchPoints) || 1let maxCanvasPixels = 16777216// PDF之外占据的宽度 -18 padding -18减去滚动条宽度(不确定)let autoWidth = 36let textLayerTop = 3let scaleInterval = 0.05let isAndroid = /Android/.test(userAgent)let isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || (platform === 'MacIntel' && maxTouchPoints > 1);(function checkCanvasSizeLimitation() { if (isIOS || isAndroid) { maxCanvasPixels = 5242880 autoWidth -= 18 textLayerTop -= 1 // 手机上面缩放对清晰度影响更小 scaleInterval = 0.4 }})()import AlloyFinger from 'alloyfinger'//包装一下 不然 eslint 报警告class FingerTouch { constructor(element, options) { Object.assign(this, AlloyFinger.prototype) AlloyFinger.call(this, element, options) }}export default { data() { return {  src: './static/react-native.pdf',  loading: true,  pdfDoc: null,  boxEl: null,  wrapEl: null,  areaWidth: 0,  btnWidth: 0,  viewWidth: 0,  viewHeight: 0,  pixelRatio: 2,  isFirstTimeRender: true,  viewport: null,  canvasEles: [],  canvasCtxs: [],  totallPage: 0,  pageScale: 1, // pdf 适应窗口产生的 scale  curCanvasCSSWh: null,  transform: null,  pageRenderedNum: 0,  scaleTimer: null,  lastStyleScale: 1,  lastRerenderScale: 1,  alloyFinger: null,  viewTop: 0,  viewLeft: 9,  textEls: [] } }, mounted() { this.init() }, methods: { async init() {  //禁止下拉刷新  document.addEventListener(  'touchmove',  function (ev) {   ev.preventDefault()  },  { passive: false }  )  this.boxEl = document.querySelector('.pdf-touch-box')  this.wrapEl = document.getElementsByClassName('pdf-canvas-wrap')[0]  this.btnWidth = this.areaWidth = this.boxEl.clientWidth  const loadingState = await this.getPDF()  if (loadingState === 'success') {  this.initRenderOneByOne()  this.initTouch()  } else this.boxEl.innerText = loadingState }, initTouch() {  this.alloyFinger = new FingerTouch(this.wrapEl, {})  this.alloyFinger.on('pinch', e => {  let zoom = e.zoom  let curScale = this.lastStyleScale * zoom  if (curScale <= this.pageScale / 2 || curScale >= 5) return  this.scaleEvent(curScale)  })  this.alloyFinger.on('pressMove', e => {  this.viewTop += e.deltaY  this.viewLeft += e.deltaX  }) }, scaleEvent(scale) {  // 渲染中 不让缩放 也不让重绘  if (this.pageRenderedNum != this.totallPage || this.totallPage === 0) return  // 没在渲染中 随意缩放  this.scaleCanvas(scale)  // 说明是第一次事件 或重绘完成 开始计时  if (this.scaleTimer === null) {  this.scaleTimer = this.renderDelayer(666)  }  //时间间隔内再次触发缩放 重新计时  clearTimeout(this.scaleTimer)  this.scaleTimer = this.renderDelayer(666) }, renderDelayer(interval) {  return setTimeout(() => {  this.scaleRenderAll()  this.scaleTimer = null  }, interval) }, scaleTopLeft(width, height) {  if (Math.abs(this.viewTop) > height / 2) this.viewTop *= 1 / 2  if (Math.abs(this.viewLeft) > width / 2) this.viewLeft *= 1 / 2 }, scaleCanvas(scale) {  this.lastStyleScale = scale  console.log(scale)  // 改变 viewport 大小  this.viewport = this.viewport.clone({  scale: (this.pageScale * CSS_UNITS * scale).toFixed(3)  })  const { styleWidth, styleHeight } = this.getCanvasCSSWH()  // 计算一下 top left 不然可能会显示到 窗口外面 看不到了  this.scaleTopLeft(styleWidth, styleHeight)  // 改变CSS canvas 会变模糊  this.canvasEles.forEach(canvas => {  // 不修改 width height 不然会重置 canvas 变空白  canvas.style.width = styleWidth + 'px'  canvas.style.height = styleHeight + 'px'  }) }, // 使用新渲染的 canvas 替换 缩放过后不清晰的 canvas scaleRenderAll() {  let curInterval = Math.abs(this.lastStyleScale - this.lastRerenderScale)  let curScaleInterval = scaleInterval  let isNarrow = this.lastStyleScale < this.lastRerenderScale  // 如果是变小 变化不大时 清晰度影响更小  if (isNarrow) curScaleInterval = scaleInterval * 2  console.log('scaleRenderAll', curScaleInterval, curInterval)  // 变化很小的时候就不计时重新渲染了 清晰度影响不大 1.1 - 1 = 0.10000000000000009  if (curInterval <= curScaleInterval) return  this.lastRerenderScale = this.lastStyleScale  this.pageRenderedNum = 0  const len = this.canvasEles.length  for (let pageNum = 1; pageNum <= len; pageNum++) {  let newCanvas = document.createElement('canvas')  let newCtx = newCanvas.getContext('2d', {   alpha: false  })  newCanvas.setAttribute('id', `pdf-canvas${pageNum}`)  this.canvasCtxs[pageNum - 1] = newCtx  let that = this  this.pdfDoc.getPage(pageNum).then(function (page) {   that.setCanvasCSSWh.call(that, newCanvas)   let renderTask = that.pageRender.call(that, page, newCtx)   renderTask.promise   .then(function () {    let oldCanvas = that.canvasEles[pageNum - 1]    oldCanvas.parentElement.replaceChild(newCanvas, oldCanvas)    that.canvasEles[pageNum - 1] = newCanvas    that.pag......

原文转载:http://www.shaoqun.com/a/859336.html

跨境电商:https://www.ikjzd.com/

飞书互动:https://www.ikjzd.com/w/1319.html

邮乐购物商城:https://www.ikjzd.com/w/1776

custommade:https://www.ikjzd.com/w/2514


一、渲染pdf核心代码首先安装pdf.js的npm版本:npmipdfjs-dist@2.6.347使用:import*asPDFJSfrom"pdfjs-dist"其中,pdf.js加载pdf文件依赖了pdf.worker.js,通过指定pdf.worker.js路径让pdf.js加载依赖:  PDFJS.GlobalWorkerOptions.workerSrc="
"七分靠选品,三分靠运营"你选对产品了吗?:https://www.ikjzd.com/articles/126907
亚马逊限制入仓对卖家有什么影响?:https://www.ikjzd.com/articles/126809
Wish季节性选品指南来咯 Get万圣节销售Tips!:https://www.ikjzd.com/articles/126925
亚马逊运营中关于各类发票的问题:https://www.ikjzd.com/articles/126924
求你停下别再㖭了老师 哥一起我会坏掉的:http://lady.shaoqun.com/a/248422.html
口述和少妇在阳台上做了 小东西我们今天换一种姿势:http://lady.shaoqun.com/a/248024.html
学长我们去厕所里做好不好 小东西是不是又想要了:http://lady.shaoqun.com/m/a/247931.html
美女用手扒开自己下面 把她压在桌上进进出出:http://lady.shaoqun.com/m/a/247404.html
女海王阵型!不告诉男朋友就勾搭富二代!数百万粉丝,Tik Tok女人,网络名人,做了很多轮:http://lady.shaoqun.com/a/410933.html
清迈的一个天桥小舒林成同志,被居民举报:http://lady.shaoqun.com/a/410934.html
女人为什么选择"暧昧"?倾听中年妇女的心声:http://lady.shaoqun.com/a/410935.html
独立站高昂流量成废品,如何操作才能起死回生?(上):https://www.ikjzd.com/articles/146487

No comments:

Post a Comment