如何使用 PDF.js 和 jQuery 在 PDF 上创建可拖动元素
Posted
技术标签:
【中文标题】如何使用 PDF.js 和 jQuery 在 PDF 上创建可拖动元素【英文标题】:How to create a draggable element on top of a PDF using PDF.js and jQuery 【发布时间】:2021-11-15 13:51:34 【问题描述】:我正在创建一项服务,以使用 PDF.js 和 jQuery 为 pdf 标记图像。我设法使用 PDF.js 创建了一个可拖动的对象,但该对象在被拖动时会留下过去对象的痕迹。
我使用context.clearRect(0, 0, canvas.width, canvas.height);
清除了过去的对象,但它也清除了画布中的底层 PDF。
如何在不影响底层 PDF 的情况下拖动该对象?
这是我到目前为止所做的。
我正在使用以下代码将 PDF 加载到画布上。
function loadPdfPreview(base64pdf)
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument(data: base64pdf);
loadingTask.promise.then(function (pdf)
// Fetch the first page
pdf.getPage(1).then(function (page)
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
// Render PDF page into canvas context
var renderContext =
canvasContext: context,
viewport: viewport
;
page.render(renderContext).then(function ()
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
, function (e)
console.log(e);
);
);
);
pdf 加载到画布后,我使用以下函数在画布顶部绘制对象。
function drawObjectFromBlueprint(blueprint)
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
// Clearing the previous dummy objects
context.clearRect(0, 0, canvas.width, canvas.height);
// drawing the dummy object
context.beginPath();
context.moveTo(blueprint.x, blueprint.y);
context.lineTo(blueprint.right, blueprint.y);
context.lineTo(blueprint.right, blueprint.bottom);
context.lineTo(blueprint.x, blueprint.bottom);
context.closePath();
context.fillStyle = blueprint.fill;
context.fill();
context.stroke();
我使用以下代码处理鼠标移动事件。
function handleMouseMove(e)
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
我使用以下代码监听鼠标移动事件。
$("#drawable-canvas").mousemove(function (e)
handleMouseMove(e);
);
我想在不影响基础 PDF 的情况下重新绘制对象。试图通过清除整个画布来加载 PDF 并重新绘制对象,但它没有按预期工作。
【问题讨论】:
我认为您需要一个可拖动的新画布。防止与pdf一起使用。 【参考方案1】:在page.render
方法的回调中,会在画布上绘制pdf页面。您必须单独保存绘制的图像,以免原始图像因拖动而消失。
// maybe globalScope...?
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
// your code
page.render(renderContext).then(function ()
// Save the original page image.
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
tempCtx.drawImage(canvas, 0, 0);
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
, ...
接下来,请将其修改为使用drawObjectFromBlueprint
中的原始页面图像进行绘制。
function drawObjectFromBlueprint(blueprint)
// draw original page image
context.drawImage(tempCanvas, 0, 0);
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
...
【讨论】:
【参考方案2】:经过两个小时的尝试,找到了实现此目的的方法。我使用了@Nikolaus 建议的两个画布,并使用底部画布加载 PDF,顶部画布用于绘图。
以下是我的 html:
<div class="col-md-12" id="pdfDisplay" style="display: none;">
<div id="pageContainer" class="pdfViewer nopadding" style="background-color:transparent">
<canvas id="pdf-canvas" style="border:1px solid black"></canvas>
<canvas id="drawable-canvas" style="border:1px solid black"></canvas>
</div>
</div>
以下是我将两个画布放在彼此顶部的 CSS。
#pageContainer position: relative;
#drawable-canvas position: absolute; top: 0; left: 0;
以下是我的全局 javascript 变量:
var isUploading = false;
var base64pdf = "";
var initX = 50;
var initY = 50;
var initWidth = 200;
var initHeight = 150;
// blueprint options are in pixels
// this blueprint holds the latest values for the draggable object
// always update this global blueprint when making a change so it holds the latest values
var blueprint =
x: initX,
y: initY,
width: initWidth,
height: initHeight,
right: (initX+initWidth), // x + width
bottom: (initY+initHeight), // y + height
fill: "skyblue"
;
var context = null;
var canvas = null;
var drawableContext = null;
var drawableCanvas = null;
var canvasOffset = null;
var offsetX = 0;
var offsetY = 0;
var canvasOffset1 = null;
var offsetX1 = 0;
var offsetY1 = 0;
var lastX = 0;
var lastY = 0;
var mouseIsDown = false;
Javascript 函数可以监听鼠标的上移、下移和移动,因为我只需要在使用鼠标拖动对象时跟踪鼠标的移动。
$("#drawable-canvas").mousedown(function (e)
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
lastX = mouseX;
lastY = mouseY;
mouseIsDown = true;
);
$("#drawable-canvas").mousemove(function (e)
handleMouseMove(e);
);
$("#drawable-canvas").mouseup(function (e)
mouseIsDown = false;
);
Javascript 函数将 PDF 加载到底部画布。
function loadPdfPreview(base64pdf)
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument(data: base64pdf);
loadingTask.promise.then(function (pdf)
// Fetch the first page
pdf.getPage(1).then(function (page)
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
canvasOffset1 = $("#drawable-canvas").offset();
offsetX1 = canvasOffset1.left;
offsetY1 = canvasOffset1.top;
// creating the drawable-canvas canvas for drawing purposes without affecting the pdf-canvas
// it has identical width and height and X and Y values
drawableCanvas = document.getElementById('drawable-canvas');;
drawableCanvas.height = viewport.height;
//bringing the drawable canvas up using z-index
drawableCanvas.style.zIndex = 1;
drawableCanvas.width = viewport.width;
drawableContext = drawableCanvas.getContext('2d');
// Render PDF page into canvas context
var renderContext =
canvasContext: context,
viewport: viewport
;
page.render(renderContext).then(function ()
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
, function (e)
console.log(e);
);
);
);
处理鼠标移动(拖动对象):
function handleMouseMove(e)
if (!mouseIsDown)
return;
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
console.log(blueprint);
在可绘制画布上绘制对象的Javascript函数,完全独立于pdf-canvas。
function drawObjectFromBlueprint(blueprint)
// drawing a draggable element inside the canvas
drawableContext.strokeStyle = "lightgray";
// Clearing the previous dummy objects
drawableContext.clearRect(0, 0, drawableCanvas.width, drawableCanvas.height);
// drawing the dummy object
drawableContext.beginPath();
drawableContext.moveTo(blueprint.x, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.bottom);
drawableContext.lineTo(blueprint.x, blueprint.bottom);
drawableContext.closePath();
drawableContext.fillStyle = blueprint.fill;
drawableContext.fill();
drawableContext.stroke();
【讨论】:
以上是关于如何使用 PDF.js 和 jQuery 在 PDF 上创建可拖动元素的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PyQt 中使用 pdf.js 查看器呈现 PDF?