pdf-js-wrapper.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. enableXfa: false, // default is false (2021-10-12), but set explicitly to be sure
  38. renderInteractiveForms: false,
  39. })
  40. linkService.setViewer(viewer)
  41. this.eventBus = eventBus
  42. this.linkService = linkService
  43. this.viewer = viewer
  44. }
  45. // load a document from a URL
  46. loadDocument(url) {
  47. // prevents any previous loading task from populating the viewer
  48. this.loadDocumentTask = undefined
  49. return new Promise((resolve, reject) => {
  50. this.loadDocumentTask = PDFJS.getDocument({
  51. url,
  52. cMapUrl,
  53. cMapPacked: true,
  54. disableFontFace,
  55. rangeChunkSize,
  56. disableAutoFetch: true,
  57. disableStream: true,
  58. textLayerMode: 2, // PDFJSViewer.TextLayerMode.ENABLE,
  59. })
  60. this.loadDocumentTask.promise
  61. .then(doc => {
  62. if (!this.loadDocumentTask) {
  63. return // ignoring the response since loading task has been aborted
  64. }
  65. const previousDoc = this.viewer.pdfDocument
  66. this.viewer.setDocument(doc)
  67. this.linkService.setDocument(doc)
  68. resolve(doc)
  69. if (previousDoc) {
  70. previousDoc.cleanup().catch(console.error)
  71. previousDoc.destroy()
  72. }
  73. })
  74. .catch(error => {
  75. if (this.loadDocumentTask) {
  76. reject(error)
  77. }
  78. })
  79. .finally(() => {
  80. this.loadDocumentTask = undefined
  81. })
  82. })
  83. }
  84. // update the current scale value if the container size changes
  85. updateOnResize() {
  86. const currentScaleValue = this.viewer.currentScaleValue
  87. if (
  88. currentScaleValue === 'auto' ||
  89. currentScaleValue === 'page-fit' ||
  90. currentScaleValue === 'page-width'
  91. ) {
  92. this.viewer.currentScaleValue = currentScaleValue
  93. }
  94. this.viewer.update()
  95. }
  96. // get the page and offset of a click event
  97. clickPosition(event, pageElement, textLayer) {
  98. const { viewport } = this.viewer.getPageView(textLayer.pageNumber - 1)
  99. const pageRect = pageElement.querySelector('canvas').getBoundingClientRect()
  100. const dx = event.clientX - pageRect.left
  101. const dy = event.clientY - pageRect.top
  102. const [left, top] = viewport.convertToPdfPoint(dx, dy)
  103. return {
  104. page: textLayer.pageNumber - 1,
  105. offset: {
  106. left,
  107. top: viewport.viewBox[3] - top,
  108. },
  109. }
  110. }
  111. // get the current page, offset and page size
  112. get currentPosition() {
  113. const pageIndex = this.viewer.currentPageNumber - 1
  114. const pageView = this.viewer.getPageView(pageIndex)
  115. const pageRect = pageView.div.getBoundingClientRect()
  116. const containerRect = this.container.getBoundingClientRect()
  117. const dy = containerRect.top - pageRect.top
  118. const [, , width, height] = pageView.viewport.viewBox
  119. const [, top] = pageView.viewport.convertToPdfPoint(0, dy)
  120. return {
  121. page: pageIndex,
  122. offset: { top, left: 0 },
  123. pageSize: { height, width },
  124. }
  125. }
  126. abortDocumentLoading() {
  127. this.loadDocumentTask = undefined
  128. }
  129. destroy() {
  130. if (this.loadDocumentTask) {
  131. this.loadDocumentTask.destroy()
  132. this.loadDocumentTask = undefined
  133. }
  134. this.viewer.destroy()
  135. }
  136. }