You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于pdfjs与PDF-LIB的PDF画布点击删除数字标注功能咨询

在PDF.js查看器中实现可点击删除的数字标注

当然可以在PDF.js查看器内添加点击事件,不用纠结单纯叠加HTML的问题,结合PDF.js的渲染机制和定位逻辑就能解决。下面是具体实现思路:

1. 绑定Canvas点击事件(直接操作渲染层)

PDF.js通过Canvas渲染每一页PDF,你可以直接给Canvas绑定点击事件,然后将鼠标坐标转换为PDF内部坐标,匹配标注位置:

// 获取所有页面的Canvas元素
const canvases = document.querySelectorAll('.page canvas');
canvases.forEach((canvas, index) => {
  const pageNum = index + 1; // PDF页码从1开始
  canvas.addEventListener('click', (e) => {
    // 获取当前页面的viewport(从PDF.js的viewer实例中获取)
    const viewport = pdfViewer.getPageView(pageNum - 1).viewport;
    // 将鼠标客户端坐标转换为PDF内部坐标
    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX - rect.left) / viewport.scale;
    const y = (rect.bottom - e.clientY) / viewport.scale; // PDF的Y轴从底部开始计算
    
    // 遍历标注数组,判断点击位置是否在数字标注范围内
    const targetAnnotation = annotations.find(anno => {
      return anno.pageNum === pageNum && 
             x >= anno.x - 10 && x <= anno.x + 10 && 
             y >= anno.y - 10 && y <= anno.y + 10;
    });
    
    if (targetAnnotation) {
      deleteAnnotation(targetAnnotation);
    }
  });
});

2. 准确定位叠加HTML元素(解决之前的定位失败问题)

如果想用HTML元素显示数字,关键是基于PDF.js的页面容器和viewport计算准确位置:

// 假设标注对象格式:{ id: 'anno1', pageNum: 2, x: 100, y: 200, number: '1' }
function renderAnnotation(annotation) {
  const pageView = pdfViewer.getPageView(annotation.pageNum - 1);
  const viewport = pageView.viewport;
  const pageContainer = pageView.div;
  
  // 将PDF坐标转换为HTML容器内的坐标
  const htmlCoords = viewport.convertToViewportPoint(annotation.x, annotation.y);
  // 转换PDF Y轴为HTML Y轴(从上到下)
  const htmlY = viewport.height - htmlCoords[1];
  
  // 创建数字元素
  const numElement = document.createElement('span');
  numElement.textContent = annotation.number;
  numElement.style.cssText = `
    position: absolute;
    left: ${htmlCoords[0]}px;
    top: ${htmlY}px;
    padding: 2px 6px;
    background: #ffeb3b;
    cursor: pointer;
    z-index: 10;
  `;
  numElement.dataset.annoId = annotation.id;
  
  // 添加点击删除事件
  numElement.addEventListener('click', () => {
    // 从标注数组移除
    annotations = annotations.filter(anno => anno.id !== annotation.id);
    // 移除HTML元素
    numElement.remove();
    // 用PDF-LIB更新PDF文档
    updatePDFAfterDelete(annotation);
  });
  
  pageContainer.appendChild(numElement);
}

3. 结合PDF-LIB完成持久化删除

删除标注后,需要用PDF-LIB加载原PDF,移除对应的文本标注并重新生成:

async function updatePDFAfterDelete(annotation) {
  // 加载原PDF文档
  const pdfDoc = await PDFLib.PDFDocument.load(originalPdfBytes);
  const targetPage = pdfDoc.getPages()[annotation.pageNum - 1];
  
  // 根据你添加标注时的逻辑,移除对应内容(示例需结合实际存储调整)
  // 建议维护标注与PDF-LIB操作的映射表,方便精准删除
  
  // 保存修改后的PDF
  const modifiedPdfBytes = await pdfDoc.save();
  // 更新PDF.js查看器显示新文档
  loadModifiedPDF(modifiedPdfBytes);
}

关键注意点

  • 监听PDF.js的pagerendered事件,在页面渲染完成后再渲染标注,避免滚动后标注丢失
  • 处理缩放逻辑:监听scalechanged事件,缩放时重新计算标注元素位置
  • 保持数据一致性:确保内存标注数组、HTML元素、PDF-LIB中的标注三者同步

内容的提问来源于stack exchange,提问作者adrian thuo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:05:10