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

如何在使用Canvas元素的PdfJs 3.4.120中显示标准工具栏?

问题描述

在Spring Boot-MVC应用的JSP页面中使用PDF.js 3.4.120版本展示PDF文件,遇到以下问题:

  • 用iframe嵌入viewer.html能显示标准工具栏,但需求限制无法使用iframe
  • 自行通过Canvas渲染PDF仅能显示文档内容,缺少工具栏功能

当前使用的代码如下:

$.ajax({
        //some code
    }).done(function(data, textStatus, jqXHR) {
    
        var pdfData = new Uint8Array(data);
        var pdfContainer = document.getElementById('pdfContainer');
        pdfjsLib.GlobalWorkerOptions.workerSrc = "pdf.worker.min.js";

        pdfjsLib.getDocument({ data: pdfData }).promise.then(function(pdf) {

            for(pageNum = 1; pageNum <= pdf.numPages; pageNum++) {

                pdf.getPage(pageNum).then(page => {

                    const canvas = document.createElement('canvas');

                    var scale = 1.5;
                    var viewport = page.getViewport({ scale: scale, });

                    var outputScale = window.devicePixelRatio || 1;
                    var context = canvas.getContext('2d');

                    canvas.width = Math.floor(viewport.width * outputScale);
                    canvas.height = Math.floor(viewport.height * outputScale);
                    canvas.style.width = Math.floor(viewport.width) + "px";
                    canvas.style.height =  Math.floor(viewport.height) + "px";

                    var transform = outputScale !== 1
                      ? [outputScale, 0, 0, outputScale, 0, 0]
                      : null;

                    var renderContext = {
                      canvasContext: context,
                      transform: transform,
                      viewport: viewport
                    };
                    page.render(renderContext);
                    pdfContainer.appendChild(canvas);

                            
                });
            }
        });
    })

页面容器:

<div id="pdfContainer"></div>
解决方案:手动实现基础工具栏功能

直接用Canvas渲染仅会绘制PDF页面内容,PDF.js不会自动提供工具栏,需要自行构建UI并绑定操作逻辑。

步骤1:添加工具栏HTML结构

在页面中插入工具栏容器,包含常用操作按钮:

<div id="pdfToolbar">
  <button id="prevPage">上一页</button>
  <span id="pageInfo">第 <span id="currentPage">1</span> 页 / 共 <span id="totalPages">0</span> 页</span>
  <button id="nextPage">下一页</button>
  <button id="zoomIn">放大</button>
  <button id="zoomOut">缩小</button>
</div>
<div id="pdfContainer"></div>

步骤2:修改JavaScript代码,添加状态管理与工具栏逻辑

维护PDF实例、当前页码、缩放比例等状态,为按钮绑定对应操作:

// 全局状态变量
let pdfInstance = null;
let currentPageNum = 1;
let scale = 1.5;
const pdfContainer = document.getElementById('pdfContainer');
const currentPageEl = document.getElementById('currentPage');
const totalPagesEl = document.getElementById('totalPages');

// 渲染指定页码的页面
function renderPage(pageNum) {
  // 清空容器
  pdfContainer.innerHTML = '';
  
  pdfInstance.getPage(pageNum).then(page => {
    const canvas = document.createElement('canvas');
    const outputScale = window.devicePixelRatio || 1;
    const viewport = page.getViewport({ scale: scale });

    canvas.width = Math.floor(viewport.width * outputScale);
    canvas.height = Math.floor(viewport.height * outputScale);
    canvas.style.width = Math.floor(viewport.width) + "px";
    canvas.style.height = Math.floor(viewport.height) + "px";

    const transform = outputScale !== 1
      ? [outputScale, 0, 0, outputScale, 0, 0]
      : null;

    const renderContext = {
      canvasContext: canvas.getContext('2d'),
      transform: transform,
      viewport: viewport
    };
    
    page.render(renderContext);
    pdfContainer.appendChild(canvas);
    
    // 更新页码显示
    currentPageEl.textContent = pageNum;
  });
}

// 绑定工具栏事件
function bindToolbarEvents() {
  document.getElementById('prevPage').addEventListener('click', () => {
    if (currentPageNum > 1) {
      currentPageNum--;
      renderPage(currentPageNum);
    }
  });

  document.getElementById('nextPage').addEventListener('click', () => {
    if (currentPageNum < pdfInstance.numPages) {
      currentPageNum++;
      renderPage(currentPageNum);
    }
  });

  document.getElementById('zoomIn').addEventListener('click', () => {
    scale += 0.2;
    renderPage(currentPageNum);
  });

  document.getElementById('zoomOut').addEventListener('click', () => {
    if (scale > 0.5) {
      scale -= 0.2;
      renderPage(currentPageNum);
    }
  });
}

// 加载PDF并初始化
$.ajax({
  // 补充AJAX配置,务必设置responseType为arraybuffer以获取二进制数据
  responseType: 'arraybuffer'
}).done(function(data, textStatus, jqXHR) {
  const pdfData = new Uint8Array(data);
  pdfjsLib.GlobalWorkerOptions.workerSrc = "pdf.worker.min.js";

  pdfjsLib.getDocument({ data: pdfData }).promise.then(function(pdf) {
    pdfInstance = pdf;
    totalPagesEl.textContent = pdf.numPages;
    // 渲染第一页
    renderPage(currentPageNum);
    // 绑定工具栏事件
    bindToolbarEvents();
  });
});

注意事项

  • 必须将AJAX请求的responseType设置为arraybuffer,否则无法正确解析PDF二进制数据
  • 可根据需求扩展工具栏功能:比如添加打印按钮(调用window.print())、下载按钮(通过pdfInstance.getData()获取原始数据生成下载链接)、旋转按钮(修改page.getViewport的rotation参数)

进阶方案:复用PDF.js Viewer的UI组件

如果项目允许引入额外资源,可直接复用官方Viewer的工具栏组件:

  1. 从PDF.js发布包中引入viewer.css、viewer.js(注意依赖顺序)
  2. 复制viewer.html中的核心DOM结构到JSP页面
  3. 通过PDFViewerApplication API加载PDF数据,无需自行渲染Canvas

这种方式能快速获得完整工具栏功能,避免重复开发,但需要引入官方的Viewer资源文件。


内容的提问来源于stack exchange,提问作者Akshay Sumbe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:48:23