Svelte PDF Viewer Highlightend PDF

392 views Asked by At

I have the following problem: I want to render PDFs, and some of them may contain highlighted text as an overlay. I'm using pdfjs-dist to display the PDFs. The PDF is rendered correctly; however, the overlay/highlighted text is not displayed. Does anyone have an idea on how to fix that?

Here's my current Svelte component:

    `<script lang="ts">
import { onMount } from 'svelte';
import * as pdfjs from 'pdfjs-dist';
import { Icon } from '@webcms/component-library';

export let currPage = 0;
export let blob: Blob | undefined = undefined;
export let hasErrors = false;

let loaded = false;

$: if (currPage) {
    scrollToPage(currPage);
}

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
    'pdfjs-dist/build/pdf.worker.js',
    import.meta.url
).toString();

let canvas: HTMLCanvasElement;
let pdfDoc: pdfjs.PDFDocumentProxy | null = null;

onMount(async () => {
    pdfDoc = null;

    if (blob) {
        let arryBuffer = await blob.arrayBuffer();
        pdfjs
            .getDocument(arryBuffer)
            .promise.then(function (pdf) {
                pdfDoc = pdf;
                let viewer = document.getElementById('pdf-viewer');

                for (let page = 1; page <= pdf.numPages; page++) {
                    canvas = document.createElement('canvas');
                    canvas.className = 'pdf-page-canvas';
                    viewer?.appendChild(canvas);
                    renderPage(page, canvas);
                }
            })
            .catch((e) => {
                hasErrors = true;
                console.error(e);
            });
    }

    loaded = true;
});

/**
 * Scrolls to a specific page in the viewer.
 *
 * @param {number} pageNumber - The page number to scroll to.
 */
function scrollToPage(pageNumber: number) {
    const canvasElement = document.querySelector('.pdf-page-canvas:nth-child(' + 
             pageNumber + ')');
    if (canvasElement) {
        canvasElement.scrollIntoView();
    }
}

/**
 * Renders a specific page of a PDF document onto a canvas element.
 *
 * @param {number} pageNumber - The page number to render.
 * @param {HTMLCanvasElement} canvas - The canvas element to render onto.
 */
function renderPage(pageNumber: number, canvas: HTMLCanvasElement) {
    pdfDoc?.getPage(pageNumber).then(function (page) {
        let viewport = page.getViewport({ scale: window.innerWidth < 1300 ? 1 : 
                    2  });
        let context = canvas.getContext('2d');
        if (context) {
            canvas.width = viewport.width * 2;
            canvas.height = viewport.height * 2;
            context.scale(2, 2);
            page.render({ canvasContext: context, viewport: viewport });
            if (pageNumber === currPage) {
                canvas.scrollIntoView();
            }
        }
    });
}
  </script>

  {#if loaded}
<div class="pdf-layout">
    <div id="pdf-viewer" />
</div>
  {/if} `

I tried using other libraries but encountered the same result. My only solution so far has been to use an iframe, but I wanted to avoid it because I intend to integrate buttons for navigating through the PDF, and I want to prevent the iframe from reloading.

EDIT: I checked the PDF, and the issue is not with the overlay; rather, the annotation layer did not render correctly.

1

There are 1 answers

2
Eilimint On

Is the highlighted overlay an annotation? For pdfjs you need to manually render the text layer and annotation layers to be able to select text and click on annotations such as hyperlinks. After you have called page.render you can add the text and annotation layers.

import { AnnotationLayerBuilder, TextLayerBuilder, PDFLinkService, LinkTarget } from 'pdfjs-dist/web/pdf_viewer'
import 'pdfjs-dist/web/pdf_viewer.css'

async function renderAnnotationLayer(viewport) {
    const linkService = new PDFLinkService({
      externalLinkTarget: LinkTarget.BLANK,
      eventBus
    })

    linkService.setViewer(pageContainer)

    var annotation: AnnotationLayer = new AnnotationLayerBuilder({
      pageDiv: annotationLayerElement,
      pdfPage: pdfPage,
      linkService
    })

    await annotation.render(viewport)
  }