From 27d6f6c11685ee2377ab2af15fb3a5e835240f70 Mon Sep 17 00:00:00 2001 From: Erik Demaine Date: Thu, 21 Dec 2023 17:06:44 -0500 Subject: [PATCH] Render selectable PDF text and upgrade pdfjs to v3 --- CHANGELOG.md | 4 ++++ client/MessagePDF.coffee | 12 +++++++----- client/message.styl | 13 ++++++++++--- package.json | 4 ++-- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f78613..a9d6493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ To see every change with descriptions aimed at developers, see As a continuously updated web app, Coauthor uses dates instead of version numbers. +## 2023-12-21 + +* You can now select and copy text from PDFs. + ## 2023-12-20 * Fix the wrong page's PDF links sometimes showing up when quickly flipping diff --git a/client/MessagePDF.coffee b/client/MessagePDF.coffee index ab1d9a5..7782c88 100644 --- a/client/MessagePDF.coffee +++ b/client/MessagePDF.coffee @@ -131,13 +131,14 @@ WrappedMessagePDF = React.memo ({file}) -> canvas.height = height * dpiScale #unless dpiScale == 1 canvas.style.transform = "scale(#{1/dpiScale},#{1/dpiScale})" - canvas.style.transformOrigin = "0% 0%" - scaledViewport = page.getViewport scale: dpiScale * width / viewport.width + scale = dpiScale * width / viewport.width + scaledViewport = page.getViewport {scale} setRendering true renderTask = page.render canvasContext: context viewport: scaledViewport canceled = false + textRender = null Promise.all [renderTask.promise, page.getAnnotations()] .then ([rendered, annotationsLoaded]) => return if canceled @@ -162,10 +163,10 @@ WrappedMessagePDF = React.memo ({file}) -> setRendering false setAnnotations newAnnotations setAnnotationsTransform "scale(#{1/dpiScale},#{1/dpiScale}) matrix(#{scaledViewport.transform.join ','})" + textRef.current.style.setProperty '--scale-factor', scale textRef.current.style.transform = "scale(#{1/dpiScale},#{1/dpiScale})" - textRef.current.style.transformOrigin = "0% 0%" textRender = pdfjs.renderTextLayer - textContentStream: page.streamTextContent() + textContentSource: page.streamTextContent() container: textRef.current viewport: scaledViewport isOffscreenCanvasSupported: true @@ -175,6 +176,8 @@ WrappedMessagePDF = React.memo ({file}) -> => canceled = true renderTask.cancel() + textRender?.cancel() + textRef.current?.innerHTML = '' , [page, elementWidth, fit, inView] ## Synchronize page input with navigation of page number @@ -290,7 +293,6 @@ WrappedMessagePDF = React.memo ({file}) ->
{for annotation in annotations continue unless annotation.subtype == 'Link' diff --git a/client/message.styl b/client/message.styl index b663d59..2362a73 100644 --- a/client/message.styl +++ b/client/message.styl @@ -429,6 +429,8 @@ nav.contents .pdfBox width: 100% .pdf + > * + transform-origin: 0% 0% > svg width: 100% height: auto @@ -441,14 +443,19 @@ nav.contents border: solid hsla(250,75%,50%,33%) &:hover border: solid hsla(250,75%,50%,66%) - > span + > span, > br position: absolute cursor: text text-align: initial white-space: pre transform-origin: 0% 0% - width: max-content - color: purple + color: transparent + opacity: 25% + ::selection + background: blue + background: AccentColor + > br::selection + background: transparent @media print .pdf > .annotations display: none diff --git a/package.json b/package.json index 5f32dd8..add54f7 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,8 @@ "markdown-it-anchor": "8.6.4", "markdown-it-replacements": "1.0.2", "markdown-it-task-checkbox": "1.0.6", - "meteor-node-stubs": "^1.0.1", - "pdfjs-dist": "2.5.207", + "meteor-node-stubs": "1.2.7", + "pdfjs-dist": "3.11.174", "react": "^17.0.1", "react-bootstrap": "^1.4.3", "react-bootstrap-typeahead": "^5.1.4",