pdf-js-wrapper.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // NOTE: using "legacy" build as main build requires webpack v5
  2. // import PDFJS from 'pdfjs-dist/webpack'
  3. import * as PDFJS from 'pdfjs-dist/legacy/build/pdf'
  4. import * as PDFJSViewer from 'pdfjs-dist/legacy/web/pdf_viewer'
  5. import PDFJSWorker from 'pdfjs-dist/legacy/build/pdf.worker'
  6. import 'pdfjs-dist/legacy/web/pdf_viewer.css'
  7. import getMeta from '../../../utils/meta'
  8. if (typeof window !== 'undefined' && 'Worker' in window) {
  9. PDFJS.GlobalWorkerOptions.workerPort = new PDFJSWorker()
  10. }
  11. const params = new URLSearchParams(window.location.search)
  12. const disableFontFace = params.get('disable-font-face') === 'true'
  13. const cMapUrl = getMeta('ol-pdfCMapsPath')
  14. const imageResourcesPath = getMeta('ol-pdfImageResourcesPath')
  15. const rangeChunkSize = 128 * 1024 // 128K chunks
  16. export default class PDFJSWrapper {
  17. constructor(container) {
  18. this.container = container
  19. // create the event bus
  20. const eventBus = new PDFJSViewer.EventBus()
  21. // create the link service
  22. const linkService = new PDFJSViewer.PDFLinkService({
  23. eventBus,
  24. externalLinkTarget: 2,
  25. externalLinkRel: 'noopener',
  26. })
  27. // create the localization
  28. // const l10n = new PDFJSViewer.GenericL10n('en-GB') // TODO: locale mapping?
  29. // create the viewer
  30. const viewer = new PDFJSViewer.PDFViewer({
  31. container,
  32. eventBus,
  33. imageResourcesPath,
  34. linkService,
  35. // l10n, // commented out since it currently breaks `aria-label` rendering in pdf pages
  36. enableScripting: false, // default is false, but set explicitly to be sure
  37. renderInteractiveForms: false,
  38. })
  39. linkService.setViewer(viewer)
  40. this.eventBus = eventBus
  41. this.linkService = linkService
  42. this.viewer = viewer
  43. }
  44. // load a document from a URL
  45. loadDocument(url) {
  46. // prevents any previous loading task from populating the viewer
  47. this.loadDocumentTask = undefined
  48. return new Promise((resolve, reject) => {
  49. this.loadDocumentTask = PDFJS.getDocument({
  50. url,
  51. cMapUrl,
  52. cMapPacked: true,
  53. disableFontFace,
  54. rangeChunkSize,
  55. disableAutoFetch: true,
  56. disableStream: true,
  57. textLayerMode: 2, // PDFJSViewer.TextLayerMode.ENABLE,
  58. })
  59. this.loadDocumentTask.promise
  60. .then(doc => {
  61. if (!this.loadDocumentTask) {
  62. return // ignoring the response since loading task has been aborted
  63. }
  64. const previousDoc = this.viewer.pdfDocument
  65. this.viewer.setDocument(doc)
  66. this.linkService.setDocument(doc)
  67. resolve(doc)
  68. if (previousDoc) {
  69. previousDoc.cleanup().catch(console.error)
  70. previousDoc.destroy()
  71. }
  72. })
  73. .catch(error => {
  74. if (this.loadDocumentTask) {
  75. reject(error)
  76. }
  77. })
  78. .finally(() => {
  79. this.loadDocumentTask = undefined
  80. })
  81. })
  82. }
  83. // update the current scale value if the container size changes
  84. updateOnResize() {
  85. const currentScaleValue = this.viewer.currentScaleValue
  86. if (
  87. currentScaleValue === 'auto' ||
  88. currentScaleValue === 'page-fit' ||
  89. currentScaleValue === 'page-width'
  90. ) {
  91. this.viewer.currentScaleValue = currentScaleValue
  92. }
  93. this.viewer.update()
  94. }
  95. // get the page and offset of a click event
  96. clickPosition(event, pageElement, textLayer) {
  97. const { viewport } = this.viewer.getPageView(textLayer.pageNumber - 1)
  98. const pageRect = pageElement.querySelector('canvas').getBoundingClientRect()
  99. const dx = event.clientX - pageRect.left
  100. const dy = event.clientY - pageRect.top
  101. const [left, top] = viewport.convertToPdfPoint(dx, dy)
  102. return {
  103. page: textLayer.pageNumber - 1,
  104. offset: {
  105. left,
  106. top: viewport.viewBox[3] - top,
  107. },
  108. }
  109. }
  110. // get the current page, offset and page size
  111. get currentPosition() {
  112. const pageIndex = this.viewer.currentPageNumber - 1
  113. const pageView = this.viewer.getPageView(pageIndex)
  114. const pageRect = pageView.div.getBoundingClientRect()
  115. const containerRect = this.container.getBoundingClientRect()
  116. const dy = containerRect.top - pageRect.top
  117. const [, , width, height] = pageView.viewport.viewBox
  118. const [, top] = pageView.viewport.convertToPdfPoint(0, dy)
  119. return {
  120. page: pageIndex,
  121. offset: { top, left: 0 },
  122. pageSize: { height, width },
  123. }
  124. }
  125. abortDocumentLoading() {
  126. this.loadDocumentTask = undefined
  127. }
  128. destroy() {
  129. if (this.loadDocumentTask) {
  130. this.loadDocumentTask.destroy()
  131. this.loadDocumentTask = undefined
  132. }
  133. this.viewer.destroy()
  134. }
  135. }