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

Angular17实现PDF选定区域矩形绘制及OCR坐标获取的问题

问题解决方案

问题1:Canvas遮挡PDF查看器控件

你的canvas设置了z-index:1,直接覆盖在PDF查看器上方,导致所有点击事件都被canvas拦截,控件自然无法使用。解决办法:

  • 给canvas添加pointer-events: none,让它默认不拦截鼠标事件
  • 仅在绘制阶段临时开启canvas的pointer-events: auto,绘制完成后再关闭

问题2:绘制矩形与选定区域偏差大

偏差核心原因是canvas的显示尺寸和内部绘图缓冲区尺寸不匹配,加上PDF的缩放、分页影响,坐标没有正确转换。解决步骤:

  1. 同步canvas的width/height属性(内部绘图尺寸)与CSS宽高(显示尺寸)
  2. 获取PDF页面的缩放比例,将鼠标的容器相对坐标转换为PDF页面的实际坐标
  3. 结合当前页码修正Y轴坐标,抵消分页带来的偏移

修改后的代码

HTML部分

<div style="position: relative;width: 50%;height: 90vh;" class="col-6" #pdfContainer>                                     
   <ngx-extended-pdf-viewer 
   [base64Src]="base64string.split(',')[1]"
   height="90vh" 
   [zoom]="'page-actual'"
   [useBrowserLocale]="true" 
   [textLayer]="true"
   [showHandToolButton]="true"
   (pageChange)="onPageChange($event)">
   </ngx-extended-pdf-viewer>     
   <canvas #drawCanvas style="position: absolute; top: 0; left: 0; z-index: 1; width: 100%; height: 100%;border: red 2px solid; pointer-events: none;" (mousedown)="onMouseDown($event)" (mouseup)="onMouseUp($event)"></canvas>
</div>

TypeScript部分

import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-pdf-annotator',
  templateUrl: './pdf-annotator.component.html',
  styleUrls: ['./pdf-annotator.component.css']
})
export class PdfAnnotatorComponent {
  base64string: string = '';
  fileDroped: boolean = false;
  startX: number = 0;
  startY: number = 0;
  endX: number = 0;
  endY: number = 0;
  isDrawing: boolean = false;
  currentPage: number = 1;
  @ViewChild('drawCanvas') drawCanvas!: ElementRef<HTMLCanvasElement>;
  @ViewChild('pdfContainer') pdfContainer!: ElementRef<HTMLElement>;

  onPageChange(page: number) {
    this.currentPage = page;
    // 切换页面时清空画布
    const ctx = this.drawCanvas.nativeElement.getContext('2d');
    if (ctx) {
      ctx.clearRect(0, 0, this.drawCanvas.nativeElement.width, this.drawCanvas.nativeElement.height);
    }
  }

  ngAfterViewInit() {
    // 同步canvas内部尺寸和显示尺寸
    const canvas = this.drawCanvas.nativeElement;
    const container = this.pdfContainer.nativeElement;
    canvas.width = container.clientWidth;
    canvas.height = container.clientHeight;
    // 监听窗口 resize,同步canvas尺寸
    window.addEventListener('resize', () => {
      canvas.width = container.clientWidth;
      canvas.height = container.clientHeight;
    });
  }

  onMouseDown(event: MouseEvent) {
    if (!this.fileDroped) return;
    const canvas = this.drawCanvas.nativeElement;
    const container = this.pdfContainer.nativeElement;
    
    // 临时开启canvas鼠标事件监听
    canvas.style.pointerEvents = 'auto';
    
    const rect = container.getBoundingClientRect();
    // 获取相对于容器的坐标
    this.startX = event.clientX - rect.left;
    this.startY = event.clientY - rect.top;
    this.isDrawing = true;
  }

  onMouseUp(event: MouseEvent) {
    if (!this.fileDroped || !this.isDrawing) return;
    const canvas = this.drawCanvas.nativeElement;
    const container = this.pdfContainer.nativeElement;
    const rect = container.getBoundingClientRect();
    
    this.endX = event.clientX - rect.left;
    this.endY = event.clientY - rect.top;
    
    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.strokeStyle = 'blue';
      ctx.lineWidth = 2;
      // 修正坐标,确保宽高为正
      const x = Math.min(this.startX, this.endX);
      const y = Math.min(this.startY, this.endY);
      const width = Math.abs(this.endX - this.startX);
      const height = Math.abs(this.endY - this.startY);
      ctx.strokeRect(x, y, width, height);
      
      // 转换为PDF页面的相对坐标(默认A4尺寸:宽595px,高842px,可根据实际PDF调整)
      const pdfPageWidth = 595;
      const pdfPageHeight = 842;
      const scale = container.clientWidth / pdfPageWidth;
      
      const pdfX = x / scale;
      const pdfY = (y - (this.currentPage - 1) * pdfPageHeight * scale) / scale;
      const pdfWidth = width / scale;
      const pdfHeight = height / scale;
      
      console.log(`PDF页面坐标:X=${pdfX.toFixed(2)}, Y=${pdfY.toFixed(2)}, 宽=${pdfWidth.toFixed(2)}, 高=${pdfHeight.toFixed(2)}`);
    }
    
    // 关闭canvas鼠标事件监听,避免遮挡控件
    canvas.style.pointerEvents = 'none';
    this.isDrawing = false;
  }
}

ng2-pdf-viewer无法显示的排查点

如果file和base64两种方式都失效,检查以下内容:

  • 确认依赖安装完整:npm install ng2-pdf-viewer pdfjs-dist
  • 检查base64格式:如果包含data:application/pdf;base64,前缀,直接绑定[src]="base64string"即可,无需split
  • 查看浏览器控制台报错:排查是否存在CORS限制、PDF文件损坏或版本兼容问题

内容的提问来源于stack exchange,提问作者john younan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:24:52