使用 pdf.js 使用加载的 pdf 文件在 canvas 中绘制矩形

Draw rectangle in canvas with loaded pdf file using pdf.js

我正在尝试在 pdf 文件上绘制矩形。当我在 pdf 中绘制矩形时,矩形无法正确绘制。

我想一次只画一个矩形,当我画新的矩形时,旧的矩形应该被移除,但它没有发生。

这是我的代码:

pdf渲染代码(渲染正常)

function pdfFile (file) {
pdfjsLib.workerSrc = 'pdf.worker.js';
pdfjsLib.getDocument(file).promise.then(function(pdfDoc) {
  pdf = pdfDoc;
  document.getElementById('page_count').textContent = pdfDoc.numPages;
  showButtonGroup(pdf);
  renderPage(pageNum);
});
} 

 function renderPage(num) {
    pageRendering = true;
    pdf.getPage(num).then(function(page) {
      var viewport = page.getViewport({scale: scale});
      canvas.height = viewport.height;
      canvas.width = viewport.width;
      var renderContext = {
        canvasContext: ctx,
        viewport: viewport
      };
      var renderTask = page.render(renderContext);
      renderTask.promise.then(function() {
        pageRendering = false;
        if (pageNumPending !== null) {
          renderPage(pageNumPending);
          pageNumPending = null;
        }
      });
    });

    document.getElementById('page_num').textContent = num;
}

鼠标移动功能无法正常使用

function mouseMove(e) {
    if (drag) {
        ctx.putImageData(pdfPages[pageNum], 0, 0);
        ctx.clearRect(rect.startX, rect.startY, rect.w, rect.h);
        rect.w = ((e.pageX - x) - this.offsetLeft) - rect.startX;
        rect.h = ((e.pageY - y) - this.offsetTop) - rect.startY;      
        ctx.strokeStyle = color;
        ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
        Object.assign(data, {
            x: rect.startX,
            y: rect.startY,
            w: rect.w,
            h: rect.h
        })
        console.log(data);
    }
}

  1. 当我启用 clearRect 和 putImageData 函数时,矩形会正确绘制,但 canvas pdf 显示为空。这是附件图片

  2. 当仅启用clearRect 功能时,在pdf 中显示多个矩形。这是附件图片

请检查以下内容,需要在创建新矩形之前清除现有矩形

function renderPage(num) {
    pageRendering = true;
    pdf.getPage(num).then(function (page) {
        var viewport = page.getViewport({ scale: scale });
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        var renderContext = {
            canvasContext: ctx,
            viewport: viewport
        };
        var renderTask = page.render(renderContext);
        renderTask.promise.then(function () {
            pageRendering = false;

            //You need to clear the existing rectangle
            pdfPages[num] = ctx.getImageData(0, 0, canvas.width, canvas.height);

            //Now you can draw new rectangle
            drawRectangle(10, 10, 100, 50);
            if (pageNumPending !== null) {
                renderPage(pageNumPending);
                pageNumPending = null;
            }
        });
    });

    function drawRectangle(x, y, w, h) {
        ctx.strokeStyle = color;
        ctx.strokeRect(x, y, w, h);
    }

使用 pdf.js 在 canvas 上做可选矩形的另一种方法是使用 toDataURL() 保存原始 canvas,然后在 clearRect 之后使用 canvas.draw () 使用之前保存的 base64 图像绘制 canvas。

import React, { useEffect, useState, useRef, useCallback } from "react";
import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
import * as pdfjsLib from "pdfjs-dist/build/pdf";

export default function CustomPdfReader({ url }) {
  pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;

  const canvasRef = useRef();
  const [pdfRef, setPdfRef] = useState("");
  const currentPage = 1;
  const zoomScale = 1;
  const rotateAngle = 0;
  var pdf_image = "";
  const renderPage = useCallback(
    (pageNum, pdf = pdfRef) => {
      pdf &&
        pdf.getPage(pageNum).then(function (page) {
          const viewport = page.getViewport({ scale: zoomScale, rotation: rotateAngle });
          const canvas = canvasRef.current;
          canvas.height = viewport?.height;
          canvas.width = viewport?.width;
          const renderContext = {
            canvasContext: canvas?.getContext("2d"),
            viewport: viewport,
            textContent: pdfRef,
          };

          page.render(renderContext);
        });
    },
    [pdfRef, url]
  );
  useEffect(() => {
    if (url.slice(-4).toLowerCase() === ".pdf") {
      renderPage(currentPage, pdfRef);
    } else {
      setPdfRef("");
    }
  }, [pdfRef, renderPage, url]);

  useEffect(() => {
    const loadingTask = pdfjsLib.getDocument(url);
    loadingTask.promise.then(
      (loadedPdf) => {
        setPdfRef(loadedPdf);
      },
      function (reason) {
        console.error(reason);
      }
    );
  }, [url]);

  var cursorInCanvas = false;
  var canvasOfDoc = canvasRef?.current;
  var ctx;
  var startX;
  var startY;
  var offsetX;
  var offsetY;

  const saveInitialCanvas = () => {
    if (canvasOfDoc?.getContext) {
      var canvasPic = new Image();
      canvasPic.src = canvasOfDoc.toDataURL();
      pdf_image = canvasPic;
    }
  };

  useEffect(() => {
    if (canvasOfDoc) {
      ctx = canvasOfDoc.getContext("2d");
      var canvasOffset = canvasOfDoc.getBoundingClientRect();
      offsetX = canvasOffset.left;
      offsetY = canvasOffset.top;
    }
  }, [canvasOfDoc, pdfRef,  renderPage, url]);

  function handleMouseIn(e) {
    if (typeof pdf_image == "string") {
      saveInitialCanvas();
    }
    e.preventDefault();
    e.stopPropagation();
    startX = ((e.offsetX * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
    startY = ((e.offsetY * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;

    cursorInCanvas = true;
  }

  function handleMouseOut(e) {
    e.preventDefault();
    e.stopPropagation();
    cursorInCanvas = false;
  }

  function handleMouseMove(e) {
    e.preventDefault();
    e.stopPropagation();
    if (!cursorInCanvas) {
      return;
    }
    let mouseX = ((e.offsetX * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;
    let mouseY = ((e.offsetY * canvasOfDoc.width) / canvasOfDoc.clientWidth) | 0;

    var width = mouseX - startX;
    var height = mouseY - startY;
    if (ctx) {
      ctx?.clearRect(0, 0, canvasOfDoc.width, canvasOfDoc.height);
      ctx?.drawImage(pdf_image, 0, 0);
      ctx.beginPath();
      ctx.rect(startX, startY, width, height);
      ctx.strokeStyle = "#1B9AFF";
      ctx.lineWidth = 1;
      ctx.stroke();
    }
  }

  canvasOfDoc?.addEventListener("mousedown", function (e) {
    handleMouseIn(e);
  });
  canvasOfDoc?.addEventListener("mousemove", function (e) {
    handleMouseMove(e);
  });
  canvasOfDoc?.addEventListener("mouseup", function (e) {
    handleMouseOut(e);
  });
  canvasOfDoc?.addEventListener("mouseout", function (e) {
    handleMouseOut(e);
  });

  return (
    <>
      <canvas id="pdf-doc" ref={canvasRef} />
    </>
  );
}